/* turns.c
 *
 * Copyright (C) 1999 Tom Gilbert
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include "Gnerudite.h"

extern int debug;
extern grid_button button[15][15];
extern rack_button tile_button[13];
extern int first_go;
extern GtkWidget *window;
extern GtkWidget *score_label2;
extern int scores[27];
extern int players_scores[8];

int
go_ended (void)
{
  switch (go_is_valid ())
    {
    case TURN_INVALID_NOT_IN_SAME_ROW:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n"
	   "You seem to have a horizontal word, with at "
	   "least one tile in a different row.");
	break;
      }
    case TURN_INVALID_NOT_IN_SAME_COL:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n"
	   "You seem to have a vertical word, with at "
	   "least one tile in a different column.");
	break;
      }
    case TURN_INVALID_NO_WORD_MATCH:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n" "The word is not in my dictionary.");
	break;
      }
    case TURN_INVALID_ONLY_ONE_TILE:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n"
	   "A one letter word really doesn't cut the mustard!.");
	break;
      }
    case TURN_INVALID_GO_CANCELLED:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n"
	   "You placed no tiles, but chose not to skip your go.");
	break;
      }
    case TURN_INVALID_GAP_IN_WORD:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n" "There appears to be a gap in it!");
	break;
      }
    case TURN_INVALID_DIAGONAL_WORD:
      {
	gnome_ok_dialog
	  ("Your go was not valid.\n\n" "Did you try a diagonal word?");
	break;
      }
    case TURN_INVALID_NOT_ADJACENT:
      {
	if (first_go)
	  {
	    gnome_ok_dialog
	      ("Your go was not valid.\n\n"
	       "On the first go, at least one tile "
	       "should be placed on the center spot");
	  }
	else
	  {
	    gnome_ok_dialog
	      ("Your go was not valid.\n\n"
	       "You should place tiles next to an " "existing tile.");
	  }
	break;
      }
    case NO_ERROR:
      {
	TOMTRACE (("\nYour go was valid\n"));
	start_next_go ();
	return TRUE;
	break;
      }
    case TURN_SKIPPED:
      {
	TOMTRACE (("\nYou skipped your go\n"));
	gnome_app_flash (GNOME_APP (window), "Go was skipped");
	start_next_go ();
	return TRUE;
	break;
      }
    default:
      {
	gnome_ok_dialog ("Your go was not valid. I don't know why!");
	break;
      }
    }
  reset_last_go ();
  clear_grid_button_validations ();

  return TRUE;
}


/* TODO */
/* This function is a behemoth. It is _huge_. It really needs breaking up
 * into smaller functions. I have just kind of thrown it together to get
 * something working */

