From 7569a58bb773a4325e6ef53e7e71046a9176300f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Teuli=C3=A8re?= Date: Tue, 23 Jun 2009 12:41:53 +0000 Subject: [PATCH] Each letter (tile) now has a display string, defaulting to its internal char. It is not yet possible to change it. This display string is used in the ncurses and Qt interfaces. Display strings are types "wdstring" instead of plain "wstring" in a few places (not all of them) to help recognize them. --- dic/dic.h | 46 ++++---- dic/dic_search.cpp | 238 +++++++++++++--------------------------- dic/header.cpp | 20 +++- dic/header.h | 5 + dic/tile.cpp | 15 +++ dic/tile.h | 2 + game/bag.cpp | 4 +- game/pldrack.cpp | 4 +- game/rack.cpp | 8 +- game/round.cpp | 8 +- qt/bag_widget.cpp | 8 +- qt/board_widget.cpp | 7 +- qt/dic_tools_widget.cpp | 10 +- test/training_benj.ref | 8 +- test/training_racc.ref | 32 +++--- utils/eliottxt.cpp | 36 ++---- utils/game_io.cpp | 2 +- utils/ncurses.cpp | 42 ++++--- 18 files changed, 224 insertions(+), 271 deletions(-) diff --git a/dic/dic.h b/dic/dic.h index 523f40e..8777927 100644 --- a/dic/dic.h +++ b/dic/dic.h @@ -44,6 +44,17 @@ struct params_7plus1_t; struct params_regexp_t; class DicEdge; +/** + * A wdstring is a display string, i.e. it can contains more chars thani + * the represented string. The difference arises in languages such as Catalan, + * where for example "QU" is made of 2 real characters, but corresponds to a + * single tile. + * + * The wdstring type has no particular interest other than signaling + * a bit more precisely the type of contents of the string. + */ +typedef wstring wdstring; + class Dictionary { public: @@ -182,7 +193,7 @@ public: * @param oWordList: results * @param iMaxResults: maximum number of returned results (0 means no limit) */ - void searchBenj(const wstring &iWord, vector &oWordList, + void searchBenj(const wstring &iWord, vector &oWordList, unsigned int iMaxResults = 0) const; /** @@ -191,27 +202,18 @@ public: * @param oWordList: results * @param iMaxResults: maximum number of returned results (0 means no limit) */ - void searchRacc(const wstring &iWord, vector &oWordList, + void searchRacc(const wstring &iWord, vector &oWordList, unsigned int iMaxResults = 0) const; - /** - * Search for crosswords - * @param iMask: letters - * @param oWordList: results - * @param iMaxResults: maximum number of returned results (0 means no limit) - */ - void searchCross(const wstring &iMask, vector &oWordList, - unsigned int iMaxResults = 0) const; - /** * Search for all feasible word with "rack" plus one letter * @param iRack: letters - * @param oWordlist: results + * @param oWordlist: results (grouped by added character) * @param joker: true if the search must be performed when a joker is in the rack * @param iMaxResults: maximum number of returned results (0 means no limit) */ void search7pl1(const wstring &iRack, - map > &oWordList, + map > &oWordList, bool joker) const; /** @@ -226,7 +228,7 @@ public: * @throw InvalidRegexpException When the regular expression cannot be parsed */ bool searchRegExp(const wstring &iRegexp, - vector &oWordList, + vector &oWordList, unsigned int iMinLength, unsigned int iMaxLength, unsigned int iMaxResults = 0) const; @@ -257,22 +259,18 @@ private: */ const DicEdge * seekEdgePtr(const wchar_t *s, const DicEdge *eptr) const; - /// Helper for searchCross() - void searchCrossRec(struct params_cross_t *params, - vector &oWordList, - const DicEdge *edgeptr, - unsigned int iMaxResults) const; - /// Helper for search7pl1() - void searchWordByLen(struct params_7plus1_t *params, + void searchWordByLen(struct params_7plus1_t ¶ms, int i, const DicEdge *edgeptr) const; /// Helper for searchRegExp() - void searchRegexpRec(struct params_regexp_t *params, + void searchRegexpRec(const struct params_regexp_t ¶ms, int state, const DicEdge *edgeptr, - vector &oWordList, - unsigned int iMaxResults) const; + vector &oWordList, + unsigned int iMaxResults, + const wdstring &iCurrWord = L"", + unsigned int iNbChars = 0) const; }; #endif /* _DIC_H_ */ diff --git a/dic/dic_search.cpp b/dic/dic_search.cpp index 16dd8df..a9cce4d 100644 --- a/dic/dic_search.cpp +++ b/dic/dic_search.cpp @@ -75,14 +75,28 @@ bool Dictionary::searchWord(const wstring &iWord) const struct params_7plus1_t { - wchar_t added_char; - map > *results; + wchar_t added_code; + wdstring added_display; + map > *results; int search_len; wchar_t search_wordtst[DIC_WORD_MAX]; char search_letters[63]; }; -void Dictionary::searchWordByLen(struct params_7plus1_t *params, +wdstring convertToDisplay(const Header &iHeader, const wstring &iWord) +{ + wdstring dispStr; + dispStr.reserve(iWord.size()); + for (unsigned int i = 0; i < iWord.size(); ++i) + { + const wdstring &chr = + iHeader.getDisplayStr(iHeader.getCodeFromChar(iWord[i])); + dispStr += chr; + } + return dispStr; +} + +void Dictionary::searchWordByLen(struct params_7plus1_t ¶ms, int i, const DicEdge *edgeptr) const { /* depth first search in the dictionary */ @@ -92,49 +106,49 @@ void Dictionary::searchWordByLen(struct params_7plus1_t *params, if (edgeptr->chr) { /* is the letter available in search_letters */ - if (params->search_letters[edgeptr->chr]) + if (params.search_letters[edgeptr->chr]) { - params->search_wordtst[i] = getHeader().getCharFromCode(edgeptr->chr); - params->search_letters[edgeptr->chr] --; - if (i == params->search_len) + params.search_wordtst[i] = getHeader().getCharFromCode(edgeptr->chr); + params.search_letters[edgeptr->chr] --; + if (i == params.search_len) { if (edgeptr->term) { // Add the solution - vector &sols = (*params->results)[params->added_char]; - if (sols.empty() || sols.back() != params->search_wordtst) - sols.push_back(params->search_wordtst); + vector &sols = (*params.results)[params.added_display]; + if (sols.empty() || sols.back() != params.search_wordtst) + sols.push_back(convertToDisplay(getHeader(), params.search_wordtst)); } } else { searchWordByLen(params, i + 1, getEdgeAt(edgeptr->ptr)); } - params->search_letters[edgeptr->chr] ++; - params->search_wordtst[i] = L'\0'; + params.search_letters[edgeptr->chr] ++; + params.search_wordtst[i] = L'\0'; } /* the letter is of course available if we have a joker available */ - if (params->search_letters[0]) + if (params.search_letters[0]) { - params->search_wordtst[i] = getHeader().getCharFromCode(edgeptr->chr); - params->search_letters[0] --; - if (i == params->search_len) + params.search_wordtst[i] = getHeader().getCharFromCode(edgeptr->chr); + params.search_letters[0] --; + if (i == params.search_len) { if (edgeptr->term) { // Add the solution - vector &sols = (*params->results)[params->added_char]; - if (sols.empty() || sols.back() != params->search_wordtst) - sols.push_back(params->search_wordtst); + vector &sols = (*params.results)[params.added_display]; + if (sols.empty() || sols.back() != params.search_wordtst) + sols.push_back(convertToDisplay(getHeader(), params.search_wordtst)); } } else { searchWordByLen(params, i + 1, getEdgeAt(edgeptr->ptr)); } - params->search_letters[0] ++; - params->search_wordtst[i] = L'\0'; + params.search_letters[0] ++; + params.search_wordtst[i] = L'\0'; } } } while (! (*edgeptr++).last); @@ -142,7 +156,7 @@ void Dictionary::searchWordByLen(struct params_7plus1_t *params, void Dictionary::search7pl1(const wstring &iRack, - map > &oWordList, + map > &oWordList, bool joker) const { if (iRack == L"" || iRack.size() > DIC_WORD_MAX) @@ -189,10 +203,11 @@ void Dictionary::search7pl1(const wstring &iRack, params.results = &oWordList; /* search for all the words that can be done with the letters */ - params.added_char = L'\0'; + params.added_code = 0; + params.added_display = L""; params.search_len = wordlen - 1; params.search_wordtst[wordlen] = L'\0'; - searchWordByLen(¶ms, 0, root_edge); + searchWordByLen(params, 0, root_edge); /* search for all the words that can be done with the letters +1 */ params.search_len = wordlen; @@ -200,11 +215,12 @@ void Dictionary::search7pl1(const wstring &iRack, const wstring &letters = getHeader().getLetters(); for (unsigned int i = 0; i < letters.size(); i++) { - params.added_char = letters[i]; unsigned int code = getHeader().getCodeFromChar(letters[i]); + params.added_code = code; + params.added_display = getHeader().getDisplayStr(code); params.search_letters[code]++; - searchWordByLen(¶ms, 0, root_edge); + searchWordByLen(params, 0, root_edge); params.search_letters[code]--; } @@ -214,7 +230,7 @@ void Dictionary::search7pl1(const wstring &iRack, /****************************************/ void Dictionary::searchRacc(const wstring &iWord, - vector &oWordList, + vector &oWordList, unsigned int iMaxResults) const { if (iWord == L"") @@ -226,31 +242,28 @@ void Dictionary::searchRacc(const wstring &iWord, else oWordList.reserve(DEFAULT_VECT_ALLOC); + // Transform the given word to make it suitable for display + const wdstring &displayWord = convertToDisplay(getHeader(), iWord); + // Try to add a letter at the front - wchar_t wordtst[DIC_WORD_MAX]; - wcscpy(wordtst + 1, iWord.c_str()); const wstring &letters = getHeader().getLetters(); for (unsigned int i = 0; i <= letters.size(); i++) { - wordtst[0] = letters[i]; - if (searchWord(wordtst)) - oWordList.push_back(wordtst); + if (searchWord(letters[i] + iWord)) + { + const wdstring &chr = + getHeader().getDisplayStr(getHeader().getCodeFromChar(letters[i])); + oWordList.push_back(chr + displayWord); + } if (iMaxResults && oWordList.size() >= iMaxResults) return; } // Try to add a letter at the end - int i; - for (i = 0; iWord[i]; i++) - wordtst[i] = iWord[i]; - - wordtst[i ] = '\0'; - wordtst[i+1] = '\0'; - const DicEdge *edge_seek = seekEdgePtr(iWord.c_str(), getEdgeAt(getRoot())); - /* points to what the next letter can be */ + // Point to what the next letter can be const DicEdge *edge = getEdgeAt(edge_seek->ptr); if (edge != getEdgeAt(0)) @@ -259,8 +272,7 @@ void Dictionary::searchRacc(const wstring &iWord, { if (edge->term) { - wordtst[i] = getHeader().getCharFromCode(edge->chr); - oWordList.push_back(wordtst); + oWordList.push_back(displayWord + getHeader().getDisplayStr(edge->chr)); if (iMaxResults && oWordList.size() >= iMaxResults) return; } @@ -271,7 +283,7 @@ void Dictionary::searchRacc(const wstring &iWord, /****************************************/ /****************************************/ -void Dictionary::searchBenj(const wstring &iWord, vector &oWordList, +void Dictionary::searchBenj(const wstring &iWord, vector &oWordList, unsigned int iMaxResults) const { if (iWord == L"") @@ -283,26 +295,27 @@ void Dictionary::searchBenj(const wstring &iWord, vector &oWordList, else oWordList.reserve(DEFAULT_VECT_ALLOC); - wchar_t wordtst[DIC_WORD_MAX]; - wcscpy(wordtst + 3, iWord.c_str()); + // Transform the given word to make it suitable for display + const wdstring &displayWord = convertToDisplay(getHeader(), iWord); + const DicEdge *edge0, *edge1, *edge2, *edgetst; edge0 = getEdgeAt(getRoot()); edge0 = getEdgeAt(edge0->ptr); do { - wordtst[0] = getHeader().getCharFromCode(edge0->chr); + const wdstring &chr0 = getHeader().getDisplayStr(edge0->chr); edge1 = getEdgeAt(edge0->ptr); do { - wordtst[1] = getHeader().getCharFromCode(edge1->chr); + const wdstring &chr1 = getHeader().getDisplayStr(edge1->chr); edge2 = getEdgeAt(edge1->ptr); do { edgetst = seekEdgePtr(iWord.c_str(), edge2); if (edgetst->term) { - wordtst[2] = getHeader().getCharFromCode(edge2->chr); - oWordList.push_back(wordtst); + const wdstring &chr2 = getHeader().getDisplayStr(edge2->chr); + oWordList.push_back(chr0 + chr1 + chr2 + displayWord); if (iMaxResults && oWordList.size() >= iMaxResults) return; } @@ -314,121 +327,33 @@ void Dictionary::searchBenj(const wstring &iWord, vector &oWordList, /****************************************/ /****************************************/ -struct params_cross_t -{ - int wordlen; - wchar_t mask[DIC_WORD_MAX]; -}; - - -void Dictionary::searchCrossRec(struct params_cross_t *params, - vector &oWordList, - const DicEdge *edgeptr, - unsigned int iMaxResults) const -{ - if (iMaxResults && oWordList.size() >= iMaxResults) - return; - - const DicEdge *current = getEdgeAt(edgeptr->ptr); - - if (params->mask[params->wordlen] == '\0') - { - if (edgeptr->term) - oWordList.push_back(params->mask); - } - else if (current->chr == 0) - { - // Do not go on recursion if we are on the sink - return; - } - else if (params->mask[params->wordlen] == '.') - { - do - { - params->mask[params->wordlen] = getHeader().getCharFromCode(current->chr); - params->wordlen ++; - searchCrossRec(params, oWordList, current, iMaxResults); - params->wordlen --; - params->mask[params->wordlen] = '.'; - } - while (!(*current++).last); - } - else - { - do - { - if (current->chr == getHeader().getCodeFromChar(params->mask[params->wordlen])) - { - params->wordlen ++; - searchCrossRec(params, oWordList, current, iMaxResults); - params->wordlen --; - break; - } - } - while (!(*current++).last); - } -} - - -void Dictionary::searchCross(const wstring &iMask, vector &oWordList, - unsigned int iMaxResults) const -{ - if (iMask == L"") - return; - - // Allocate room for all the results - if (iMaxResults) - oWordList.reserve(iMaxResults); - else - oWordList.reserve(DEFAULT_VECT_ALLOC); - - struct params_cross_t params; - - int i; - for (i = 0; i < DIC_WORD_MAX && iMask[i]; i++) - { - if (iswalpha(iMask[i])) - params.mask[i] = towupper(iMask[i]); - else - params.mask[i] = '.'; - } - params.mask[i] = '\0'; - - params.wordlen = 0; - searchCrossRec(¶ms, oWordList, getEdgeAt(getRoot()), iMaxResults); -} - -/****************************************/ -/****************************************/ - struct params_regexp_t { - int minlength; - int maxlength; + unsigned int minlength; + unsigned int maxlength; Automaton *automaton_field; - wchar_t word[DIC_WORD_MAX]; - int wordlen; }; -void Dictionary::searchRegexpRec(struct params_regexp_t *params, +void Dictionary::searchRegexpRec(const struct params_regexp_t ¶ms, int state, const DicEdge *edgeptr, - vector &oWordList, - unsigned int iMaxResults) const + vector &oWordList, + unsigned int iMaxResults, + const wdstring &iCurrWord, + unsigned int iNbChars) const { if (iMaxResults && oWordList.size() >= iMaxResults) return; int next_state; /* if we have a valid word we store it */ - if (params->automaton_field->accept(state) && edgeptr->term) + if (params.automaton_field->accept(state) && edgeptr->term) { - int l = wcslen(params->word); - if (params->minlength <= l && - params->maxlength >= l) + if (params.minlength <= iNbChars && + params.maxlength >= iNbChars) { - oWordList.push_back(params->word); + oWordList.push_back(iCurrWord); } } /* we now drive the search by exploring the dictionary */ @@ -436,16 +361,12 @@ void Dictionary::searchRegexpRec(struct params_regexp_t *params, do { /* the current letter is current->chr */ - next_state = params->automaton_field->getNextState(state, current->chr); + next_state = params.automaton_field->getNextState(state, current->chr); /* 1: the letter appears in the automaton as is */ if (next_state) { - params->word[params->wordlen] = - getHeader().getCharFromCode(current->chr); - params->wordlen ++; - searchRegexpRec(params, next_state, current, oWordList, iMaxResults); - params->wordlen --; - params->word[params->wordlen] = L'\0'; + searchRegexpRec(params, next_state, current, oWordList, iMaxResults, + iCurrWord + getHeader().getDisplayStr(current->chr), iNbChars + 1); } } while (!(*current++).last); } @@ -453,7 +374,6 @@ void Dictionary::searchRegexpRec(struct params_regexp_t *params, /** * Initialize the lists of letters with pre-defined lists - * 0: all tiles * 1: vowels * 2: consonants @@ -489,7 +409,7 @@ static void initLetterLists(const Dictionary &iDic, bool Dictionary::searchRegExp(const wstring &iRegexp, - vector &oWordList, + vector &oWordList, unsigned int iMinLength, unsigned int iMaxLength, unsigned int iMaxResults) const @@ -542,9 +462,7 @@ bool Dictionary::searchRegExp(const wstring &iRegexp, params.minlength = iMinLength; params.maxlength = iMaxLength; params.automaton_field = a; - memset(params.word, L'\0', sizeof(params.word)); - params.wordlen = 0; - searchRegexpRec(¶ms, a->getInitId(), + searchRegexpRec(params, a->getInitId(), getEdgeAt(getRoot()), oWordList, iMaxResults ? iMaxResults + 1 : 0); delete a; diff --git a/dic/header.cpp b/dic/header.cpp index 3cbf0c7..2865c8d 100644 --- a/dic/header.cpp +++ b/dic/header.cpp @@ -236,9 +236,9 @@ wchar_t Header::getCharFromCode(unsigned int iCode) const // Safety check if (iCode == 0 || iCode > m_letters.size()) { - ostringstream ss; - ss << iCode; - throw DicException("Header::getCharFromCode: no letter for code " + ss.str()); + ostringstream oss; + oss << iCode; + throw DicException("Header::getCharFromCode: no letter for code " + oss.str()); } return m_letters[iCode - 1]; } @@ -259,6 +259,20 @@ unsigned int Header::getCodeFromChar(wchar_t iChar) const } +wstring Header::getDisplayStr(unsigned int iCode) const +{ + // Safety check + if (iCode == 0 || iCode > m_letters.size()) + { + ostringstream oss; + oss << iCode; + throw DicException("Header::getDisplayStr: No code for letter '" + oss.str()); + } + // TODO: return a const wstring & instead of a wstring + return wstring(1, m_letters[iCode - 1]); +} + + void Header::read(istream &iStream) { Dict_header_old aHeader; diff --git a/dic/header.h b/dic/header.h index 7097293..e8d0a7f 100644 --- a/dic/header.h +++ b/dic/header.h @@ -121,6 +121,11 @@ public: */ unsigned int getCodeFromChar(wchar_t iChar) const; + /** + * Return the display stirng corresponding to the given code + */ + wstring getDisplayStr(unsigned int iCode) const; + /** * Print a readable summary of the header on standard output */ diff --git a/dic/tile.cpp b/dic/tile.cpp index 2235bad..fba806a 100644 --- a/dic/tile.cpp +++ b/dic/tile.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "tile.h" #include "header.h" @@ -95,6 +96,20 @@ unsigned int Tile::getPoints() const } +wstring Tile::getDisplayStr() const +{ + if (m_code == 0) + throw DicException("Tile::getDisplayStr: Invalid tile"); + if (m_joker && iswalpha(m_char)) + { + wstring str = m_header->getDisplayStr(m_code); + std::transform(str.begin(), str.end(), str.begin(), towlower); + return str; + } + return m_header->getDisplayStr(m_code); +} + + wchar_t Tile::toChar() const { if (m_joker) diff --git a/dic/tile.h b/dic/tile.h index a4592a6..4e74fb9 100644 --- a/dic/tile.h +++ b/dic/tile.h @@ -24,6 +24,7 @@ #include #include +#include using namespace std; @@ -57,6 +58,7 @@ public: unsigned int getPoints() const; wchar_t toChar() const; unsigned int toCode() const; + wstring getDisplayStr() const; static const Tile &Joker() { return m_TheJoker; } diff --git a/game/bag.cpp b/game/bag.cpp index 015004a..2fe94e9 100644 --- a/game/bag.cpp +++ b/game/bag.cpp @@ -81,7 +81,7 @@ unsigned int Bag::getNbConsonants() const void Bag::takeTile(const Tile &iTile) { ASSERT(in(iTile), - "The bag does not contain the letter " + convertToMb(iTile.toChar())); + "The bag does not contain the letter " + convertToMb(iTile.getDisplayStr())); m_tilesMap[iTile]--; m_ntiles--; @@ -91,7 +91,7 @@ void Bag::takeTile(const Tile &iTile) void Bag::replaceTile(const Tile &iTile) { ASSERT(in(iTile) < iTile.maxNumber(), - "Cannot replace tile: " + convertToMb(iTile.toChar())); + "Cannot replace tile: " + convertToMb(iTile.getDisplayStr())); m_tilesMap[iTile]++; m_ntiles++; diff --git a/game/pldrack.cpp b/game/pldrack.cpp index f0fefa3..e90917e 100644 --- a/game/pldrack.cpp +++ b/game/pldrack.cpp @@ -203,7 +203,7 @@ wstring PlayedRack::toString(display_mode mode) const BOOST_FOREACH(const Tile &tile, m_oldTiles) { - s += tile.toChar(); + s += tile.getDisplayStr(); } if (mode > RACK_SIMPLE && getNbOld() > 0 && getNbNew() > 0) @@ -213,7 +213,7 @@ wstring PlayedRack::toString(display_mode mode) const BOOST_FOREACH(const Tile &tile, m_newTiles) { - s += tile.toChar(); + s += tile.getDisplayStr(); } return s; diff --git a/game/rack.cpp b/game/rack.cpp index 7b1bdb9..b634865 100644 --- a/game/rack.cpp +++ b/game/rack.cpp @@ -34,7 +34,7 @@ Rack::Rack() void Rack::remove(const Tile &t) { ASSERT(in(t), - "The rack does not contain the letter " + convertToMb(t.toChar())); + "The rack does not contain the letter " + convertToMb(t.getDisplayStr())); m_tiles[t.toCode()]--; m_ntiles--; } @@ -67,7 +67,11 @@ wstring Rack::toString() const for (unsigned int i = 1; i < m_tiles.size(); i++) { // Append m_tiles[i] copies of the char - rs.append(m_tiles[i], Dictionary::GetDic().getTileFromCode(i).toChar()); + const wstring &chr = Dictionary::GetDic().getTileFromCode(i).getDisplayStr(); + for (unsigned int j = 0; j < m_tiles[i]; ++j) + { + rs += chr; + } } return rs; } diff --git a/game/round.cpp b/game/round.cpp index 804903c..5b1384d 100644 --- a/game/round.cpp +++ b/game/round.cpp @@ -21,6 +21,7 @@ #include #include +#include // For std::transform #include #include "tile.h" #include "round.h" @@ -137,15 +138,14 @@ void Round::removeRightToRack(Tile __UNUSED__ c, bool __UNUSED__ iJoker) wstring Round::getWord() const { - wchar_t c; wstring s; for (unsigned int i = 0; i < getWordLen(); i++) { - c = getTile(i).toChar(); + wstring chr = getTile(i).getDisplayStr(); if (isJoker(i)) - c = towlower(c); - s += c; + std::transform(chr.begin(), chr.end(), chr.begin(), towlower); + s += chr; } return s; } diff --git a/qt/bag_widget.cpp b/qt/bag_widget.cpp index ac9eab5..d08907e 100644 --- a/qt/bag_widget.cpp +++ b/qt/bag_widget.cpp @@ -79,10 +79,14 @@ void BagWidget::updateModel() unsigned int nb = bag.in(tile); if (nb != 0) { + // Concatenate the display char nb times + wdstring str; + for (unsigned int i = 0; i < nb; ++i) + str += tile.getDisplayStr(); + int rowNum = m_model->rowCount(); m_model->insertRow(rowNum); - m_model->setData(m_model->index(rowNum, 0), - qfw(wstring(nb, tile.toChar()))); + m_model->setData(m_model->index(rowNum, 0), qfw(str)); m_model->setData(m_model->index(rowNum, 1), tile.getPoints()); } } diff --git a/qt/board_widget.cpp b/qt/board_widget.cpp index fc12856..af7027b 100644 --- a/qt/board_widget.cpp +++ b/qt/board_widget.cpp @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *****************************************************************************/ +#include // For std::transform #include #include #include @@ -138,12 +139,14 @@ void BoardWidget::paintEvent(QPaintEvent *) // Draw the letter if (m_game != NULL && !m_game->getBoard().getTile(row, col).isEmpty()) { - wchar_t chr = towupper(m_game->getBoard().getTile(row, col).toChar()); + wstring chr = m_game->getBoard().getTile(row, col).getDisplayStr(); + // Make the display char in upper case + std::transform(chr.begin(), chr.end(), chr.begin(), towupper); if (m_game->getBoard().getCharAttr(row, col) & ATTR_JOKER) painter.setPen(JokerColour); painter.setFont(letterFont); painter.drawText(xPos, yPos + 1, squareSize, squareSize, - Qt::AlignCenter, qfw(wstring(1, chr))); + Qt::AlignCenter, qfw(chr)); painter.setPen(NormalColour); // Draw the points of the tile diff --git a/qt/dic_tools_widget.cpp b/qt/dic_tools_widget.cpp index 03092db..26c32cd 100644 --- a/qt/dic_tools_widget.cpp +++ b/qt/dic_tools_widget.cpp @@ -185,18 +185,18 @@ void DicToolsWidget::refreshPlus1() if (rack->text() != "") { - map > wordList; + map > wordList; m_dic->search7pl1(qtw(rack->text()), wordList, true); int rowNum = 0; - map >::const_iterator it; + map >::const_iterator it; for (it = wordList.begin(); it != wordList.end(); it++) { // Create the header line model->insertRow(rowNum); const QModelIndex &index = model->index(rowNum, 0); - if (it->first) - model->setData(index, qfw(wstring(1, it->first))); + if (it->first != L"") + model->setData(index, qfw(it->first)); else model->setData(index, _q("Anagrams")); treeView->setExpanded(index, true); @@ -300,7 +300,7 @@ void DicToolsWidget::refreshDicInfo() { model->insertRow(rowNum); model->setData(model->index(rowNum, 0), - qfw(wstring(1, it->toChar()))); + qfw(it->getDisplayStr())); model->setData(model->index(rowNum, 1), it->getPoints()); model->setData(model->index(rowNum, 2), it->maxNumber()); model->setData(model->index(rowNum, 3), diff --git a/test/training_benj.ref b/test/training_benj.ref index 63540bd..9b2f621 100644 --- a/test/training_benj.ref +++ b/test/training_benj.ref @@ -4,12 +4,12 @@ commande> e mode entraînement [?] pour l'aide commande> b b maison -PLUmaison +PLUMAISON commande> b b animal commande> b b jures -CONjures -GOUjures -PARjures +CONJURES +GOUJURES +PARJURES commande> q fin du mode entraînement commande> q diff --git a/test/training_racc.ref b/test/training_racc.ref index 87c059a..3df914a 100644 --- a/test/training_racc.ref +++ b/test/training_racc.ref @@ -4,24 +4,24 @@ commande> e mode entraînement [?] pour l'aide commande> b r ave -Bave -Cave -Gave -Have -Lave -Nave -Pave -Rave -aveC -aveN -aveU -aveZ +BAVE +CAVE +GAVE +HAVE +LAVE +NAVE +PAVE +RAVE +AVEC +AVEN +AVEU +AVEZ commande> b r yeux commande> b r ka -Oka -Ska -kaN -kaS +OKA +SKA +KAN +KAS commande> q fin du mode entraînement commande> q diff --git a/utils/eliottxt.cpp b/utils/eliottxt.cpp index 5d48bd7..35a4a12 100644 --- a/utils/eliottxt.cpp +++ b/utils/eliottxt.cpp @@ -485,7 +485,7 @@ void handleRegexp(const Dictionary& iDic, const vector &tokens) printf("search for %s (%d,%d,%d)\n", convertToMb(regexp).c_str(), nres, lmin, lmax); - vector wordList; + vector wordList; try { iDic.searchRegExp(regexp, wordList, lmin, lmax, nres); @@ -496,7 +496,7 @@ void handleRegexp(const Dictionary& iDic, const vector &tokens) return; } - BOOST_FOREACH(const wstring &wstr, wordList) + BOOST_FOREACH(const wdstring &wstr, wordList) { printf("%s\n", convertToMb(wstr).c_str()); } @@ -598,22 +598,22 @@ void loopTraining(PublicGame &iGame) { case L'b': { - vector wordList; + vector wordList; iGame.getDic().searchBenj(word, wordList); - BOOST_FOREACH(const wstring &wstr, wordList) + BOOST_FOREACH(const wdstring &wstr, wordList) cout << convertToMb(wstr) << endl; } break; case L'p': { - map > wordMap; + map > wordMap; iGame.getDic().search7pl1(word, wordMap, false); - map >::const_iterator it; + map >::const_iterator it; for (it = wordMap.begin(); it != wordMap.end(); ++it) { - if (it->first) + if (it->first != L"") cout << "+" << convertToMb(it->first) << endl; - BOOST_FOREACH(const wstring &wstr, it->second) + BOOST_FOREACH(const wdstring &wstr, it->second) { cout << " " << convertToMb(wstr) << endl; } @@ -622,9 +622,9 @@ void loopTraining(PublicGame &iGame) break; case L'r': { - vector wordList; + vector wordList; iGame.getDic().searchRacc(word, wordList); - BOOST_FOREACH(const wstring &wstr, wordList) + BOOST_FOREACH(const wdstring &wstr, wordList) cout << convertToMb(wstr) << endl; } break; @@ -659,22 +659,6 @@ void loopTraining(PublicGame &iGame) iGame.trainingSetRackManual(false, letters); } break; - case L'x': - { - const wstring &cross = checkCrossToken(tokens, 1); - if (cross == L"") - helpTraining(); - else - { - vector wordList; - iGame.getDic().searchCross(cross, wordList); - BOOST_FOREACH(const wstring &wstr, wordList) - { - printf(" %s\n", convertToMb(wstr).c_str()); - } - } - } - break; case L'*': iGame.trainingSetRackRandom(false, PublicGame::kRACK_ALL); break; diff --git a/utils/game_io.cpp b/utils/game_io.cpp index fee150c..609c8dc 100644 --- a/utils/game_io.cpp +++ b/utils/game_io.cpp @@ -187,7 +187,7 @@ void GameIO::printNonPlayed(ostream &out, const PublicGame &iGame) { if (bag.in(tile) > 9) out << " "; - out << setw(2) << convertToMb(tile.toChar()); + out << setw(2) << convertToMb(tile.getDisplayStr()); } out << endl; diff --git a/utils/ncurses.cpp b/utils/ncurses.cpp index eae2bcf..e9f1440 100644 --- a/utils/ncurses.cpp +++ b/utils/ncurses.cpp @@ -244,19 +244,22 @@ void CursesIntf::drawBoard(WINDOW *win, int y, int x) const mvwprintw(win, y + row + 1, x + 3 * col + 1, " "); // Now add the letter - wchar_t c = m_game->getBoard().getChar(row, col); - if (c) + const Tile &t = m_game->getBoard().getTile(row, col); + if (!t.isEmpty()) { - cchar_t cc; - if (iswlower(c)) + const wstring &chr = t.getDisplayStr(); + int offset = 0; + if (chr.size() > 1) + offset = -1; + if (m_game->getBoard().isJoker(row, col)) { - setcchar(&cc, &c, A_BOLD, COLOR_GREEN, NULL); - mvwadd_wch(win, y + row + 1, x + 3 * col + 2, &cc); + wattron(win, A_BOLD | COLOR_PAIR(COLOR_GREEN)); + mvwprintw(win, y + row + 1, x + 3 * col + 2 + offset, convertToMb(chr).c_str()); + wattroff(win, A_BOLD); } else { - setcchar(&cc, &c, 0, 0, NULL); - mvwadd_wch(win, y + row + 1, x + 3 * col + 2, &cc); + mvwprintw(win, y + row + 1, x + 3 * col + 2 + offset, convertToMb(chr).c_str()); } } else @@ -374,7 +377,7 @@ void CursesIntf::drawHistory(Box &ioBox) const int y = ioBox.getTop(); // Heading - string heading = truncString(_(" N | RACK | SOLUTION | REF | PTS | P | BONUS"), + string heading = truncString(_(" N | RACK | SOLUTION | REF | PTS | P | BONUS"), ioBox.getWidth() - 1); mvwprintw(m_win, y, x + 1, "%s", heading.c_str()); mvwhline(m_win, y + 1, x + 1, ACS_HLINE, heading.size()); @@ -392,7 +395,7 @@ void CursesIntf::drawHistory(Box &ioBox) const wstring coord = r.getCoord().toString(); ioBox.printDataLine(i, x, " %2d %s %s %s %3d %1d %c", - i + 1, padAndConvert(t.getPlayedRack().toString(), 8).c_str(), + i + 1, padAndConvert(t.getPlayedRack().toString(), 14, false).c_str(), padAndConvert(r.getWord(), 15, false).c_str(), padAndConvert(coord, 3).c_str(), r.getPoints(), t.getPlayer(), r.getBonus() ? '*' : ' '); @@ -403,7 +406,7 @@ void CursesIntf::drawHistory(Box &ioBox) const wstring invWord = L"<" + m.getBadWord() + L">"; ioBox.printDataLine(i, x, " %2d %s %s %s %3d %1d", - i + 1, padAndConvert(t.getPlayedRack().toString(), 8).c_str(), + i + 1, padAndConvert(t.getPlayedRack().toString(), 14, false).c_str(), padAndConvert(invWord, 15, false).c_str(), padAndConvert(m.getBadCoord(), 3).c_str(), m.getScore(), t.getPlayer()); @@ -419,7 +422,7 @@ void CursesIntf::drawHistory(Box &ioBox) const ioBox.printDataLine(i, x, " %2d %s %s %s %3d %1d", - i + 1, padAndConvert(t.getPlayedRack().toString(), 8).c_str(), + i + 1, padAndConvert(t.getPlayedRack().toString(), 14, false).c_str(), padAndConvert(action, 15, false).c_str(), " - ", m.getScore(), t.getPlayer()); } @@ -427,11 +430,11 @@ void CursesIntf::drawHistory(Box &ioBox) const int nbLines = min(i + 2 - ioBox.getFirstLine(), ioBox.getLastLine() - ioBox.getFirstLine() + 2); mvwvline(m_win, y, x + 4, ACS_VLINE, nbLines); - mvwvline(m_win, y, x + 15, ACS_VLINE, nbLines); - mvwvline(m_win, y, x + 33, ACS_VLINE, nbLines); + mvwvline(m_win, y, x + 21, ACS_VLINE, nbLines); mvwvline(m_win, y, x + 39, ACS_VLINE, nbLines); mvwvline(m_win, y, x + 45, ACS_VLINE, nbLines); - mvwvline(m_win, y, x + 49, ACS_VLINE, nbLines); + mvwvline(m_win, y, x + 51, ACS_VLINE, nbLines); + mvwvline(m_win, y, x + 55, ACS_VLINE, nbLines); } @@ -500,13 +503,16 @@ void CursesIntf::drawBag(Box &ioBox) const int i; for (i = ioBox.getFirstLine(); i < (int)allTiles.size() && i < ioBox.getLastLine(); i++) { + const wstring &chr = allTiles[i].getDisplayStr(); + wstring str; + for (unsigned int j = 0; j < m_game->getBag().in(allTiles[i]); ++j) + str += chr; ioBox.printDataLine(i, ioBox.getLeft() + 1, " %s %2d %2d %s", - padAndConvert(wstring(1, allTiles[i].toChar()), 2).c_str(), + padAndConvert(allTiles[i].getDisplayStr(), 2).c_str(), allTiles[i].getPoints(), allTiles[i].maxNumber(), - convertToMb(wstring(m_game->getBag().in(allTiles[i]), - allTiles[i].toChar())).c_str()); + convertToMb(str).c_str()); } int nbLines = min(i + 2 - ioBox.getFirstLine(),