
/* RCS Info: $Revision: 1.2 $ on $Date: 89/03/15 11:16:30 $
 *           $Source: /yew3/faustus/src/scrabble/RCS/move.c,v $
 * Copyright (c) 1989 Wayne A. Christopher, U. C. Berkeley CS Dept
 *      faustus@renoir.berkeley.edu, ucbvax!faustus
 * Permission is granted to modify and re-distribute this code in any manner
 * as long as this notice is preserved.  All standard disclaimers apply.
 *
 */

#include "scrabble.h"

static void dopos(board_t *board, player_t *player, int x, int y,
               bool horiz, move_t *best);
static int wordpoints(board_t *board, int x, int y, bool horiz, int len,
               char *word, char subc, int wx, int wy, bool allbonuses,
               bool *wilds);
static bool validword(board_t *board, int x, int y, int len, char subc,
               bool horiz, bool machine, bool check);
static bool validlocation(board_t *board, int x, int y, bool horiz, int len);

void
bestmove(board_t *board, player_t *player, move_t *best)
{
       int x, y;
       move_t try;

       best->points = -1;

       for (x = 0; x < SIZE; x++)
               for (y = 0; y < SIZE; y++) {
                       dopos(board, player, x, y, true, &try);
                       if (try.points > best->points)
                               *best = try;
                       dopos(board, player, x, y, false, &try);
                       if (try.points > best->points)
                               *best = try;
               }
       
       return;
}

#ifdef notdef

void
printmove(int which, move_t *move, FILE *fp)
{
       fprintf(fp, "Player %d: \"%s\", %s at (%d, %d) for %d points.\n",
                       which, move->word, move->horiz ? "horiz" : "vert",
                       move->x, move->y, move->points);
       
       return;
}

#endif

static void
dopos(board_t *board, player_t *player, int x, int y, bool horiz, move_t *best)
{
       char opt[SIZE];
       char req[SIZE];
       int numopt, numreq;
       word_t *words, *set, *word;
       int i, j, len;
       char c;
       move_t try;

       best->points = -1;

       try.x = x;
       try.y = y;
       try.horiz = horiz;

       for (len = 1; horiz ? (x + len <= SIZE) : (y + len <= SIZE); len++) {
               try.length = len;

               /* First make sure this is a place we can put a word. */
               if (!validlocation(board, x, y, horiz, len))
                       continue;

#ifdef notdef
               if (debug)
                       fprintf(stderr, "\t(%d, %d), %s, len %d ---\n",
                                       x, y, horiz ? "horiz" : "vert", len);
#endif

               /* Make the letter set. */
               for (i = 0, numopt = 0; i < player->numworking; i++)
                       opt[i] = player->working[i];
               numopt = player->numworking;

               for (j = 0, numreq = 0; j < len; j++) {
                       c = boardletter(board, x, y, horiz, j);
                       if (something(c))
                               req[numreq++] = c;
               }
               if (((horiz ? x : y) + len < SIZE) && something(boardletter
                               (board, x, y, horiz, len)))
                       continue;
               if (((horiz ? x : y) > 0) && something(boardletter
                               (board, x, y, horiz, - 1)))
                       continue;

               if (numreq + numopt < len)
                       break;

#ifdef notdef
               if (debug) {
                       fprintf(stderr, "\tReq:");
                       for (i = 0; i < numreq; i++)
                               fprintf(stderr, " %c", req[i]);
                       fprintf(stderr, "\n\tOpt:");
                       for (i = 0; i < numopt; i++)
                               fprintf(stderr, " %c", opt[i]);
                       fprintf(stderr, "\n");
               }
#endif

               words = getpossibles(opt, numopt, req, numreq, len);

               for (set = words; set; set = set->next_set)
                       for (word = set; word; word = word->next) {
                               try.word = word->word;
                               for (i = 0; i < SIZE; i++)
                                       try.wild[i] = false;
                               trymove(&try, board, player, false);
                               if (try.points > best->points)
                                       *best = try;
                       }
       }

       return;
}