int
go_is_valid (void)
{

  int i = 0, j = 0, k = 0;
  int tiles_placed_this_go = 0;
  int temp_row = -1;
  int temp_col = -1;
  int first_col = -1;
  int first_row = -1;
  int last_col = -1;
  int last_row = -1;
  int my_row = -1;
  int my_col = -1;
  int ONLY_ONE_TILE = FALSE;
  short double_word = 0;
  short triple_word = 0;
  int turn_score = 0;
  int word_score = 0;
  gchar word[16];
  gchar *words[16];
  int number_of_words = 0;

  direction word_direction = WORD_UNKNOWN;
  grid_button *placed_tiles[15] =
    { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL
  };

  TOMTRACE (("Entering go_is_valid\n"));

  /* Here we iterate through the grid, checking for button.placed_this_go
   * and use this to count how many tiles have been placed this go.
   * We will then judge the orientation of the word, and check validity. */
  for (i = 0; i < 15; i++)
    for (j = 0; j < 15; j++)
      {
	if (button[j][i].placed_this_go)
	  {
	    /* This tile has just been placed */
	    placed_tiles[tiles_placed_this_go] = &button[j][i];
	    tiles_placed_this_go++;
	  }
      }
  TOMTRACE (("\nNumber of tiles placed this turn = %d\n",
	     tiles_placed_this_go));
  if (tiles_placed_this_go < 1)
    {
      /* No tiles placed this go, so act as if the player had selected
       * skip go */
      if (cb_skip_go_pressed ())
	return TURN_SKIPPED;
      else
	return TURN_INVALID_GO_CANCELLED;
    }
  else if (tiles_placed_this_go == 1)
    {
      /* Special case for only one tile placed */
      TOMTRACE (("Only one tile placed\n"));
      ONLY_ONE_TILE = TRUE;
    }
  else
    {
      /* Check same row or column */
      if ((temp_row = count_placed_tiles_in_row (placed_tiles[0]->row)) > 1)
	{
	  word_direction = WORD_RIGHT;
	  if (temp_row < tiles_placed_this_go)
	    return TURN_INVALID_NOT_IN_SAME_COL;
	}
      else if ((temp_col = count_placed_tiles_in_col (placed_tiles[0]->col)) >
	       1)
	{
	  word_direction = WORD_DOWN;
	  if (temp_col < tiles_placed_this_go)
	    return TURN_INVALID_NOT_IN_SAME_ROW;
	}
      else
	return TURN_INVALID_DIAGONAL_WORD;


      /* Now we check whether the placed tiles are adjacent to existing ones */
      if (!are_tiles_adjacent (placed_tiles, tiles_placed_this_go))
	return TURN_INVALID_NOT_ADJACENT;

      /* Check for presence of wildcard character */
      for (i = 0; i < tiles_placed_this_go; i++)
	{
	  if (placed_tiles[i]->letter == '*')
	    {
	      gchar c = ask_user_for_wildcard_char (placed_tiles[i]->row,
						    placed_tiles[i]->col);
	      placed_tiles[i]->is_wildcard = TRUE;
	      grid_button_assign_char (placed_tiles[i], c);
	    }
	}

/* If you stick letters on the end of a word, the
 * pre-existing word is picked up by this bit */

      if (word_direction == WORD_DOWN)
	{
	  word_score = 0;
	  double_word = 0;
	  triple_word = 0;
	  /* This bit looks upwards, to see if these letters are tacked
	   * onto the end of an existing word */
	  TOMTRACE (("Word direction = down\n"));
	  temp_col = placed_tiles[0]->col;
	  my_row = placed_tiles[0]->row;
	  last_row = placed_tiles[tiles_placed_this_go - 1]->row;
	  if (my_row > 0)
	    {
	      while ((button[my_row - 1][temp_col].letter != '\0')
		     && (my_row > 0))
		my_row--;
	    }
	  first_row = my_row;
	  for (i = first_row, j = 0; i < 15; i++, j++)
	    {
	      if (!button[i][temp_col].letter)
		{
		  if (i < last_row + 1)
		    return TURN_INVALID_GAP_IN_WORD;
		  else
		    break;
		}
	      else
		{
		  word[j] = button[i][temp_col].letter;
		  word_score +=
		    calc_score_for_tile (&button[i][temp_col], &double_word,
					 &triple_word);
		  word[j + 1] = '\0';
		}
	    }
	  turn_score +=
	    get_final_word_score (word_score, double_word, triple_word);
	}
      else if (word_direction == WORD_RIGHT)
	{
	  word_score = 0;
	  double_word = 0;
	  triple_word = 0;
	  /* This bit looks left, to see if these letters are tacked
	   * onto the end of an existing word */
	  TOMTRACE (("Word direction = right\n"));
	  temp_row = placed_tiles[0]->row;
	  first_col = placed_tiles[0]->col;
	  last_col = placed_tiles[tiles_placed_this_go - 1]->col;
	  if (first_col > 0)
	    {
	      while ((button[temp_row][first_col - 1].letter != '\0')
		     && (first_col > 0))
		first_col--;
	    }
	  for (i = first_col, j = 0; i < 15; i++, j++)
	    {
	      if (!button[temp_row][i].letter)
		{
		  if (i < last_col + 1)
		    return TURN_INVALID_GAP_IN_WORD;
		  else
		    break;
		}
	      else
		{
		  word[j] = button[temp_row][i].letter;
		  word_score +=
		    calc_score_for_tile (&button[temp_row][i], &double_word,
					 &triple_word);
		  word[j + 1] = '\0';
		}
	    }
	  turn_score +=
	    get_final_word_score (word_score, double_word, triple_word);
	}
      else
	{
	  g_assert_not_reached ();
	}

/* I don't think there's a gap, and we have a suspect _primary_ word */

      TOMTRACE (("I suspect the primary word formed by this move is: %s\n",
		 word));

      words[number_of_words++] = strdup (word);
    }

/* Now, get secondary words, and check them too! */

  if (ONLY_ONE_TILE)
    {
      /* Here's a special condition! */
      if ((first_go) && (ONLY_ONE_TILE))
	{
	  /* Is a one letter word legal??? */
	  TOMTRACE (("You only placed one tile on your first go\n"));
	  return TURN_INVALID_ONLY_ONE_TILE;
	}

      TOMTRACE (("Only one tile, checking surrounding tiles\n"));

      /* Now we check whether the placed tiles are adjacent to existing ones */
      if (!are_tiles_adjacent (placed_tiles, tiles_placed_this_go))
	return TURN_INVALID_NOT_ADJACENT;

      /* Check for presence of wildcard character */
      if (placed_tiles[0]->letter == '*')
	{
	  gchar c = ask_user_for_wildcard_char (placed_tiles[0]->row,
						placed_tiles[0]->col);
	  placed_tiles[0]->is_wildcard = TRUE;
	  grid_button_assign_char (placed_tiles[0], c);
	}


      temp_row = placed_tiles[0]->row;
      temp_col = placed_tiles[0]->col;
      if ((temp_row > 0) && (!button[temp_row - 1][temp_col].letter == '\0'))
	{
	  word_score = 0;
	  double_word = 0;
	  triple_word = 0;
	  /* There is a neighbouring piece here */
	  TOMTRACE (("There is a piece to the left\n"));
	  my_row = temp_row;
	  while ((button[my_row - 1][temp_col].letter != '\0')
		 && (my_row > 0))
	    my_row--;
	  word[0] = '\0';
	  first_row = my_row;
	  last_row = temp_row;
/*	  for (i = first_row, j = 0; i < last_row + 1; i++, j++)  */
	  for (i = first_row, j = 0; i < 15; i++, j++)
	    {
	      if (!button[i][temp_col].letter)
		break;
	      else
		{
		  word[j] = button[i][temp_col].letter;
		  word_score +=
		    calc_score_for_tile (&button[i][temp_col], &double_word,
					 &triple_word);
		  word[j + 1] = '\0';
		}
	    }
	  turn_score +=
	    get_final_word_score (word_score, double_word, triple_word);
	  TOMTRACE (("The primary word formed by this move\n\
(starting to the left of the single placed tile) is: %s\n", word));
	  words[number_of_words++] = strdup (word);
	}
/* We do an else if here, as if there is a piece to the left _and_ right,
 * the first check will get it. Otherwise we'll end up examining it twice. */
      else if ((temp_row < 14)
	       && (!button[temp_row + 1][temp_col].letter == '\0'))
	{
	  word_score = 0;
	  double_word = 0;
	  triple_word = 0;
	  /* There is a neighbouring piece here */
	  TOMTRACE (("There is a piece to the right\n"));
	  my_row = temp_row;
	  while ((button[my_row + 1][temp_col].letter != '\0')
		 && (my_row < 14))
	    my_row++;
	  word[0] = '\0';
	  first_row = temp_row;
	  last_row = my_row;
/*	  for (i = first_row, j = 0; i < last_row + 1; i++, j++)  */
	  for (i = first_row, j = 0; i < 15; i++, j++)
	    {
	      if (!button[i][temp_col].letter)
		break;
	      else
		{
		  word[j] = button[i][temp_col].letter;
		  word_score +=
		    calc_score_for_tile (&button[i][temp_col], &double_word,
					 &triple_word);
		  word[j + 1] = '\0';
		}
	    }
	  turn_score +=
	    get_final_word_score (word_score, double_word, triple_word);
	  TOMTRACE (("The primary word formed by this move\n\
(starting at the the single placed tile and going right) is: %s\n", word));
	  words[number_of_words++] = strdup (word);
	}
      temp_row = placed_tiles[0]->row;
      temp_col = placed_tiles[0]->col;
      if ((temp_col > 0) && (!button[temp_row][temp_col - 1].letter == '\0'))
	{
	  word_score = 0;
	  double_word = 0;
	  triple_word = 0;
	  /* There is a neighbouring piece here */
	  TOMTRACE (("There is a piece above\n"));
	  my_col = temp_col;
	  while ((button[temp_row][my_col - 1].letter != '\0')
		 && (my_col > 0))
	    my_col--;
	  word[0] = '\0';
	  first_col = my_col;
	  last_col = temp_col;
/*	  for (i = first_col, j = 0; i < last_col + 1; i++, j++) */
	  for (i = first_col, j = 0; i < 15; i++, j++)
	    {
	      if (!button[temp_row][i].letter)
		break;
	      else
		{
		  word[j] = button[temp_row][i].letter;
		  word_score +=
		    calc_score_for_tile (&button[temp_row][i], &double_word,
					 &triple_word);
		  word[j + 1] = '\0';
		}
	    }
	  turn_score +=
	    get_final_word_score (word_score, double_word, triple_word);
	  TOMTRACE (("The primary word formed by this move\n\
(Going downwards, ending at the the single placed tile) is: %s\n", word));
	  words[number_of_words++] = strdup (word);
	}
/* We do an else if here, as if there is a piece to the left _and_ right,
 * the first check will get it. Otherwise we'll end up examining it twice. */
      else if ((temp_col < 14)
	       && (!button[temp_row][temp_col + 1].letter == '\0'))
	{
	  word_score = 0;
	  double_word = 0;
	  triple_word = 0;
	  /* There is a neighbouring piece here */
	  TOMTRACE (("There is a piece below\n"));
	  my_col = temp_col;
	  while ((button[temp_row][my_col + 1].letter != '\0')
		 && (my_col < 14))
	    my_col++;
	  word[0] = '\0';
	  first_col = temp_col;
	  last_col = my_col;
/*	  for (i = first_col, j = 0; i < last_col + 1; i++, j++)  */
	  for (i = first_col, j = 0; i < 15; i++, j++)
	    {
	      if (!button[temp_row][i].letter)
		break;
	      else
		{
		  word[j] = button[temp_row][i].letter;
		  word_score +=
		    calc_score_for_tile (&button[temp_row][i], &double_word,
					 &triple_word);
		  word[j + 1] = '\0';
		}
	    }
	  turn_score +=
	    get_final_word_score (word_score, double_word, triple_word);
	  TOMTRACE (("The primary word formed by this move\n\
(Starting at the the single placed tile and going down) is: %s\n", word));
	  words[number_of_words++] = strdup (word);
	}
    }
  else if (word_direction == WORD_DOWN)
    {
      /* Here we scan each placed letter, 
       * looking for new perpendicular words. */
      for (i = 0; i < tiles_placed_this_go; i++)
	{
	  if ((placed_tiles[i]->col > 0)
	      &&
	      (!button[placed_tiles[i]->row][placed_tiles[i]->col - 1].letter
	       == '\0'))
	    {
	      word_score = 0;
	      double_word = 0;
	      triple_word = 0;
	      /* There is a neighbouring piece here */
	      TOMTRACE (("There is a piece above placed tile number %d\n",
			 i + 1));
	      temp_row = placed_tiles[i]->row;
	      temp_col = placed_tiles[i]->col;
	      my_col = temp_col;
	      while ((button[temp_row][my_col - 1].letter != '\0')
		     && (my_col > 0))
		my_col--;
	      word[0] = '\0';
	      first_col = my_col;
	      last_col = temp_col;
/*	      for (k = first_col, j = 0; k < last_col + 1; k++, j++)  */
	      for (k = first_col, j = 0; k < 15; k++, j++)
		{
		  if (!button[temp_row][k].letter)
		    break;
		  else
		    {
		      word[j] = button[temp_row][k].letter;
		      word_score +=
			calc_score_for_tile (&button[temp_row][k],
					     &double_word, &triple_word);
		      word[j + 1] = '\0';
		    }
		}
	      turn_score +=
		get_final_word_score (word_score, double_word, triple_word);
	      TOMTRACE (("A secondary word formed by this move\n\
(Going downwards, ending at the the primary word) is: %s\n", word));
	      words[number_of_words++] = strdup (word);
	    }
	  else if ((placed_tiles[i]->col < 14)
		   &&
		   (!button[placed_tiles[i]->row]
		    [placed_tiles[i]->col + 1].letter == '\0'))
	    {
	      word_score = 0;
	      double_word = 0;
	      triple_word = 0;
	      /* There is a neighbouring piece here */
	      TOMTRACE (("There is a piece below placed tile number %d\n",
			 i + 1));
	      temp_row = placed_tiles[i]->row;
	      temp_col = placed_tiles[i]->col;
	      my_col = temp_col;
	      while ((button[temp_row][my_col + 1].letter != '\0')
		     && (my_col < 14))
		my_col++;
	      word[0] = '\0';
	      first_col = temp_col;
	      last_col = my_col;
/*	      for (k = first_col, j = 0; k < last_col + 1; k++, j++)  */
	      for (k = first_col, j = 0; k < 15; k++, j++)
		{
		  if (!button[temp_row][k].letter)
		    break;
		  else
		    {
		      word[j] = button[temp_row][k].letter;
		      word_score +=
			calc_score_for_tile (&button[temp_row][k],
					     &double_word, &triple_word);
		      word[j + 1] = '\0';
		    }
		}
	      turn_score +=
		get_final_word_score (word_score, double_word, triple_word);
	      TOMTRACE (("A secondary word formed by this move\n\
(Going downwards, starting at the the primary word) is: %s\n", word));
	      words[number_of_words++] = strdup (word);
	    }
	}
    }
  else if (word_direction == WORD_RIGHT)
    {
      /* Here we scan each placed letter looking for new perpendicular words */
      for (i = 0; i < tiles_placed_this_go; i++)
	{
	  temp_row = placed_tiles[i]->row;
	  temp_col = placed_tiles[i]->col;
	  if ((temp_row > 0)
	      && (!button[temp_row - 1][temp_col].letter == '\0'))
	    {
	      word_score = 0;
	      double_word = 0;
	      triple_word = 0;
	      /* There is a neighbouring piece here */
	      TOMTRACE (("There is a piece to the left of placed tile %d\n",
			 i + 1));
	      my_row = temp_row;
	      while ((button[my_row - 1][temp_col].letter != '\0')
		     && (my_row > 0))
		my_row--;
	      word[0] = '\0';
	      first_row = my_row;
	      last_row = temp_row;
/*	      for (k = first_row, j = 0; k < temp_row + 1; k++, j++) */
	      for (k = first_row, j = 0; k < 15; k++, j++)
		{
		  if (!button[k][temp_col].letter)
		    break;
		  else
		    {
		      word[j] = button[k][temp_col].letter;
		      word_score +=
			calc_score_for_tile (&button[k][temp_col],
					     &double_word, &triple_word);
		      word[j + 1] = '\0';
		    }
		}
	      turn_score +=
		get_final_word_score (word_score, double_word, triple_word);
	      TOMTRACE (("A secondary word formed by this move\n"
			 "(starting to the left of the primary "
			 "word and ending on it) is: %s\n", word));
	      words[number_of_words++] = strdup (word);
	    }
/* We do an else if here, as if there is a piece to the left _and_ right,
 * the first check will get it. Otherwise we'll end up examining it twice. */
	  else if ((temp_row < 14)
		   && (!button[temp_row + 1][temp_col].letter == '\0'))
	    {
	      word_score = 0;
	      double_word = 0;
	      triple_word = 0;
	      /* There is a neighbouring piece here */
	      TOMTRACE (
			("There is a piece to the right of placed tile %d\n",
			 i + 1));
	      my_row = temp_row;
	      while ((button[my_row + 1][temp_col].letter != '\0')
		     && (my_row < 14))
		my_row++;
	      word[0] = '\0';
	      first_row = temp_row;
	      last_row = my_row;
/*	      for (k = first_row, j = 0; k < last_row + 1; k++, j++) */
	      for (k = first_row, j = 0; k < 15; k++, j++)
		{
		  if (!button[k][temp_col].letter)
		    break;
		  else
		    {
		      word[j] = button[k][temp_col].letter;
		      word_score +=
			calc_score_for_tile (&button[k][temp_col],
					     &double_word, &triple_word);
		      word[j + 1] = '\0';
		    }
		}
	      turn_score +=
		get_final_word_score (word_score, double_word, triple_word);
	      TOMTRACE (
			("A secondary word formed by this move\n"
			 "(starting at the the primary word and "
			 "going right) is: %s\n", word));
	      words[number_of_words++] = strdup (word);
	    }
	}
    }
  else
    g_assert_not_reached ();

/* Now check all the words */
  for (i = 0; i < number_of_words; i++)
    {
      TOMTRACE (("Checking word : %s\n", words[i]));
      if (!wordsearch (words[i]))
	return TURN_INVALID_NO_WORD_MATCH;
      else
	TOMTRACE (("Word found in dictionary : %s\n", words[i]));
    }
  TOMTRACE (("Total score for this turn: %d\n", turn_score));
  update_player_score (0, turn_score);
  /* If we get here, after all that, the poor turn must be ok */
  return NO_ERROR;
}

