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