static bool
validlocation(board_t *board, int x, int y, bool horiz, int len)
{
       int i;

       if (board->virgin) {
               if (((y == SIZE / 2) && (x <= SIZE / 2) &&
                                       (x + len - 1 >= SIZE / 2)) ||
                   ((x == SIZE / 2) && (y <= SIZE / 2) &&
                                       (y + len - 1 >= SIZE / 2)))
                       return (true);
               else
                       return (false);
       }

       for (i = 0; i < len; i++)
               if (horiz) {
                       if (something(boardletter(board, x, y, horiz, i)) ||
                                       ((y > 0) && something(boardletter
                                       (board, x, y - 1, horiz, i))) ||
                                       ((y < SIZE - 1) && something(boardletter
                                       (board, x, y + 1, horiz, i))))
                               return (true);
               } else {
                       if (something(boardletter(board, x, y, horiz, i)) ||
                                       ((x > 0) && something(boardletter
                                       (board, x - 1, y, horiz, i))) ||
                                       ((x < SIZE - 1) && something(boardletter
                                       (board, x + 1, y, horiz, i))))
                               return (true);
               }
       
       return (false);
}

/* This routine returns the value of a move, or -1 if the move would
 * be invalid.
 */

void
trymove(move_t *move, board_t *board, player_t *player, bool check)
{
       bool used[WORK_SIZE];
       int numused = 0;
       int i, j, x, y;
       int len;
       char c;
       char buf[BSIZE];

/*printf("try %s at %d, %d, %d\n", move->word, move->x, move->y, move->horiz);*
/

       if (check) {
               sprintf(buf, "Is \"%s\" a word?", move->word);
               if (!user_confirm(buf)) {
                       remword(move->word);
                       move->points = -1;
                       return;
               }
       }

       for (i = 0; i < WORK_SIZE; i++) {
               used[i] = false;
               if (iswild(player->working[i]))
                       player->working[i] = WILD;
       }

       /* First do the validity checks. */
       for (i = 0; i < move->length; i++) {
               c = boardletter(board, move->x, move->y, move->horiz, i);
               if (iswild(c))
                       c = maketame(c);
               if (something(c)) {
                       if (move->word[i] != c) {
                               move->points = -1;
                               return;
                       }
               } else {
                       for (j = 0; j < player->numworking; j++)
                               if ((move->word[i] == player->working[j]) &&
                                               !used[j]) {
                                       used[j] = true;
                                       numused++;
                                       break;
                               }
                       if (j == player->numworking) {
                               for (j = 0; j < player->numworking; j++)
                                       if ((player->working[j] == WILD) &&
                                                       !used[j]) {
                                               move->wild[i] = true;
                                               used[j] = true;
                                               numused++;
                                               break;
                                       }
                               if (j == player->numworking) {
                                       move->points = -1;
                                       return;
                               }
                       }
               }
       }

#ifdef notdef
       if (debug)
               fprintf(stderr, "\t(%d, %d) %s: %s", move->x, move->y,
                               move->horiz ? "horiz" : "vert", move->word);
#endif

       if (!numused) {
               move->points = -1;
               return;
       }

       /* Add up the value of this word. */
       move->points = wordpoints(board, move->x, move->y, move->horiz,
                       move->length, move->word, '\0', 0, 0, true,
                       move->wild);
       
       if (numused == WORK_SIZE)
               move->points += ALL_BONUS;
       
       if (move->horiz)
               for (i = 0; i < move->length; i++) {
                       x = move->x + i;
                       if (something(board->letters[x][move->y]))
                               continue;
                       for (y = move->y; (y > 0) && something(board->
                                       letters[x][y - 1]); y--)
                               ;
                       for (len = 1, j = y; (j < SIZE - 1) &&
                                       (something(board->letters[x][j + 1]) ||
                                       (j + 1 == move->y)); len++, j++)
                               ;
                       if (len == 1)
                               continue;
                       if (validword(board, x, y, len, move->word[i], false,
                                       player->machine, check))
                               move->points += wordpoints(board, x, y, false,
                                               len, (char *) NULL,
                                               move->word[i], x, y,
                                               false, (bool *) NULL);
                       else {
                               move->points = -1;
#ifdef notdef
                               if (debug)
                                       fprintf(stderr, "=-1\n");
#endif
                               return;
                       }
               }
       else
               for (i = 0; i < move->length; i++) {
                       y = move->y + i;
                       if (something(board->letters[move->x][y]))
                               continue;
                       for (x = move->x; (x > 0) && something(board->
                                       letters[x - 1][y]); x--)
                               ;
                       for (len = 1, j = x; (j < SIZE - 1) &&
                                       (something(board->letters[j + 1][y]) ||
                                       (j + 1 == move->x)); len++, j++)
                               ;
                       if (len == 1)
                               continue;
                       if (validword(board, x, y, len, move->word[i], true,
                                       player->machine, check))
                               move->points += wordpoints(board, x, y, true,
                                               len, (char *) NULL,
                                               move->word[i], x, y,
                                               false, (bool *) NULL);
                       else {
                               move->points = -1;
#ifdef notdef
                               if (debug)
                                       fprintf(stderr, "=-1\n");
#endif
                               return;
                       }
               }

#ifdef notdef
       if (debug)
               fprintf(stderr, "\n");
#endif
       
       return;
}