int
start_next_go ()
{
  /* TODO */
  clear_grid_button_validations ();
  if (button[7][7].letter != '\0')
    {
      TOMTRACE (("First go has been taken\n"));
      first_go = FALSE;
    }
  deal_seven_letters ();

  return TRUE;
}

int
count_placed_tiles_in_row (int row)
{
  int i;
  int count = 0;

  for (i = 0; i < 15; i++)
    {
      if (button[row][i].placed_this_go)
	count++;
    }
  return count;
}

int
count_placed_tiles_in_col (int col)
{
  int i;
  int count = 0;

  for (i = 0; i < 15; i++)
    {
      if (button[i][col].placed_this_go)
	count++;
    }
  return count;
}

int
reset_last_go (void)
{
  /* Return all buttons with placed_this_go==TRUE to the tray */
  int i, j;

  for (i = 0; i < 15; i++)
    for (j = 0; j < 15; j++)
      {
	if (button[i][j].placed_this_go)
	  {
	    return_tile_to_rack (&button[i][j]);
	  }
      }

  return TRUE;
}

void
return_tile_to_rack (grid_button * gridbutton)
{
  int i;

  for (i = 3; i < 10; i++)
    {
      if (tile_button[i].letter == '\0')
	{
	  if (gridbutton->is_wildcard)
	    rack_button_assign_char (&tile_button[i], '*');
	  else
	    rack_button_assign_char (&tile_button[i], gridbutton->letter);
	  gtk_label_set (GTK_LABEL (gridbutton->label), "");
	  gridbutton->letter = '\0';
	  gridbutton->placed_this_go = FALSE;
	  gridbutton->is_wildcard = FALSE;
	  reset_tile_status (gridbutton);
	  return;
	}
    }
}

