/* This file is part of cardwords
   (c) 1998 1999 2000 Tobias Peters
   see file COPYING for the copyright terms.
   
   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
*/

// cardwords_dicbot_cardtable.hh

/* Classes containing _DicBot_ and files containing _dicbot_ indicate
   classes and files for dicbot. dicbot will be the dictionary and
   robot process started by the cardwords server.

   The server delegates the following tasks to dicbot:

   - Check if a move is valid. This means:
   . * Check if there is enough space on the card-table to actually lay the
   .   cards.
   . * Check if all words created by that move are valid. This can be
   .   disabled.
   - Calculate the score of a move. This contains a validity check as above.
   - Calculate the best possible move for a given set of cards. The best
   . possible move means the one that gets the most points.
   . This contains several score calculations as above.
*/

// This file defines The class CardWords_DicBot_CardTable.
// This class contains all information dicbot wants to have about the
// card-table.


/* The format of a card-table description, as used by
   ostream& << CardWords_DicBot_CardTable&   and   read_card_table(istream&):

   <width> * <height>
   (<starting_column>,<starting_row>)
   [(<column>,<row>) [L <value>] [W <value>] [C <value>] [B] [T <card description>];]*
   (<end_column>,<end_row>)

   <...> : ... is meta name
   [...] : ... can be left out
   [...]*: ... can be there zero, one ore more times

   width and height are unsigned ints. They define the size of the card-table.
   starting_column  The first move onto the card-table must place a card in
   .                this column if starting_column < width.
   starting_row     The first move onto the card-table must place a card in
   .                this row if starting_row < height.
   .                starting_column and starting_row together are in a
   .                CardWords_CardTableLocation format. If both values are
   .                valid, they define a starting card-table cell together.
   column and row   define a valid card-table cell with 0<=column<width and
   .                0<=row<height. This is in a CardWords_CardTableLocation
   .                format.
   * ( , ) ;        literal asterix, parenthesis, comma and semicolon.
   .                ( , and ) belong to CardWords_CardTableLocation format.
   L W C T          literal L, W, C and T; the next will be a
   .                letter factor, word factor, cell points value or card
   .                description respectively.
   B                flag for a blocked cell.
   value            an int.
   card description a valid card description as produced by
   .                ostream& << CardWords_CardDescription& and recognized
   .                by istream& >> CardWords_CardDescription&.
   .                If T is left out, <no card> is the default (which
   .                cannot yet be expressed with a card description).
   .                This format is described in cardwords_cardbase.hh.
   end_column, end_row
   .                This is the end marker. If column or row are out of
   .                range, the end of the description is reached.
   .                This is in a CardWords_CardTableLocation format.


   Card-table cells not mentioned in the description are assumed to have
   letter factor DEFAULT_LETTER_FACTOR, word factor DEFAULT_WORD_FACTOR,
   cell points DEFAULT_CELL_POINTS, no card and are not blocked.
   DEFAULT_LETTER_FACTOR, DEFAULT_WORD_FACTOR should be 1,
   DEFAULT_CELL_POINTS should be 0.
*/

#ifndef CARDWORDS_DICTBOT_TABLE_HH
#define CARDWORDS_DICTBOT_TABLE_HH

#include "cardwords_cardtablelocation.hh"
#include "cardwords_dicbot_cardtablecell.hh"
#include "cardwords_matrix.hh"
namespace CardWords {
class Move;
class Dictionary;
class BonusTable;
class String;

#define MOVE_VALID (-1)
#define MOVE_INVALID (-2)
#define IS_MOVE_VALID(move) ((move) == MOVE_VALID)
#define IS_MOVE_INVALID(move) ((move) != MOVE_VALID)

class DicBot_CardTable :
  public Matrix<DicBot_CardTableCell>
{
public:
  DicBot_CardTable (size_t columns,
                              size_t rows,
                              CardTableLocation start);

  void 
  add_card (CardTableLocation, const CardDescription &);

  void 
  remove_card (CardTableLocation);

  // Returns -1 (MOVE_VALID) if the move is valid.
  // Returns -2 (MOVE_INVALID) if the move is invalid because the move is not
  // in the dictionary.
  // Returns 0<= x < move.size() if the move's x'th card led to an invalid
  // side word.
  // If the given pointer to String is not 0, sets String
  // to the word that was not in the dictionary.
  int
  check_move (const Move & move,
              const Dictionary * dict = 0,
              String * false_word = 0);

  // Returns -1 (MOVE_VALID) if the move is valid.
  // Returns -2 (MOVE_INVALID) if the move is invalid because the move is not
  // in the dictionary.
  // Returns 0<= x < move.size() if the move's x'th card led to an invalid
  // side word.
  // Writes the score of that move into the int referenced by the second
  // argument, if the move is valid.
  // If false_word is not 0, it is possible to differentiate between a move
  // that is only invalid because one of the new words are not in the
  // dictionary and a move that is is invalid because of formal reasons, like
  // not touching another card or not obeying the start condition:
  // If count_move sets *false_word to a word, than this word would have been
  // created and is not in the dictionary. The return value in this case is
  // either -2, if the primary word fails, or >= 0, if a sideword fails.
  // If count_move does not touch *false_word (make it empty to detect this
  // difference), and returns MOVE_INVALID, then formal reasons forbid this
  // move.
  // If the move is valid (MOVE_VALID is returned), *false_word is also left
  // untouched.
  int
  count_move (const Move &,
              int * score,
              const Dictionary * dict= 0,
              String * false_word = 0);

  // the same as count_move, but actually lays the letters onto the card-table
  int
  add_move (const Move & move,
            int * score,
            const Dictionary * dict = 0,
            String * false_word = 0);

  // counts the number of free places after this field
  size_t
  count_free (CardTableLocation, Direction) const;

  // checks if a neighbour of this location in the given direction carries a
  // card
  bool
  has_neighbour (CardTableLocation, Direction) const;

  // return how many cards are on the card-table:
  size_t
  get_no_of_contained_cards(void) const;

  bool
  is_empty (void) const;

  // Return the starting_pos. If one of the values is out of range, we only
  // have a starting row/column. If both values are out of range, there is no
  // restriction where to place the first move.
  CardTableLocation get_starting_pos(void) const;

  // setting the bonus table:
  void set_bonus_table (const BonusTable *);
  
private:
  // Same comment as to check_move applies.
  // Users of this class do not need to know about the additional parameter,
  // that's why we have check_move and private_check_move.
  int
  private_check_move (const Move & move,
                      const Dictionary * dict,
                      String * false_word,
                      bool recursive);

  // Same comment as to count_move applies.
  // Users of this class do not need to know about the additional parameter,
  // that's why we have count_move and private_count_move.
  int
  private_count_move (const Move &,
                      int * score,
                      const Dictionary * dict,
                      String * false_word,
                      bool recursive);
  size_t no_of_contained_cards;
  CardTableLocation starting_pos;

  const BonusTable * bonus_table;
};
}
// read card-table from stream
// see comment at end of file for an explanation of the format
CardWords::DicBot_CardTable *
read_card_table( class istream & );

// output card-table to stream in a format accepted by read_card_table()
// see comment at end of file for an explanation of the format
ostream & operator <<(class ostream &, const CardWords::DicBot_CardTable &);

#endif

