1 /*      XScrabble
2         moves.c
3         move validation and scoring routines
4         By csuos@warwick.ac.uk
5 */
6 
7 #include "scrab.h"
8 #include "globals.h"
9 
convupper(char * str)10 void convupper(char *str)
11 {
12 	int conv = 0;
13 
14 	while (str[conv] != '\0')
15 	{
16 		str[conv] = toupper((int)str[conv]);
17 		conv++;
18 	}
19 }
20 
emptyboard(char b[BOARDSIZE][BOARDSIZE])21 unsigned int emptyboard(char b[BOARDSIZE][BOARDSIZE])
22 {
23 	int x,y;
24 	int empty = 1;
25 	for (x = 0; x < BOARDSIZE; x++)
26 		for (y = 0; y < BOARDSIZE; y++)
27 			{
28 				if (b[x][y] != ' ')
29 			 		empty = 0;
30 			 }
31 	return empty;
32 }
33 
validate(char newboard[BOARDSIZE][BOARDSIZE],int testing,int * goscore)34 int validate(char newboard[BOARDSIZE][BOARDSIZE],int testing, int *goscore)
35 {
36 	int checkx,checky;
37 	int sx,sy,ex,ey;
38 	int finish = 0; /* set finished flag to false */
39 	int invalid = 0; /* set invalid flag to false */
40 	int nothoriz = 1; /* set horizontal check to true */
41 	int notvert = 1; /* set vertical check to true */
42 	int oldpiece = 0; /* set old piece check to false */
43 	int csx,csy,cex,cey,empty;
44 
45 	empty = emptyboard(board);
46 
47 	/* find first new letter */
48 	checkx = checky = 0;
49 	while (!((board[checkx][checky] == ' ') && (newboard[checkx][checky] != ' '))
50 		&& (!finish))
51 	{
52 		checkx++;
53 		if (checkx == BOARDSIZE)
54 			{ checkx = 0;
55 			  checky++; }
56 		if (checky == BOARDSIZE)
57 			finish = 1; /* set finished flag to true */
58 	}
59 	if (finish) return HORLICKS;
60 	/* return invalid if new pieces are not added */
61 	else
62 		{ sx=checkx; sy=checky; }
63 
64 	/* check for a horizontal word */
65 	if ((checkx+1 < BOARDSIZE) && (newboard[checkx+1][checky] != ' '))
66 	{
67 		/* find end of horizontal , including old pieces*/
68 		while ((checkx+1 < BOARDSIZE) &&
69 		 (newboard[checkx+1][checky] != ' '))
70 		 {
71 			if (board[checkx+1][checky] == ' ')
72 				{ nothoriz = 0; }
73 			checkx++;
74 		 }
75 		 if (!nothoriz)
76 		 {
77 			 ex = checkx;
78 			 ey = checky;
79 
80 		/* check for no extra pieces */
81 		checkx++;
82 		if (checkx == BOARDSIZE)
83 			{ checkx = 0 ; checky++; }
84 		while ((checky < BOARDSIZE) && (!invalid))
85 			{
86 				if ((board[checkx][checky] == ' ') &&
87 				    (newboard[checkx][checky] != ' '))
88 				   invalid = 1; /* go is invalid */
89 				else {
90 					checkx++;
91 					if (checkx == BOARDSIZE)
92 						{ checkx = 0 ; checky++; }
93 				}
94 			}
95 		if (invalid)
96 			return HORLICKS;
97 		else
98 			{
99 			if (!empty)
100 			/* check to see if there is an old piece around word */
101 			{
102 			csx = sx;
103 			cex = ex;
104 			if (sy > 0) csy = sy-1;
105 			else csy = sy;
106 			if (ey < BOARDSIZE-1) cey = ey+1;
107 			else cey = ey;
108 			for (checkx = csx; checkx <= cex; checkx++)
109 				for (checky = csy; checky <= cey; checky++)
110 					if (board[checkx][checky] != ' ')
111 						oldpiece = 1;
112 			if ((sx > 0)&&(board[sx-1][sy]!=' '))
113 				oldpiece = 1;
114 			if ((ex < BOARDSIZE-1)&&(board[ex+1][ey]!=' '))
115 				oldpiece = 1;
116 			if (oldpiece)
117 			return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
118 			else
119 				return HORLICKS;
120 			}
121 			else
122 				return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
123 			}
124 		}
125 	}
126 	checkx = sx;
127 	checky = sy;
128 		/* check for a vertical word */
129 		if ((checky+1 < BOARDSIZE) && (newboard[checkx][checky+1] != ' ')
130 			&& nothoriz)
131 		{
132 
133 			/* check for no extra pieces before vertical word */
134 			checky++;
135 			checkx = 0;
136 			while ((checkx < sx) && (!invalid))
137 			{
138 				if ((board[checkx][checky] == ' ') &&
139 				    (newboard[checkx][checky] != ' '))
140 				   invalid = 1; /* extra piece, go is invalid */
141 				else {
142 					checky++;
143 					if (checky == BOARDSIZE)
144 						{ checky = sy+1; checkx++; }
145 					}
146 			}
147 			if (invalid)
148 				return HORLICKS;
149 			/* reset check variables */
150 			checkx=sx; checky=sy;
151 
152 			/* now find end of vertical word */
153 			while ((checky+1 < BOARDSIZE) &&
154 		 		(newboard[checkx][checky+1] != ' '))
155 		 	{
156 				if (board[checkx][checky+1] == ' ')
157 					{ notvert = 0; }
158 				checky++;
159 		 	}
160 
161 		 	if (!notvert)
162 		 	{
163 		 	ex = checkx;
164 			ey = checky;
165 
166 			/* check for no extra pieces after vertical word */
167 			checky++;
168 			if (checky == BOARDSIZE)
169 				{ checky = sy; checkx ++; }
170 			while ((checkx < BOARDSIZE) && (!invalid))
171 				{
172 					if ((board[checkx][checky] == ' ') &&
173 					    (newboard[checkx][checky] != ' '))
174 					   invalid = 1; /* go is invalid */
175 					else {
176 						checky++;
177 						if (checky == BOARDSIZE)
178 							{ checky = sy ; checkx++; }
179 					}
180 				}
181 			if (invalid)
182 				return HORLICKS;
183 			else
184 			{
185 			if (!empty)
186 			{
187 				csy = sy;
188 				cey = ey;
189 				if (sx > 0) csx = sx-1;
190 				else csx = sx;
191 				if (ex < BOARDSIZE-1) cex = ex+1;
192 				else cex = ex;
193 				for (checkx = csx; checkx <= cex; checkx++)
194 					for (checky = csy; checky <= cey; checky++)
195 						if (board[checkx][checky] != ' ')
196 							oldpiece = 1;
197 				if ((sy > 0)&&(board[sx][sy-1]!=' '))
198 					oldpiece = 1;
199 				if ((ey < BOARDSIZE-1)&&(board[ex][ey+1]!=' '))
200 					oldpiece = 1;
201 				if (oldpiece)
202 					return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
203 				else
204 					return HORLICKS;
205 			}
206 			else
207 				return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
208 			}
209 			}
210 		}
211 			if (notvert && nothoriz)
212 			{	/* one letter */
213 				ex = sx; ey = sy;
214 				/* check for no extra letters */
215 				checkx++;
216 				if (checkx == BOARDSIZE)
217 					{ checkx = 0; checky++; }
218 				while ((checky < BOARDSIZE) && (!invalid))
219 				{
220 					if ((board[checkx][checky] == ' ') &&
221 					    (newboard[checkx][checky] != ' '))
222 					   invalid = 1; /* go is invalid */
223 					else {
224 						checkx++;
225 						if (checkx == BOARDSIZE)
226 							{ checkx = 0; checky++; }
227 					}
228 				}
229 			if (invalid)
230 				return HORLICKS;
231 			else
232 			{
233 			/* check to see if there is at least one surrounding piece */
234 			if (((sy > 0)&&(board[sx][sy-1]!=' '))||
235 			    ((sy < BOARDSIZE-1)&&(board[sx][sy+1]!=' '))||
236 			    ((sx > 0)&&(board[sx-1][sy]!=' '))||
237 			    ((sx < BOARDSIZE-1)&&(board[sx+1][sy]!=' ')))
238 				return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
239 			else
240 				return HORLICKS;
241 			}
242 			}
243 	return HORLICKS; /* just in case */
244 }
245 
246 
checkwords(char nb[BOARDSIZE][BOARDSIZE],int sx,int sy,int ex,int ey,int testing,int * goscore)247 int checkwords(char nb[BOARDSIZE][BOARDSIZE],int sx,int sy,int ex,int ey,int testing,int *goscore)
248 {
249 	int checkx,checky,lefttile,righttile,toptile,bottile;
250 	int indict,fillword;
251 	char checkword[16];
252 	int correct = 1;
253 	int loneletter = 0;
254 	char wordsmade[BESTGOWORDSLEN] = "";
255 	int wordpos = 0;
256 
257 	/* initialise go score */
258 	*goscore = 0;
259 
260 	/* if first go check to see if it passes through centre */
261 	if (emptyboard(board))
262 	{
263 		/* if horizontal word */
264 		if (ey-sy == 0)
265 		{
266 			if (!((sx <= 7) && (ex >= 7) && (sy == 7)))
267 				return NOTCENTRE;
268 		}
269 		else
270 		/* if vertical word */
271 		{
272 			if (!((sy <= 7) && (ey >= 7) && (sx == 7)))
273 				return NOTCENTRE;
274 		}
275 	}
276 
277 	/* check for horizontal word */
278 	if (ey-sy == 0)
279 	{
280 		/* ####check left and right for complete word#### */
281 
282 		/* check left */
283 		checkx = sx;
284 		while (((checkx-1) >= 0) && (board[checkx-1][sy] != ' '))
285 		{
286 			checkx--;
287 		}
288 		lefttile = checkx;
289 
290 		/* check right */
291 		checkx = ex;
292 		while (((checkx+1) < BOARDSIZE) && (board[checkx+1][sy] != ' '))
293 		{
294 			checkx++;
295 		}
296 		righttile = checkx;
297 
298 		/* do not check if it is one letter */
299 		if (!((lefttile == sx)&&(righttile == sx)))
300 		{
301 			/* construct word */
302 			for (fillword=lefttile; fillword <= righttile; fillword++)
303 			{
304 				checkword[fillword-lefttile] = nb[fillword][sy];
305 			}
306 			checkword[fillword-lefttile]='\0';
307 
308 			/* and check it */
309 			convupper(checkword);
310 			if (!testing)
311 				indict = wordsearch(checkword);
312 			else
313 				indict = 1;
314 			correct = correct&&indict;
315 			if (indict)
316 				{
317 				*goscore += scoreword(lefttile,sy,righttile,sy,nb);
318 				if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
319 				{
320 					if (wordpos != 0)
321 						strcat(wordsmade,",");
322 					wordpos+=strlen(checkword)+1;
323 					strcat(wordsmade,checkword);
324 				}
325 				}
326 		}
327 		else
328 			{ loneletter = 1; }
329 
330 		/* #####check up and down along word#### */
331 		checkx = sx;
332 
333 		/* move along letters */
334 		while ((checkx <= ex)&&correct)
335 		{
336 		/* only check and score new words */
337 		if (board[checkx][sy] == ' ')
338 			{
339 			/* check up */
340 			checky = sy;
341 			while (((checky-1) >= 0) && (board[checkx][checky-1] != ' '))
342 			{
343 				checky--;
344 			}
345 			toptile = checky;
346 
347 			/* check down */
348 			checky = sy;
349 			while (((checky+1) < BOARDSIZE) && (board[checkx][checky+1] != ' '))
350 			{
351 				checky++;
352 			}
353 			bottile = checky;
354 
355 
356 			/* do not check if it is one letter */
357 			if (!((toptile == sy)&&(bottile == sy)))
358 			{
359 				/* construct word */
360 				for (fillword=toptile; fillword <= bottile; fillword++)
361 				{
362 					checkword[fillword-toptile] = nb[checkx][fillword];
363 				}
364 				checkword[fillword-toptile]='\0';
365 
366 				/* and check it */
367 				convupper(checkword);
368 				if (!testing)
369 					{
370 					indict = wordsearch(checkword);
371 					}
372 				else
373 					indict = 1;
374 				correct = correct&&indict;
375 				if (indict)
376 					{
377 					*goscore += scoreword(checkx,toptile,checkx,bottile,nb);
378 					if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
379 					{
380 						if (wordpos != 0)
381 							strcat(wordsmade,",");
382 						wordpos+=strlen(checkword)+1;
383 						strcat(wordsmade,checkword);
384 					}
385 					}
386 			}
387 			else
388 			{
389 				if (loneletter)
390 					correct = 0;
391 				/* if this is an "island" then it is not a word */
392 			}
393 			}
394 			checkx++;
395 		}
396 		if (correct)
397 		{
398 			if (!testing) alterbestgo(*goscore,wordsmade);
399 			return VALID;
400 		}
401 		else
402 			return INVALID;
403 	}
404 	else
405 	/*### check up and down for complete word ###*/
406 	{
407 		/* check up */
408 		checky = sy;
409 		while (((checky-1) >= 0) && (board[sx][checky-1] != ' '))
410 		{
411 			checky--;
412 		}
413 		toptile = checky;
414 
415 		/* check down */
416 		checky = ey;
417 		while (((checky+1) < BOARDSIZE) && (board[sx][checky+1] != ' '))
418 		{
419 			checky++;
420 		}
421 		bottile = checky;
422 
423 		/* no need to check for lone letter, already checked */
424 		/* construct word */
425 		for (fillword=toptile; fillword <= bottile; fillword++)
426 		{
427 			checkword[fillword-toptile] = nb[sx][fillword];
428 		}
429 		checkword[fillword-toptile]='\0';
430 
431 		/* and check it */
432 		convupper(checkword);
433 		if (!testing)
434 			indict = wordsearch(checkword);
435 		else
436 			indict = 1;
437 		correct = correct && indict;
438 		if (indict)
439 		{
440 		*goscore += scoreword(sx,toptile,sx,bottile,nb);
441 		if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
442 			{
443 				if (wordpos != 0)
444 					strcat(wordsmade,",");
445 				wordpos+=strlen(checkword)+1;
446 				strcat(wordsmade,checkword);
447 			}
448 		}
449 
450 		/* ####check left and right along word#### */
451 		checky = sy;
452 
453 		/* move along letters */
454 		while ((checky <= ey) && correct)
455 		{
456 		/* only check and score new words */
457 		if (board[sx][checky] == ' ')
458 			{
459 			/* check left */
460 			checkx = sx;
461 			while (((checkx-1) >= 0) && (board[checkx-1][checky] != ' '))
462 			{
463 				checkx--;
464 			}
465 			lefttile = checkx;
466 
467 			/* check right */
468 			checkx = sx;
469 			while (((checkx+1) < BOARDSIZE) && (board[checkx+1][checky] != ' '))
470 			{
471 				checkx++;
472 			}
473 			righttile = checkx;
474 
475 			/* do not check if it is one letter */
476 			if (!((lefttile == sx)&&(righttile == sx)))
477 			{
478 				/* construct word */
479 				for (fillword=lefttile; fillword <= righttile; fillword++)
480 				{
481 					checkword[fillword-lefttile] = nb[fillword][checky];
482 				}
483 				checkword[fillword-lefttile]='\0';
484 
485 				/* and check it */
486 				convupper(checkword);
487 				if (!testing)
488 					indict = wordsearch(checkword);
489 				else
490 					indict = 1;
491 				correct = correct&&indict;
492 				if (indict)
493 				{
494 				*goscore += scoreword(lefttile,checky,righttile,checky,nb);
495 				if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
496 					{
497 						if (wordpos != 0)
498 							strcat(wordsmade,",");
499 						wordpos+=strlen(checkword)+1;
500 						strcat(wordsmade,checkword);
501 					}
502 				}
503 			}
504 			}
505 			checky++;
506 		}
507 		if (correct)
508 		{
509 			if (!testing) alterbestgo(*goscore,wordsmade);
510 			return VALID;
511 		}
512 		else
513 			return INVALID;
514 
515 	}
516 
517 	return 0; /* just in case */
518 }
519 
520 
scoreword(int sx,int sy,int ex,int ey,char nb[BOARDSIZE][BOARDSIZE])521 int scoreword(int sx,int sy,int ex,int ey, char nb[BOARDSIZE][BOARDSIZE])
522 {
523 	int wordscore = 0;
524 	int multiple = 1;
525 	int scorex,scorey;
526 	int numlett = 0,goscore = 0;
527 
528 	/* score horizontal */
529 	if ((sy - ey) == 0)
530 	{
531 		for (scorex = sx; scorex <= ex; scorex++)
532 		{
533 
534 
535 			/* score letter & bonus */
536 			if (isupper(nb[scorex][sy]))
537 			{
538 			wordscore = wordscore + letterscore[nb[scorex][sy]];
539 
540 			/* do not score for old pieces */
541 			if (board[scorex][sy] == ' ')
542 			{
543 			switch (sq_col[scorex][sy])
544 			{
545 			case 1 : /* double letter */
546 				{ wordscore += letterscore[nb[scorex][sy]];
547                                   break;}
548 			case 2 : /* tripple letter */
549 				{ wordscore += (2*letterscore[nb[scorex][sy]]);
550                                   break;}
551 			default : {break;}
552 			}
553 			}
554 			}
555 
556 			/* check for word bonus */
557 			if (board[scorex][sy] == ' ')
558 			{
559 			switch (sq_col[scorex][sy])
560 			{
561 			case 3 : /* double word */
562 				{ multiple *= 2 ; break;}
563 			case 4 : /* double word */
564 				{ multiple *= 3 ; break;}
565 			default : {break;}
566 			}
567 			/* and finally check to see if seven letters are used */
568 			numlett++;
569 			}
570 		}
571 		goscore = wordscore*multiple;
572 		if (numlett == 7)
573 			goscore += 50;
574 		return (goscore);
575 	}
576 	else
577 	{
578 		for (scorey = sy; scorey <= ey; scorey++)
579 		{
580 			/* score letter & bonus */
581 			if (isupper(nb[sx][scorey]))
582 			{
583 			wordscore += letterscore[nb[sx][scorey]];
584 
585 			/* do not score for old pieces */
586 			if (board[sx][scorey] == ' ')
587 			{
588 			switch (sq_col[sx][scorey])
589 			{
590 			case 1 : /* double letter */
591 				{ wordscore += letterscore[nb[sx][scorey]];
592                                   break;}
593 			case 2 : /* tripple letter */
594 				{ wordscore += (2*letterscore[nb[sx][scorey]]);
595                                   break;}
596 			default : {break;}
597 			}
598 			}
599 			}
600 
601 			/* check for word bonus */
602 			if (board[sx][scorey] == ' ')
603 			{
604 			switch (sq_col[sx][scorey])
605 			{
606 			case 3 : /* double word */
607 				{ multiple *= 2 ; break;}
608 			case 4 : /* double word */
609 				{ multiple *= 3 ; break;}
610 			default : {break;}
611 			}
612 			/* and finally check to see if seven letters are used */
613 			numlett++;
614 			}
615 		}
616 		goscore = wordscore*multiple;
617 		if (numlett == 7)
618 			goscore += 50;
619 		return (goscore);
620 	}
621 	return 0;
622 }
623 
624 
625 /* debug routines */
626 
addhword(char newboard[BOARDSIZE][BOARDSIZE],int x,int y,char * word,int length)627 void addhword(char newboard[BOARDSIZE][BOARDSIZE],int x,int y,char *word,int length)
628 {
629 	int add;
630 	for (add = 0; add < length; add++)
631 	{
632 		newboard[x][y] = word[add];
633 		x++;
634 	}
635 }
636 
addvword(char newboard[BOARDSIZE][BOARDSIZE],int x,int y,char * word,int length)637 void addvword(char newboard[BOARDSIZE][BOARDSIZE],int x,int y,char *word,int length)
638 {
639 	int add;
640 	for (add = 0; add < length; add++)
641 	{
642 		newboard[x][y] = word[add];
643 		y++;
644 	}
645 }
646 
647 
648 /* end of debug routines */
649 
650