int
are_tiles_adjacent (grid_button * placed_tiles[], int tiles_placed_this_go)
{
  int i = 0, k = 0, l = 0;
  int adjacent = FALSE;
/* Now we check whether the placed tiles are adjacent to existing ones */
  /* If its the first go, the rule is different */
  if (first_go)
    {
      for (i = 0; i < tiles_placed_this_go - 1; i++)
	{
	  if ((placed_tiles[i]->row == 7) && (placed_tiles[i]->col == 7))
	    {
	      adjacent = TRUE;
	      break;
	    }
	}
    }
  else
    {
      for (i = 0; i < tiles_placed_this_go; i++)
	{
	  k = placed_tiles[i]->row;
	  l = placed_tiles[i]->col;

	  if ((k < 14) && (!button[k + 1][l].placed_this_go)
	      && (!button[k + 1][l].letter == '\0'))
	    {
	      adjacent = TRUE;
	      break;
	    }
	  if ((l < 14) && (!button[k][l + 1].placed_this_go)
	      && (!button[k][l + 1].letter == '\0'))
	    {
	      adjacent = TRUE;
	      break;
	    }
	  if ((k > 0) && (!button[k - 1][l].placed_this_go)
	      && (!button[k - 1][l].letter == '\0'))
	    {
	      adjacent = TRUE;
	      break;
	    }
	  if ((l > 0) && (!button[k][l - 1].placed_this_go)
	      && (!button[k][l - 1].letter == '\0'))
	    {
	      adjacent = TRUE;
	      break;
	    }
	}
    }
  if (adjacent)
    return TRUE;
  else
    return FALSE;
}