static bool
validword(board_t *board, int x, int y, int len, char subc, bool horiz,
               bool machine, bool check)
{
       char buf[BSIZE], qbuf[BSIZE], c;
       int i;

       for (i = 0; i < len; i++) {
               c = boardletter(board, x, y, horiz, i);
               if (something(c))
                       buf[i] = c;
               else
                       buf[i] = subc;
               if (iswild(buf[i]))
                       buf[i] = maketame(buf[i]);
       }
       buf[i] = '\0';

#ifdef notdef
       if (debug)
               fprintf(stderr, " %s", buf);
#endif

       if (check) {
               sprintf(qbuf, "Is \"%s\" a word?", buf);
               if (user_confirm(qbuf)) {
                       return (true);
               } else {
                       remword(buf);
                       return (false);
               }
       } else if (isaword(buf)) {
               return (true);
       } else if (!machine) {
               sprintf(qbuf, "I don't think \"%s\" is a word.  Do you?", buf);
               if (user_confirm(qbuf)) {
                       addword(buf);
                       return (true);
               } else
                       return (false);
       } else {
               return (false);
       }
}

static int
wordpoints(board_t *board, int x, int y, bool horiz, int len, char *word,
               char subc, int wx, int wy, bool allbonuses, bool *wilds)
{
       int value = 0;
       int mult = 1;
       int i;
       bonus_t b;
       char c;

       if ((horiz ? x : y) + len > SIZE)
               return (-1);

       for (i = 0; i < len; i++) {
               if (allbonuses || (horiz && (x + i == wx)) ||
                               (!horiz && (y + i == wy)))
                       b = boardbonus(board, x, y, horiz, i);
               else
                       b = NONE;

               c = boardletter(board, x, y, horiz, i);

               if (!something(c)) {
                       if (word)
                               c = word[i];
                       else
                               c = subc;
                       assert(c);
               } else
                       b = NONE;

               if (wilds && wilds[i])
                       c = makewild(c);

               switch (b) {
                   case NONE:
                       value += letterpoints(c);
                       break;

                   case DOUBLE_LETTER:
                       value += letterpoints(c) * 2;
                       break;

                   case TRIPLE_LETTER:
                       value += letterpoints(c) * 3;
                       break;

                   case DOUBLE_WORD:
                       value += letterpoints(c);
                       mult *= 2;
                       break;

                   case TRIPLE_WORD:
                       value += letterpoints(c);
                       mult *= 3;
                       break;
               }
       }

       value *= mult;

#ifdef notdef
       if (debug)
               fprintf(stderr, "=%d", value);
#endif

       return (value);
}

