2005-02-05 12:14:56 +01:00
|
|
|
/*****************************************************************************
|
2008-01-08 14:52:32 +01:00
|
|
|
* Eliot
|
|
|
|
* Copyright (C) 1999-2007 Antoine Fraboulet & Olivier Teulière
|
|
|
|
* Authors: Antoine Fraboulet <antoine.fraboulet @@ free.fr>
|
|
|
|
* Olivier Teulière <ipkiss @@ gmail.com>
|
2005-02-05 12:14:56 +01:00
|
|
|
*
|
|
|
|
* 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
|
2005-10-23 16:53:42 +02:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2005-02-05 12:14:56 +01:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2006-01-22 13:23:52 +01:00
|
|
|
#include <wctype.h>
|
2009-06-23 15:21:19 +02:00
|
|
|
#include <algorithm>
|
2009-11-29 17:01:31 +01:00
|
|
|
#include <cstdio>
|
2009-01-17 15:57:32 +01:00
|
|
|
|
2005-02-05 12:14:56 +01:00
|
|
|
#include "dic.h"
|
2009-01-17 15:57:32 +01:00
|
|
|
|
|
|
|
#include "board.h"
|
|
|
|
#include "board_search.h"
|
2011-08-27 19:21:26 +02:00
|
|
|
#include "game_params.h"
|
2005-02-05 12:14:56 +01:00
|
|
|
#include "tile.h"
|
|
|
|
#include "round.h"
|
|
|
|
#include "rack.h"
|
|
|
|
#include "results.h"
|
2006-08-12 00:12:10 +02:00
|
|
|
#include "debug.h"
|
2005-02-05 12:14:56 +01:00
|
|
|
|
|
|
|
#define oo 0
|
|
|
|
#define __ 1
|
|
|
|
#define T2 2
|
|
|
|
#define T3 3
|
|
|
|
#define W2 2
|
|
|
|
#define W3 3
|
|
|
|
|
|
|
|
|
|
|
|
const int Board::m_tileMultipliers[BOARD_REALDIM][BOARD_REALDIM] =
|
|
|
|
{
|
|
|
|
{ oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo },
|
|
|
|
{ oo,__,__,__,T2,__,__,__,__,__,__,__,T2,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,T3,__,__,__,T3,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,T2,__,T2,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,T2,__,__,__,__,__,__,T2,__,__,__,__,__,__,T2,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,T3,__,__,__,T3,__,__,__,T3,__,__,__,T3,__,oo },
|
|
|
|
{ oo,__,__,T2,__,__,__,T2,__,T2,__,__,__,T2,__,__,oo },
|
|
|
|
{ oo,__,__,__,T2,__,__,__,__,__,__,__,T2,__,__,__,oo },
|
|
|
|
{ oo,__,__,T2,__,__,__,T2,__,T2,__,__,__,T2,__,__,oo },
|
|
|
|
{ oo,__,T3,__,__,__,T3,__,__,__,T3,__,__,__,T3,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,T2,__,__,__,__,__,__,T2,__,__,__,__,__,__,T2,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,T2,__,T2,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,T3,__,__,__,T3,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,T2,__,__,__,__,__,__,__,T2,__,__,__,oo },
|
|
|
|
{ oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const int Board::m_wordMultipliers[BOARD_REALDIM][BOARD_REALDIM] =
|
|
|
|
{
|
|
|
|
{ oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo },
|
|
|
|
{ oo,W3,__,__,__,__,__,__,W3,__,__,__,__,__,__,W3,oo },
|
|
|
|
{ oo,__,W2,__,__,__,__,__,__,__,__,__,__,__,W2,__,oo },
|
|
|
|
{ oo,__,__,W2,__,__,__,__,__,__,__,__,__,W2,__,__,oo },
|
|
|
|
{ oo,__,__,__,W2,__,__,__,__,__,__,__,W2,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,W2,__,__,__,__,__,W2,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,W3,__,__,__,__,__,__,W2,__,__,__,__,__,__,W3,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,__,W2,__,__,__,__,__,W2,__,__,__,__,oo },
|
|
|
|
{ oo,__,__,__,W2,__,__,__,__,__,__,__,W2,__,__,__,oo },
|
|
|
|
{ oo,__,__,W2,__,__,__,__,__,__,__,__,__,W2,__,__,oo },
|
|
|
|
{ oo,__,W2,__,__,__,__,__,__,__,__,__,__,__,W2,__,oo },
|
|
|
|
{ oo,W3,__,__,__,__,__,__,W3,__,__,__,__,__,__,W3,oo },
|
|
|
|
{ oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo,oo }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-08-27 19:21:26 +02:00
|
|
|
Board::Board(const GameParams &iParams):
|
|
|
|
m_params(iParams),
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesRow(BOARD_REALDIM, Tile()),
|
|
|
|
m_tilesCol(BOARD_REALDIM, Tile()),
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerRow(BOARD_REALDIM, false),
|
|
|
|
m_jokerCol(BOARD_REALDIM, false),
|
|
|
|
m_crossRow(BOARD_REALDIM, Cross()),
|
|
|
|
m_crossCol(BOARD_REALDIM, Cross()),
|
|
|
|
m_pointRow(BOARD_REALDIM, -1),
|
|
|
|
m_pointCol(BOARD_REALDIM, -1),
|
2009-06-23 14:56:40 +02:00
|
|
|
m_testsRow(BOARD_REALDIM, false),
|
2008-09-13 23:32:45 +02:00
|
|
|
m_isEmpty(true)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
// No cross check allowed around the board
|
|
|
|
for (int i = 0; i < BOARD_REALDIM; i++)
|
|
|
|
{
|
2006-11-05 14:30:06 +01:00
|
|
|
m_crossRow[0][i].setNone();
|
|
|
|
m_crossCol[0][i].setNone();
|
|
|
|
m_crossRow[i][0].setNone();
|
|
|
|
m_crossCol[i][0].setNone();
|
|
|
|
m_crossRow[BOARD_REALDIM - 1][i].setNone();
|
|
|
|
m_crossCol[BOARD_REALDIM - 1][i].setNone();
|
|
|
|
m_crossRow[i][BOARD_REALDIM - 1].setNone();
|
|
|
|
m_crossCol[i][BOARD_REALDIM - 1].setNone();
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-23 15:21:19 +02:00
|
|
|
const Tile& Board::getTile(int iRow, int iCol) const
|
2005-11-05 00:26:03 +01:00
|
|
|
{
|
2009-06-23 15:21:19 +02:00
|
|
|
return m_tilesRow[iRow][iCol];
|
2005-11-05 00:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-23 15:21:19 +02:00
|
|
|
wstring Board::getDisplayStr(int iRow, int iCol) const
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2009-06-23 15:21:19 +02:00
|
|
|
ASSERT(!isVacant(iRow, iCol),
|
|
|
|
"Trying to get the display string on an empty board square");
|
|
|
|
wstring str = getTile(iRow, iCol).getDisplayStr();
|
|
|
|
if (isJoker(iRow, iCol))
|
|
|
|
std::transform(str.begin(), str.end(), str.begin(), towlower);
|
|
|
|
return str;
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Board::isJoker(int iRow, int iCol) const
|
|
|
|
{
|
|
|
|
return m_jokerRow[iRow][iCol];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Board::isVacant(int iRow, int iCol) const
|
|
|
|
{
|
|
|
|
if (iRow < 1 || iRow > BOARD_DIM ||
|
|
|
|
iCol < 1 || iCol > BOARD_DIM)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2005-02-17 21:01:59 +01:00
|
|
|
return m_tilesRow[iRow][iCol].isEmpty();
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Board::addRound(const Dictionary &iDic, const Round &iRound)
|
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
int row = iRound.getCoord().getRow();
|
|
|
|
int col = iRound.getCoord().getCol();
|
2005-11-05 14:56:59 +01:00
|
|
|
if (iRound.getCoord().getDir() == Coord::HORIZONTAL)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
Tile t;
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-02-17 21:01:59 +01:00
|
|
|
if (m_tilesRow[row][col + i].isEmpty())
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
t = iRound.getTile(i);
|
|
|
|
m_tilesRow[row][col + i] = t;
|
|
|
|
m_jokerRow[row][col + i] = iRound.isJoker(i);
|
|
|
|
m_tilesCol[col + i][row] = t;
|
|
|
|
m_jokerCol[col + i][row] = iRound.isJoker(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
Tile t;
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-02-17 21:01:59 +01:00
|
|
|
if (m_tilesRow[row + i][col].isEmpty())
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
t = iRound.getTile(i);
|
|
|
|
m_tilesRow[row + i][col] = t;
|
|
|
|
m_jokerRow[row + i][col] = iRound.isJoker(i);
|
|
|
|
m_tilesCol[col][row + i] = t;
|
|
|
|
m_jokerCol[col][row + i] = iRound.isJoker(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buildCross(iDic);
|
2008-09-13 23:32:45 +02:00
|
|
|
m_isEmpty = false;
|
2005-02-05 12:14:56 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
checkDouble();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Board::removeRound(const Dictionary &iDic, const Round &iRound)
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
ASSERT(!m_isEmpty, "The board should not be empty");
|
2008-01-08 14:52:32 +01:00
|
|
|
int row = iRound.getCoord().getRow();
|
|
|
|
int col = iRound.getCoord().getCol();
|
2005-11-05 14:56:59 +01:00
|
|
|
if (iRound.getCoord().getDir() == Coord::HORIZONTAL)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
ASSERT(iRound.getTile(i).toCode() == m_tilesRow[row][col + i].toCode(),
|
|
|
|
"Invalid round removal");
|
2005-02-05 12:14:56 +01:00
|
|
|
if (iRound.isPlayedFromRack(i))
|
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesRow[row][col + i] = Tile();
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerRow[row][col + i] = false;
|
2006-11-05 14:30:06 +01:00
|
|
|
m_crossRow[row][col + i].setAny();
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesCol[col + i][row] = Tile();
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerCol[col + i][row] = false;
|
2006-11-05 14:30:06 +01:00
|
|
|
m_crossCol[col + i][row].setAny();
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
ASSERT(iRound.getTile(i).toCode() == m_tilesRow[row + i][col].toCode(),
|
|
|
|
"Invalid round removal");
|
2005-02-05 12:14:56 +01:00
|
|
|
if (iRound.isPlayedFromRack(i))
|
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesRow[row + i][col] = Tile();
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerRow[row + i][col] = false;
|
2006-11-05 14:30:06 +01:00
|
|
|
m_crossRow[row + i][col].setAny();
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesCol[col][row + i] = Tile();
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerCol[col][row + i] = false;
|
2006-11-05 14:30:06 +01:00
|
|
|
m_crossCol[col][row + i].setAny();
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buildCross(iDic);
|
|
|
|
#ifdef DEBUG
|
|
|
|
checkDouble();
|
|
|
|
#endif
|
2008-09-13 23:32:45 +02:00
|
|
|
|
|
|
|
// Update the m_isEmpty flag
|
|
|
|
for (int i = 1; i <= BOARD_DIM; i++)
|
|
|
|
{
|
|
|
|
for (int j = 1; j <= BOARD_DIM; j++)
|
|
|
|
{
|
|
|
|
if (!m_tilesRow[i][j].isEmpty())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_isEmpty = true;
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* XXX: There is duplicated code with board_search.c.
|
|
|
|
* We could probably factorize something... */
|
2008-11-22 14:09:28 +01:00
|
|
|
int Board::checkRoundAux(const Matrix<Tile> &iTilesMx,
|
|
|
|
const Matrix<Cross> &iCrossMx,
|
|
|
|
const Matrix<int> &iPointsMx,
|
|
|
|
const Matrix<bool> &iJokerMx,
|
|
|
|
Round &iRound) const
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
Tile t;
|
2008-01-08 14:52:32 +01:00
|
|
|
int l, p;
|
2005-02-05 12:14:56 +01:00
|
|
|
bool isolated = true;
|
|
|
|
|
2011-08-27 19:21:26 +02:00
|
|
|
int fromrack = 0;
|
2008-01-08 14:52:32 +01:00
|
|
|
int pts = 0;
|
|
|
|
int ptscross = 0;
|
|
|
|
int wordmul = 1;
|
|
|
|
int row = iRound.getCoord().getRow();
|
|
|
|
int col = iRound.getCoord().getCol();
|
2005-02-05 12:14:56 +01:00
|
|
|
|
2008-09-13 23:32:45 +02:00
|
|
|
// Is the word going out of the board?
|
|
|
|
if (col + iRound.getWordLen() > BOARD_MAX + 1)
|
|
|
|
return 8;
|
|
|
|
|
|
|
|
// Is the word an extension of another word?
|
2005-02-17 21:01:59 +01:00
|
|
|
if (!iTilesMx[row][col - 1].isEmpty() ||
|
|
|
|
!iTilesMx[row][col + iRound.getWordLen()].isEmpty())
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
t = iRound.getTile(i);
|
2005-02-17 21:01:59 +01:00
|
|
|
if (!iTilesMx[row][col + i].isEmpty())
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
// There is already a letter on the board
|
2005-02-05 12:14:56 +01:00
|
|
|
if (iTilesMx[row][col + i] != t)
|
2006-08-12 00:12:10 +02:00
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
// Check if it is only a joker
|
2006-08-12 00:12:10 +02:00
|
|
|
if ((iTilesMx[row][col+i].toCode() == t.toCode()) && iTilesMx[row][col+i].isJoker())
|
|
|
|
{
|
2006-12-23 14:50:43 +01:00
|
|
|
// Do nothing, we don't need to change the tile in the round
|
2008-09-13 23:32:45 +02:00
|
|
|
//iRound.setJoker(i,true);
|
2006-08-12 00:12:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
// Trying to overwrite a placed letter
|
2006-08-12 00:12:10 +02:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
2005-02-05 12:14:56 +01:00
|
|
|
|
|
|
|
isolated = false;
|
|
|
|
iRound.setFromBoard(i);
|
|
|
|
|
2005-03-27 23:45:04 +02:00
|
|
|
if (!iJokerMx[row][col + i])
|
2005-02-05 12:14:56 +01:00
|
|
|
pts += t.getPoints();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
// The letter is not yet on the board
|
2005-02-05 12:14:56 +01:00
|
|
|
if (iCrossMx[row][col + i].check(t))
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
// A non-trivial cross-check means an anchor square
|
2005-03-27 23:45:04 +02:00
|
|
|
if (!iCrossMx[row][col + i].isAny())
|
2005-02-05 12:14:56 +01:00
|
|
|
isolated = false;
|
|
|
|
|
2005-03-27 23:45:04 +02:00
|
|
|
if (!iRound.isJoker(i))
|
2005-02-05 12:14:56 +01:00
|
|
|
l = t.getPoints() * m_tileMultipliers[row][col + i];
|
|
|
|
else
|
|
|
|
l = 0;
|
|
|
|
pts += l;
|
|
|
|
wordmul *= m_wordMultipliers[row][col + i];
|
|
|
|
|
|
|
|
p = iPointsMx[row][col + i];
|
|
|
|
if (p >= 0)
|
|
|
|
{
|
|
|
|
ptscross += (p + l) * m_wordMultipliers[row][col + i];
|
|
|
|
}
|
2011-08-27 19:21:26 +02:00
|
|
|
++fromrack;
|
2005-02-05 12:14:56 +01:00
|
|
|
iRound.setFromRack(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
// The letter is not in the crosscheck
|
2005-02-05 12:14:56 +01:00
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-13 23:32:45 +02:00
|
|
|
// There must be at least 1 letter from the rack
|
2005-02-05 12:14:56 +01:00
|
|
|
if (fromrack == 0)
|
|
|
|
return 4;
|
|
|
|
|
2011-08-27 19:21:26 +02:00
|
|
|
// We may not be allowed to use so many letters from the rack
|
|
|
|
// (cf. "7 among 8" variant)
|
|
|
|
if (fromrack > m_params.getLettersToPlay())
|
|
|
|
return 9;
|
|
|
|
|
|
|
|
// The word must cover at least one anchor square, except
|
|
|
|
// for the first turn
|
2008-09-13 23:32:45 +02:00
|
|
|
if (isolated && !m_isEmpty)
|
2005-02-05 12:14:56 +01:00
|
|
|
return 5;
|
2008-09-13 23:32:45 +02:00
|
|
|
// The first word must be horizontal
|
2009-03-12 19:56:25 +01:00
|
|
|
// Deactivated, as a vertical first word is allowed in free games,
|
|
|
|
// and possibly in duplicate games as well (it depends on the sources)
|
|
|
|
#if 0
|
2008-09-13 23:32:45 +02:00
|
|
|
if (m_isEmpty && iRound.getCoord().getDir() == Coord::VERTICAL)
|
2005-02-05 12:14:56 +01:00
|
|
|
return 6;
|
2009-03-12 19:56:25 +01:00
|
|
|
#endif
|
2008-09-13 23:32:45 +02:00
|
|
|
// The first word must cover the H8 square
|
|
|
|
if (m_isEmpty
|
2005-02-05 12:14:56 +01:00
|
|
|
&& (row != 8 || col > 8 || col + iRound.getWordLen() <= 8))
|
|
|
|
{
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
2008-09-13 23:32:45 +02:00
|
|
|
// Set the iPointsMx and bonus
|
2011-08-27 19:21:26 +02:00
|
|
|
pts = ptscross + pts * wordmul;
|
2011-08-27 20:29:44 +02:00
|
|
|
if (fromrack == m_params.getLettersToPlay())
|
2011-08-27 19:21:26 +02:00
|
|
|
{
|
|
|
|
pts += m_params.getBonusPoints();
|
|
|
|
iRound.setBonus(true);
|
|
|
|
}
|
2005-02-05 12:14:56 +01:00
|
|
|
iRound.setPoints(pts);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-22 14:09:28 +01:00
|
|
|
int Board::checkRound(Round &iRound) const
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-11-05 14:56:59 +01:00
|
|
|
if (iRound.getCoord().getDir() == Coord::HORIZONTAL)
|
|
|
|
{
|
2005-02-05 12:14:56 +01:00
|
|
|
return checkRoundAux(m_tilesRow, m_crossRow,
|
2008-09-13 23:32:45 +02:00
|
|
|
m_pointRow, m_jokerRow, iRound);
|
2005-11-05 14:56:59 +01:00
|
|
|
}
|
2005-02-05 12:14:56 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// XXX: ugly!
|
2005-11-05 14:56:59 +01:00
|
|
|
// Exchange the coordinates temporarily
|
|
|
|
iRound.accessCoord().swap();
|
2005-02-05 12:14:56 +01:00
|
|
|
|
2005-11-05 14:56:59 +01:00
|
|
|
int res = checkRoundAux(m_tilesCol, m_crossCol,
|
2008-09-13 23:32:45 +02:00
|
|
|
m_pointCol, m_jokerCol, iRound);
|
2005-02-05 12:14:56 +01:00
|
|
|
|
2005-11-05 14:56:59 +01:00
|
|
|
// Restore the coordinates
|
|
|
|
iRound.accessCoord().swap();
|
2005-02-05 12:14:56 +01:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Board::testRound(const Round &iRound)
|
|
|
|
{
|
|
|
|
Tile t;
|
|
|
|
|
2008-01-08 14:52:32 +01:00
|
|
|
int row = iRound.getCoord().getRow();
|
|
|
|
int col = iRound.getCoord().getCol();
|
2005-11-05 14:56:59 +01:00
|
|
|
if (iRound.getCoord().getDir() == Coord::HORIZONTAL)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-02-17 21:01:59 +01:00
|
|
|
if (m_tilesRow[row][col + i].isEmpty())
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
t = iRound.getTile(i);
|
|
|
|
m_tilesRow[row][col + i] = t;
|
|
|
|
m_jokerRow[row][col + i] = iRound.isJoker(i);
|
2009-06-23 14:56:40 +02:00
|
|
|
m_testsRow[row][col + i] = true;
|
2005-02-05 12:14:56 +01:00
|
|
|
|
|
|
|
m_tilesCol[col + i][row] = t;
|
|
|
|
m_jokerCol[col + i][row] = iRound.isJoker(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
for (unsigned int i = 0; i < iRound.getWordLen(); i++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-02-17 21:01:59 +01:00
|
|
|
if (m_tilesRow[row + i][col].isEmpty())
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
t = iRound.getTile(i);
|
|
|
|
m_tilesRow[row + i][col] = t;
|
|
|
|
m_jokerRow[row + i][col] = iRound.isJoker(i);
|
2009-06-23 14:56:40 +02:00
|
|
|
m_testsRow[row + i][col] = true;
|
2005-02-05 12:14:56 +01:00
|
|
|
|
|
|
|
m_tilesCol[col][row + i] = t;
|
|
|
|
m_jokerCol[col][row + i] = iRound.isJoker(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Board::removeTestRound()
|
|
|
|
{
|
2005-02-17 21:01:59 +01:00
|
|
|
for (int row = 1; row <= BOARD_DIM; row++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-02-17 21:01:59 +01:00
|
|
|
for (int col = 1; col <= BOARD_DIM; col++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
if (m_testsRow[row][col])
|
|
|
|
{
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesRow[row][col] = Tile();
|
2009-06-23 14:56:40 +02:00
|
|
|
m_testsRow[row][col] = false;
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerRow[row][col] = false;
|
|
|
|
|
2008-01-08 14:52:32 +01:00
|
|
|
m_tilesCol[col][row] = Tile();
|
2005-02-05 12:14:56 +01:00
|
|
|
m_jokerCol[col][row] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-23 14:56:40 +02:00
|
|
|
bool Board::isTestChar(int iRow, int iCol) const
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
return m_testsRow[iRow][iCol];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-09 11:48:19 +01:00
|
|
|
int Board::GetWordMultiplier(int iRow, int iCol)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
if (iRow < BOARD_MIN || iRow > BOARD_MAX ||
|
|
|
|
iCol < BOARD_MIN || iCol > BOARD_MAX)
|
|
|
|
return 0;
|
|
|
|
return m_wordMultipliers[iRow][iCol];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-09 11:48:19 +01:00
|
|
|
int Board::GetLetterMultiplier(int iRow, int iCol)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
if (iRow < BOARD_MIN || iRow > BOARD_MAX ||
|
|
|
|
iCol < BOARD_MIN || iCol > BOARD_MAX)
|
|
|
|
return 0;
|
|
|
|
return m_tileMultipliers[iRow][iCol];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-04 22:01:27 +02:00
|
|
|
// #define CELL_STRING_FORMAT "[%c:%s:%2d]"
|
2006-11-05 14:30:06 +01:00
|
|
|
#define CELL_STRING_FORMAT "[%s:%2d]"
|
|
|
|
|
|
|
|
string Board::getCellContent_row(int row, int col) const
|
|
|
|
{
|
2008-09-13 23:32:45 +02:00
|
|
|
char buff[1024]; // [ joker, mask, point, tiles ]
|
2006-11-05 14:30:06 +01:00
|
|
|
sprintf(buff,CELL_STRING_FORMAT,
|
|
|
|
// m_jokerRow[row][col] ? 'j':'.',
|
|
|
|
m_crossRow[row][col].getHexContent().c_str(),
|
|
|
|
m_pointRow[row][col]);
|
|
|
|
return string(buff);
|
|
|
|
}
|
|
|
|
|
|
|
|
string Board::getCellContent_col(int row, int col) const
|
|
|
|
{
|
|
|
|
char buff[1024];
|
|
|
|
sprintf(buff,CELL_STRING_FORMAT,
|
|
|
|
// m_jokerCol[col][row] ? 'j':'.',
|
|
|
|
m_crossCol[col][row].getHexContent().c_str(),
|
|
|
|
m_pointCol[col][row]);
|
|
|
|
return string(buff);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-05 12:14:56 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
void Board::checkDouble()
|
|
|
|
{
|
2005-04-02 19:59:07 +02:00
|
|
|
for (int row = BOARD_MIN; row <= BOARD_MAX; row++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
2005-04-02 19:59:07 +02:00
|
|
|
for (int col = BOARD_MIN; col <= BOARD_MAX; col++)
|
2005-02-05 12:14:56 +01:00
|
|
|
{
|
|
|
|
if (m_tilesRow[row][col] != m_tilesCol[col][row])
|
2005-04-02 19:59:07 +02:00
|
|
|
printf("tiles diff %d %d\n", row, col);
|
2005-02-05 12:14:56 +01:00
|
|
|
if (m_jokerRow[row][col] != m_jokerCol[col][row])
|
2005-04-02 19:59:07 +02:00
|
|
|
printf("joker diff %d %d\n", row, col);
|
2009-01-17 15:57:32 +01:00
|
|
|
// The crossckecks and the points have no reason to be the same
|
|
|
|
// in both directions
|
2005-02-05 12:14:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2005-04-16 17:47:59 +02:00
|
|
|
|
2009-01-17 15:57:32 +01:00
|
|
|
|
|
|
|
void Board::search(const Dictionary &iDic,
|
|
|
|
const Rack &iRack,
|
|
|
|
Results &oResults) const
|
|
|
|
{
|
|
|
|
// Create a copy of the rack to avoid modifying the given one
|
|
|
|
Rack copyRack = iRack;
|
|
|
|
|
|
|
|
// Search horizontal words
|
2011-08-27 19:21:26 +02:00
|
|
|
BoardSearch horizSearch(iDic, m_params, m_tilesRow, m_crossRow,
|
2009-01-17 15:57:32 +01:00
|
|
|
m_pointRow, m_jokerRow);
|
|
|
|
horizSearch.search(copyRack, oResults, Coord::HORIZONTAL);
|
|
|
|
|
|
|
|
// Search vertical words
|
2011-08-27 19:21:26 +02:00
|
|
|
BoardSearch vertSearch(iDic, m_params, m_tilesCol, m_crossCol,
|
2009-01-17 15:57:32 +01:00
|
|
|
m_pointCol, m_jokerCol);
|
|
|
|
vertSearch.search(copyRack, oResults, Coord::VERTICAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Board::searchFirst(const Dictionary &iDic,
|
|
|
|
const Rack &iRack,
|
|
|
|
Results &oResults) const
|
|
|
|
{
|
|
|
|
// Create a copy of the rack to avoid modifying the given one
|
|
|
|
Rack copyRack = iRack;
|
|
|
|
|
|
|
|
// Search horizontal words
|
2011-08-27 19:21:26 +02:00
|
|
|
BoardSearch horizSearch(iDic, m_params, m_tilesRow, m_crossRow,
|
2009-01-17 15:57:32 +01:00
|
|
|
m_pointRow, m_jokerRow, true);
|
|
|
|
horizSearch.search(copyRack, oResults, Coord::HORIZONTAL);
|
|
|
|
}
|
|
|
|
|