int
calc_score_for_tile (grid_button * gridbutton, short *double_word,
		     short *triple_word)
{
  int score_so_far = 0;

  if (gridbutton->is_wildcard)
    {
      TOMTRACE (("Tile with letter %c is a wildcard, no points for this tile "
		 "but word bonuses are considered.\n", gridbutton->letter));
      score_so_far += 0;
      if (gridbutton->placed_this_go)
	{
	  TOMTRACE (("\tWildcard tile was placed this go, "
		     "letter scores count\n"));
	  switch (gridbutton->score)
	    {
	    case SCORE_NONE:
	      {
		TOMTRACE (("\tWildcard is not on a special tile\n"));
		break;
	      }
	    case SCORE_DOUBLE_WORD:
	      {
		TOMTRACE (("\tWildcard is on a double word tile\n"));
		(*double_word)++;
		break;
	      }
	    case SCORE_TRIPLE_WORD:
	      {
		TOMTRACE (("\tWildcard is on a triple word tile\n"));
		(*triple_word)++;
		break;
	      }
	    case SCORE_DOUBLE_LETTER:
	      {
		TOMTRACE (("\tWildcard is on a double letter tile, "
			   "but that doesn't count\n"));
		break;
	      }
	    case SCORE_TRIPLE_LETTER:
	      {
		TOMTRACE (("\tWildcard is on a triple letter tile, but "
			   "that doesn't count\n"));
		break;
	      }
	    default:
	      {
		g_assert_not_reached ();
	      }
	    }
	}
    }
  else
    {
      TOMTRACE (("Tile is not a wildcard, letter is %c\n",
		 gridbutton->letter));
      /* Get the score for this letter from the scores array */
      score_so_far += scores[(gridbutton->letter) - 64];
      if (gridbutton->placed_this_go)
	{
	  switch (gridbutton->score)
	    {
	    case SCORE_NONE:
	      {
		TOMTRACE (("\tTile is on an ordinary square\n"));
		break;
	      }
	    case SCORE_DOUBLE_WORD:
	      {
		TOMTRACE (("\tTile is on a double word score\n"));
		(*double_word)++;
		break;
	      }
	    case SCORE_TRIPLE_WORD:
	      {
		TOMTRACE (("\tTile is on a triple word score\n"));
		(*triple_word)++;
		break;
	      }
	    case SCORE_DOUBLE_LETTER:
	      {
		TOMTRACE (("\tTile is on a double letter score\n"));
		score_so_far *= 2;
		break;
	      }
	    case SCORE_TRIPLE_LETTER:
	      {
		TOMTRACE (("\tTile is on a triple letter score\n"));
		score_so_far *= 3;
		break;
	      }
	    default:
	      {
		g_assert_not_reached ();
		break;
	      }
	    }
	}
    }
  TOMTRACE (("\tScore for this tile: %d\n", score_so_far));
  return score_so_far;
}

int
get_final_word_score (int wordscore, int double_word, int triple_word)
{
  TOMTRACE (("Calculating final word score\n"));
  TOMTRACE (("\tScore so far: %d\n", wordscore));
  TOMTRACE (("\tNumber of double word scores: %d\n", double_word));
  TOMTRACE (("\tNumber of triple word scores: %d\n", triple_word));
  if ((double_word == 0) && (triple_word == 0))
    return wordscore;

  if (double_word > 0)
    wordscore *= (2 * double_word);

  if (triple_word > 0)
    wordscore *= (3 * triple_word);

  TOMTRACE (("\tTotal score: %d\n", wordscore));

  return wordscore;
}

void
update_player_score (int player, int turn_score)
{
/* TODO for now, player is hardwired to 0, so forget it! */

  gchar buf[10];
  gchar buf2[60];
  players_scores[player] += turn_score;

  g_snprintf (buf, sizeof (buf), "%d", players_scores[player]);
  gtk_label_set (GTK_LABEL (score_label2), buf);

  g_snprintf (buf2, sizeof (buf2),
	      "Your turn was valid. You scored %d points.", turn_score);
  gnome_app_flash (GNOME_APP (window), buf2);
}
