board_search.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Copyright (C) 1999-2005 Eliot
00003  * Authors: Antoine Fraboulet <antoine.fraboulet@free.fr>
00004  *          Olivier Teuliere  <ipkiss@via.ecp.fr>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  *****************************************************************************/
00020 
00021 #include <dic.h>
00022 #include "tile.h"
00023 #include "rack.h"
00024 #include "round.h"
00025 #include "results.h"
00026 #include "board.h"
00027 
00028 #include "debug.h"
00029 
00030 /*
00031  * computes the score of a word, coordinates may be changed to reflect
00032  * the real direction of the word
00033  */
00034 static void BoardSearchEvalMove(const Board &iBoard,
00035                                 Matrix<Tile> &iTilesMx,
00036                                 Matrix<int> &iPointsMx,
00037                                 Matrix<bool> &iJokerMx,
00038                                 Results &iResults, Round &iWord)
00039 {
00040     int i, pts, ptscross;
00041     int l, t, fromrack;
00042     int len, row, col, wordmul;
00043 
00044     fromrack = 0;
00045     pts      = 0;
00046     ptscross = 0;
00047     wordmul  = 1;
00048 
00049     len = iWord.getWordLen();
00050 
00051     row = iWord.getCoord().getRow();
00052     col = iWord.getCoord().getCol();
00053 
00054     for (i = 0; i < len; i++)
00055     {
00056         if (!iTilesMx[row][col+i].isEmpty())
00057         {
00058             if (!iJokerMx[row][col+i])
00059                 pts += iWord.getTile(i).getPoints();
00060         }
00061         else
00062         {
00063             if (!iWord.isJoker(i))
00064                 l = iWord.getTile(i).getPoints() *
00065                     iBoard.getLetterMultiplier(row, col + i);
00066             else
00067                 l = 0;
00068             pts += l;
00069             wordmul *= iBoard.getWordMultiplier(row, col + i);
00070 
00071             t = iPointsMx[row][col+i];
00072             if (t >= 0)
00073                 ptscross += (t + l) * iBoard.getWordMultiplier(row, col + i);
00074             fromrack++;
00075         }
00076     }
00077     pts = ptscross + pts * wordmul + 50 * (fromrack == 7);
00078     iWord.setBonus(fromrack == 7);
00079     iWord.setPoints(pts);
00080 
00081     // XXX: ugly!
00082     if (iWord.getCoord().getDir() == Coord::VERTICAL)
00083     {
00084         // Exchange the coordinates temporarily
00085         iWord.accessCoord().swap();
00086     }
00087     iResults.add(iWord);
00088     if (iWord.getCoord().getDir() == Coord::VERTICAL)
00089     {
00090         // Restore the coordinates
00091         iWord.accessCoord().swap();
00092     }
00093 }
00094 
00095 
00096 static void ExtendRight(const Board &iBoard,
00097                         const Dictionary &iDic,
00098                         Matrix<Tile> &iTilesMx,
00099                         Matrix<Cross> &iCrossMx,
00100                         Matrix<int> &iPointsMx,
00101                         Matrix<bool> &iJokerMx,
00102                         Rack &iRack, Round &ioPartialWord,
00103                         Results &iResults, unsigned int iNode,
00104                         int iRow, int iCol, int iAnchor)
00105 {
00106     Tile l;
00107     unsigned int succ;
00108 
00109     if (iTilesMx[iRow][iCol].isEmpty())
00110     {
00111         if (Dic_word(iDic, iNode) && iCol > iAnchor)
00112             BoardSearchEvalMove(iBoard, iTilesMx, iPointsMx, iJokerMx,
00113                                 iResults, ioPartialWord);
00114 
00115         for (succ = Dic_succ(iDic, iNode); succ; succ = Dic_next(iDic, succ))
00116         {
00117             l = Tile(Dic_chr(iDic, succ));
00118             if (iCrossMx[iRow][iCol].check(l))
00119             {
00120                 if (iRack.in(l))
00121                 {
00122                     iRack.remove(l);
00123                     ioPartialWord.addRightFromRack(l, 0);
00124                     ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00125                                 iJokerMx, iRack, ioPartialWord, iResults,
00126                                 succ, iRow, iCol + 1, iAnchor);
00127                     ioPartialWord.removeRightToRack(l, 0);
00128                     iRack.add(l);
00129                 }
00130                 if (iRack.in(Tile::Joker()))
00131                 {
00132                     iRack.remove(Tile::Joker());
00133                     ioPartialWord.addRightFromRack(l, 1);
00134                     ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00135                                 iJokerMx, iRack, ioPartialWord, iResults,
00136                                 succ, iRow, iCol + 1, iAnchor);
00137                     ioPartialWord.removeRightToRack(l, 1);
00138                     iRack.add(Tile::Joker());
00139                 }
00140             }
00141         }
00142     }
00143     else
00144     {
00145         l = iTilesMx[iRow][iCol];
00146         for (succ = Dic_succ(iDic, iNode); succ ; succ = Dic_next(iDic, succ))
00147         {
00148             if (Tile(Dic_chr(iDic, succ)) == l)
00149             {
00150                 ioPartialWord.addRightFromBoard(l);
00151                 ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00152                             iJokerMx, iRack, ioPartialWord,
00153                             iResults, succ, iRow, iCol + 1, iAnchor);
00154                 ioPartialWord.removeRightToBoard(l);
00155             }
00156         }
00157     }
00158 }
00159 
00160 
00161 static void LeftPart(const Board &iBoard,
00162                      const Dictionary &iDic,
00163                      Matrix<Tile> &iTilesMx,
00164                      Matrix<Cross> &iCrossMx,
00165                      Matrix<int> &iPointsMx,
00166                      Matrix<bool> &iJokerMx,
00167                      Rack &iRack, Round &ioPartialWord,
00168                      Results &iResults, int n, int iRow,
00169                      int iAnchor, int iLimit)
00170 {
00171     Tile l;
00172     int succ;
00173 
00174     ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx, iJokerMx, iRack,
00175                 ioPartialWord, iResults, n, iRow, iAnchor, iAnchor);
00176 
00177     if (iLimit > 0)
00178     {
00179         for (succ = Dic_succ(iDic, n); succ; succ = Dic_next(iDic, succ))
00180         {
00181             l = Tile(Dic_chr(iDic, succ));
00182             if (iRack.in(l))
00183             {
00184                 iRack.remove(l);
00185                 ioPartialWord.addRightFromRack(l, 0);
00186                 ioPartialWord.accessCoord().setCol(ioPartialWord.getCoord().getCol() - 1);
00187                 LeftPart(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00188                          iJokerMx, iRack, ioPartialWord, iResults,
00189                          succ, iRow, iAnchor, iLimit - 1);
00190                 ioPartialWord.accessCoord().setCol(ioPartialWord.getCoord().getCol() + 1);
00191                 ioPartialWord.removeRightToRack(l, 0);
00192                 iRack.add(l);
00193             }
00194             if (iRack.in(Tile::Joker()))
00195             {
00196                 iRack.remove(Tile::Joker());
00197                 ioPartialWord.addRightFromRack(l, 1);
00198                 ioPartialWord.accessCoord().setCol(ioPartialWord.getCoord().getCol() - 1);
00199                 LeftPart(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00200                          iJokerMx, iRack, ioPartialWord, iResults,
00201                          succ, iRow, iAnchor, iLimit - 1);
00202                 ioPartialWord.accessCoord().setCol(ioPartialWord.getCoord().getCol() + 1);
00203                 ioPartialWord.removeRightToRack(l, 1);
00204                 iRack.add(Tile::Joker());
00205             }
00206         }
00207     }
00208 }
00209 
00210 
00211 static void BoardSearchAux(const Board &iBoard,
00212                            const Dictionary &iDic,
00213                            Matrix<Tile> &iTilesMx,
00214                            Matrix<Cross> &iCrossMx,
00215                            Matrix<int> &iPointsMx,
00216                            Matrix<bool> &iJokerMx,
00217                            Rack &iRack, Results &iResults,
00218                            Coord::Direction iDir)
00219 {
00220     int row, col, lastanchor;
00221     Round partialword;
00222     for (row = 1; row <= BOARD_DIM; row++)
00223     {
00224         partialword.init();
00225         partialword.accessCoord().setDir(iDir);
00226         partialword.accessCoord().setRow(row);
00227         lastanchor = 0;
00228         for (col = 1; col <= BOARD_DIM; col++)
00229         {
00230             if (iTilesMx[row][col].isEmpty() &&
00231                 (!iTilesMx[row][col - 1].isEmpty() ||
00232                  !iTilesMx[row][col + 1].isEmpty() ||
00233                  !iTilesMx[row - 1][col].isEmpty() ||
00234                  !iTilesMx[row + 1][col].isEmpty()))
00235             {
00236                 if (!iTilesMx[row][col - 1].isEmpty())
00237                 {
00238                     partialword.accessCoord().setCol(lastanchor + 1);
00239                     ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00240                                 iJokerMx, iRack, partialword, iResults,
00241                                 Dic_root(iDic), row, lastanchor + 1, col);
00242                 }
00243                 else
00244                 {
00245                     partialword.accessCoord().setCol(col);
00246                     LeftPart(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx,
00247                              iJokerMx, iRack, partialword, iResults,
00248                              Dic_root(iDic), row, col, col -
00249                              lastanchor - 1);
00250                 }
00251                 lastanchor = col;
00252             }
00253         }
00254     }
00255 }
00256 
00257 
00258 void Board::search(const Dictionary &iDic,
00259                    const Rack &iRack,
00260                    Results &oResults)
00261 {
00262     // Create a copy of the rack to avoid modifying the given one
00263     Rack copyRack = iRack;
00264 
00265     BoardSearchAux(*this, iDic, m_tilesRow, m_crossRow,
00266                    m_pointRow, m_jokerRow,
00267                    copyRack, oResults, Coord::HORIZONTAL);
00268 
00269     BoardSearchAux(*this, iDic, m_tilesCol, m_crossCol,
00270                    m_pointCol, m_jokerCol,
00271                    copyRack, oResults, Coord::VERTICAL);
00272 }
00273 
00274 
00275 void Board::searchFirst(const Dictionary &iDic,
00276                         const Rack &iRack,
00277                         Results &oResults)
00278 {
00279     int row = 8, col = 8;
00280 
00281     // Create a copy of the rack to avoid modifying the given one
00282     Rack copyRack = iRack;
00283 
00284     Round partialword;
00285     partialword.accessCoord().setRow(row);
00286     partialword.accessCoord().setCol(col);
00287     partialword.accessCoord().setDir(Coord::HORIZONTAL);
00288     LeftPart(*this, iDic, m_tilesRow, m_crossRow,
00289              m_pointRow, m_jokerRow,
00290              copyRack, partialword, oResults, Dic_root(iDic), row, col,
00291              copyRack.nTiles() - 1);
00292 }
00293 
00294 /// Local Variables:
00295 /// mode: c++
00296 /// mode: hs-minor
00297 /// c-basic-offset: 4
00298 /// indent-tabs-mode: nil
00299 /// End:

Generated on Thu Dec 29 02:01:14 2005 for Eliot by  doxygen 1.4.5