From 77be2e9219a4ed57a143439c43229c58dfa05208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Teuli=C3=A8re?= Date: Sun, 22 Jan 2006 12:23:52 +0000 Subject: [PATCH] Backport of the 'multibyte' branch on HEAD. --- TODO | 16 +- configure.in | 4 +- dic/.cvsignore | 5 + dic/compdic.c | 8 +- dic/dic_search.c | 208 ++++++++++++++--- dic/dic_search.h | 33 ++- dic/listdic.c | 2 +- dic/regexpmain.c | 2 +- game/Makefile.am | 1 + game/bag.cpp | 4 +- game/board.cpp | 7 +- game/board.h | 4 +- game/board_search.cpp | 43 +++- game/coord.cpp | 46 ++-- game/coord.h | 16 +- game/cross.cpp | 30 +-- game/cross.h | 11 +- game/duplicate.cpp | 2 +- game/duplicate.h | 3 +- game/encoding.cpp | 104 +++++++++ game/encoding.h | 52 +++++ game/freegame.cpp | 7 +- game/freegame.h | 5 +- game/game.cpp | 18 +- game/game.h | 10 +- game/game_io.cpp | 269 +++++++++++----------- game/history.cpp | 19 +- game/history.h | 5 +- game/player.cpp | 18 +- game/player.h | 2 +- game/pldrack.cpp | 30 +-- game/pldrack.h | 15 +- game/rack.cpp | 50 ++++- game/rack.h | 16 +- game/round.cpp | 34 +-- game/round.h | 15 +- game/tile.cpp | 42 ++-- game/tile.h | 23 +- game/training.cpp | 45 ++-- game/training.h | 9 +- game/turn.cpp | 8 +- game/turn.h | 2 +- utils/eliottxt.cpp | 509 ++++++++++++++++++++++-------------------- utils/game_io.cpp | 18 +- utils/ncurses.cpp | 31 +-- wxwin/auxframes.cc | 118 +++++----- wxwin/auxframes.h | 8 +- wxwin/gfxresult.cc | 76 +++---- wxwin/gfxresult.h | 7 +- wxwin/mainframe.cc | 19 +- wxwin/searchpanel.cc | 20 +- 51 files changed, 1246 insertions(+), 803 deletions(-) create mode 100644 game/encoding.cpp create mode 100644 game/encoding.h diff --git a/TODO b/TODO index 98ebf01..79f33f3 100644 --- a/TODO +++ b/TODO @@ -3,15 +3,7 @@ * TODO Current version * ==================== - - The dictionary must use codes for performance reasons, - the board must also be made to use codes instead of tiles. - Using class Tiles during search results in a HUGE - performance penalty. Class cross is a performance killer. - Will return back to using code bitmaps in board for cross - search. Files cross.h and cross.cpp are to be removed or - replaced by a 64 bits code bitmap. - - - Correct game save/load functions : Advanced format + - Correct game save/load functions : Advanced format file saving for freegames and duplicate need a serious rewrite. We need to specifie a file format that can handle all the information contained in a multiplayer game. @@ -19,14 +11,14 @@ - Add "joker" type games in wxwin version of Eliot, Freegame and Duplicate will follow - - full French i18n interface and error messages for wxwin. + - full French i18n interface and error messages for wxwin. * ================== * Next Eliot version * ================== - - new dictionnary format that includes tiles + - new dictionnary format that includes tiles - number - points - printable equivalent @@ -45,6 +37,8 @@ - network support - add timers + - implement the dictionary as a GADDAG: + http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol24/issue2/spe880.pdf %%% Local Variables: diff --git a/configure.in b/configure.in index 55059d5..8c33ed5 100644 --- a/configure.in +++ b/configure.in @@ -86,10 +86,10 @@ dnl Check for wxWidgets AC_ARG_ENABLE([wxwidgets],AC_HELP_STRING([--enable-wxwidgets],[wxWidgets interface support (default disabled)])) if test "${enable_wxwidgets}" = "yes" then - AM_PATH_WXCONFIG(2.6.0, wxWin=1) + AM_PATH_WXCONFIG(2.6.0, [wxWin=1], [wxWin=0], [], [--unicode]) if test "${wxWin}" != 1; then AC_MSG_ERROR([ - wxWidgets must be installed on your system + wxWidgets (unicode build) must be installed on your system but wx-config script couldn't be found. Please check that wx-config is in path, the directory diff --git a/dic/.cvsignore b/dic/.cvsignore index dd8f9c1..b4d3462 100644 --- a/dic/.cvsignore +++ b/dic/.cvsignore @@ -1,5 +1,10 @@ .deps Makefile Makefile.in +scanner.h +er.c +libdic_a-er.c +libdic_a-er.h compdic listdic +regexp diff --git a/dic/compdic.c b/dic/compdic.c index 0a3343b..b5b58b6 100644 --- a/dic/compdic.c +++ b/dic/compdic.c @@ -111,14 +111,14 @@ void print_header_info(Dict_header *header) { printf("============================\n"); - printf("keyword length %d bytes\n",(int)strlen(_COMPIL_KEYWORD_)); - printf("keyword size %d bytes\n",sizeof(_COMPIL_KEYWORD_)); - printf("header size %d bytes\n",sizeof(Dict_header)); + printf("keyword length %lu bytes\n", strlen(_COMPIL_KEYWORD_)); + printf("keyword size %lu bytes\n", sizeof(_COMPIL_KEYWORD_)); + printf("header size %lu bytes\n", sizeof(Dict_header)); printf("\n"); printf("%d words\n",header->nwords); printf("\n"); printf("root : %7d (edge)\n",header->root); - printf("root : %7d (byte)\n",header->root * sizeof(Dawg_edge)); + printf("root : %7lu (byte)\n",header->root * sizeof(Dawg_edge)); printf("\n"); printf("nodes : %d+%d\n",header->nodesused, header->nodessaved); printf("edges : %d+%d\n",header->edgesused, header->edgessaved); diff --git a/dic/dic_search.c b/dic/dic_search.c index 02164cc..7bca569 100644 --- a/dic/dic_search.c +++ b/dic/dic_search.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dic_internals.h" #include "dic.h" @@ -70,18 +71,35 @@ Dic_seek_edgeptr(const Dictionary dic, const char* s, Dawg_edge *eptr) /** - * Dic_search_word : direct application of Dic_seek_edgeptr + * Dic_search_word_inner : direct application of Dic_seek_edgeptr * @param dic : dictionary * @param word : word to lookup * @result 0 not a valid word, 1 ok */ - -int -Dic_search_word(const Dictionary dic, const char* word) +static int Dic_search_word_inner(const Dictionary dic, const char* word) { - Dawg_edge *e; - e = Dic_seek_edgeptr(dic,word,dic->dawg + dic->root); - return e->term; + Dawg_edge *e; + e = Dic_seek_edgeptr(dic, word, dic->dawg + dic->root); + return e->term; +} + + +/** + * Wrapper around Dic_search_word_inner, until we have multibyte support in + * the dictionary + */ +int Dic_search_word(const Dictionary dic, const wchar_t* word) +{ + int res; + char *tmp_word = malloc(wcslen(word) + 1); + sprintf(tmp_word, "%ls", word); + + // Do the actual work + res = Dic_search_word_inner(dic, tmp_word); + + // Release memory + free(tmp_word); + return res; } @@ -159,10 +177,10 @@ Dic_search_word_by_len(struct params_7plus1_t *params, int i, Dawg_edge *edgeptr } while (! (*edgeptr++).last); } -void -Dic_search_7pl1(const Dictionary dic, const char* rack, - char buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX], - int joker) +static void +Dic_search_7pl1_inner(const Dictionary dic, const char* rack, + char buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX], + int joker) { int i,j,wordlen; const char* r = rack; @@ -235,12 +253,41 @@ Dic_search_7pl1(const Dictionary dic, const char* rack, } } + +/** + * Wrapper around Dic_search_7pl1_inner, until we have multibyte support in + * the dictionary + */ +void +Dic_search_7pl1(const Dictionary dic, const wchar_t* rack, + wchar_t buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX], + int joker) +{ + int i, j, k; + char tmp_buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX]; + char *tmp_rack = malloc(wcslen(rack) + 1); + sprintf(tmp_rack, "%ls", rack); + // Do the actual work + Dic_search_7pl1_inner(dic, tmp_rack, tmp_buff, joker); + + for (i = 0; i < DIC_LETTERS; i++) + { + for (j = 0; j < RES_7PL1_MAX; j++) + { + for (k = 0; k < DIC_WORD_MAX; k++) + { + buff[i][j][k] = tmp_buff[i][j][k]; + } + } + } +} + /****************************************/ /****************************************/ -void -Dic_search_Racc(const Dictionary dic, const char* word, - char wordlist[RES_RACC_MAX][DIC_WORD_MAX]) +static void +Dic_search_Racc_inner(const Dictionary dic, const char* word, + char wordlist[RES_RACC_MAX][DIC_WORD_MAX]) { /* search_racc will try to add a letter in front and at the end of a word */ @@ -260,7 +307,7 @@ Dic_search_Racc(const Dictionary dic, const char* word, for(i='a'; i <= 'z'; i++) { wordtst[0] = i; - if (Dic_search_word(dic,wordtst) && wordlistlen < RES_RACC_MAX) + if (Dic_search_word_inner(dic,wordtst) && wordlistlen < RES_RACC_MAX) strcpy(wordlist[wordlistlen++],wordtst); } @@ -288,13 +335,37 @@ Dic_search_Racc(const Dictionary dic, const char* word, } } -/****************************************/ -/****************************************/ - - +/** + * Wrapper around Dic_search_Racc_inner, until we have multibyte support in + * the dictionary + */ void -Dic_search_Benj(const Dictionary dic, const char* word, - char wordlist[RES_BENJ_MAX][DIC_WORD_MAX]) +Dic_search_Racc(const Dictionary dic, const wchar_t* word, + wchar_t wordlist[RES_RACC_MAX][DIC_WORD_MAX]) +{ + int i, j; + char tmp_buff[RES_RACC_MAX][DIC_WORD_MAX]; + char *tmp_word = malloc(wcslen(word) + 1); + sprintf(tmp_word, "%ls", word); + // Do the actual work + Dic_search_Racc_inner(dic, tmp_word, tmp_buff); + + for (i = 0; i < RES_RACC_MAX; i++) + { + for (j = 0; j < DIC_WORD_MAX; j++) + { + wordlist[i][j] = tmp_buff[i][j]; + } + } +} + +/****************************************/ +/****************************************/ + + +static void +Dic_search_Benj_inner(const Dictionary dic, const char* word, + char wordlist[RES_BENJ_MAX][DIC_WORD_MAX]) { int i,wordlistlen; char wordtst[DIC_WORD_MAX]; @@ -326,6 +397,30 @@ Dic_search_Benj(const Dictionary dic, const char* word, } while (!(*edge0++).last); } +/** + * Wrapper around Dic_search_Benj_inner, until we have multibyte support in + * the dictionary + */ +void +Dic_search_Benj(const Dictionary dic, const wchar_t* word, + wchar_t wordlist[RES_BENJ_MAX][DIC_WORD_MAX]) +{ + int i, j; + char tmp_buff[RES_BENJ_MAX][DIC_WORD_MAX]; + char *tmp_word = malloc(wcslen(word) + 1); + sprintf(tmp_word, "%ls", word); + // Do the actual work + Dic_search_Benj_inner(dic, tmp_word, tmp_buff); + + for (i = 0; i < RES_BENJ_MAX; i++) + { + for (j = 0; j < DIC_WORD_MAX; j++) + { + wordlist[i][j] = tmp_buff[i][j]; + } + } +} + /****************************************/ /****************************************/ @@ -341,8 +436,8 @@ struct params_cross_t { void Dic_search_cross_rec(struct params_cross_t *params, - char wordlist[RES_CROS_MAX][DIC_WORD_MAX], - Dawg_edge *edgeptr) + char wordlist[RES_CROS_MAX][DIC_WORD_MAX], + Dawg_edge *edgeptr) { Dawg_edge *current = params->dic->dawg + edgeptr->ptr; @@ -380,10 +475,9 @@ Dic_search_cross_rec(struct params_cross_t *params, } - -void -Dic_search_Cros(const Dictionary dic, const char* mask, - char wordlist[RES_CROS_MAX][DIC_WORD_MAX]) +static void +Dic_search_Cros_inner(const Dictionary dic, const char* mask, + char wordlist[RES_CROS_MAX][DIC_WORD_MAX]) { int i; struct params_cross_t params; @@ -410,6 +504,31 @@ Dic_search_Cros(const Dictionary dic, const char* mask, Dic_search_cross_rec(¶ms, wordlist, dic->dawg + dic->root); } + +/** + * Wrapper around Dic_search_Cros_inner, until we have multibyte support in + * the dictionary + */ +void +Dic_search_Cros(const Dictionary dic, const wchar_t* mask, + wchar_t wordlist[RES_CROS_MAX][DIC_WORD_MAX]) +{ + int i, j; + char tmp_buff[RES_CROS_MAX][DIC_WORD_MAX]; + char *tmp_mask = malloc(wcslen(mask) + 1); + sprintf(tmp_mask, "%ls", mask); + // Do the actual work + Dic_search_Cros_inner(dic, tmp_mask, tmp_buff); + + for (i = 0; i < RES_CROS_MAX; i++) + { + for (j = 0; j < DIC_WORD_MAX; j++) + { + wordlist[i][j] = tmp_buff[i][j]; + } + } +} + /****************************************/ /****************************************/ @@ -466,13 +585,13 @@ Dic_search_regexp_rec(struct params_regexp_t *params, * function prototype for parser generated by bison */ int regexpparse(yyscan_t scanner, NODE** root, - struct search_RegE_list_t *list, - struct regexp_error_report_t *err); + struct search_RegE_list_t *list, + struct regexp_error_report_t *err); void -Dic_search_RegE(const Dictionary dic, const char* re, - char wordlist[RES_REGE_MAX][DIC_WORD_MAX], - struct search_RegE_list_t *list) +Dic_search_RegE_inner(const Dictionary dic, const char* re, + char wordlist[RES_REGE_MAX][DIC_WORD_MAX], + struct search_RegE_list_t *list) { int i,p,n,value; int ptl[REGEXP_MAX+1]; @@ -548,6 +667,31 @@ Dic_search_RegE(const Dictionary dic, const char* re, regexp_delete_tree(root); } +/** + * Wrapper around Dic_search_RegE_inner, until we have multibyte support in + * the dictionary + */ +void +Dic_search_RegE(const Dictionary dic, const wchar_t* re, + wchar_t wordlist[RES_REGE_MAX][DIC_WORD_MAX], + struct search_RegE_list_t *list) +{ + int i, j; + char tmp_buff[RES_REGE_MAX][DIC_WORD_MAX]; + char *tmp_re = malloc(wcslen(re) + 1); + sprintf(tmp_re, "%ls", re); + // Do the actual work + Dic_search_RegE_inner(dic, tmp_re, tmp_buff, list); + + for (i = 0; i < RES_REGE_MAX; i++) + { + for (j = 0; j < DIC_WORD_MAX; j++) + { + wordlist[i][j] = tmp_buff[i][j]; + } + } +} + /****************************************/ /****************************************/ diff --git a/dic/dic_search.h b/dic/dic_search.h index d8be74b..c9b2d52 100644 --- a/dic/dic_search.h +++ b/dic/dic_search.h @@ -62,7 +62,8 @@ extern "C" * @param path : lookup word * @return 1 present, 0 error */ -int Dic_search_word(Dictionary dic, const char* path); +int Dic_search_word(Dictionary dic, + const wchar_t* path); /** * Search for all feasible word with "rack" plus one letter @@ -70,7 +71,10 @@ int Dic_search_word(Dictionary dic, const char* path); * @param rack : letters * @param wordlist : results */ -void Dic_search_7pl1(Dictionary dic, const char* rack, char wordlist[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX], int joker); +void Dic_search_7pl1(Dictionary dic, + const wchar_t* rack, + wchar_t wordlist[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX], + int joker); /** * Search for all feasible word adding a letter in front or at the end @@ -78,7 +82,9 @@ void Dic_search_7pl1(Dictionary dic, const char* rack, char wordlist[DIC_LETTERS * @param word : word * @param wordlist : results */ -void Dic_search_Racc(Dictionary dic, const char* word, char wordlist[RES_RACC_MAX][DIC_WORD_MAX]); +void Dic_search_Racc(Dictionary dic, + const wchar_t* word, + wchar_t wordlist[RES_RACC_MAX][DIC_WORD_MAX]); /** * Search for benjamins @@ -86,7 +92,9 @@ void Dic_search_Racc(Dictionary dic, const char* word, char wordlist[RES_RACC_MA * @param rack : letters * @param wordlist : results */ -void Dic_search_Benj(Dictionary dic, const char* word, char wordlist[RES_BENJ_MAX][DIC_WORD_MAX]); +void Dic_search_Benj(Dictionary dic, + const wchar_t* word, + wchar_t wordlist[RES_BENJ_MAX][DIC_WORD_MAX]); /** * Search for crosswords @@ -94,7 +102,9 @@ void Dic_search_Benj(Dictionary dic, const char* word, char wordlist[RES_BENJ_MA * @param rack : letters * @param wordlist : results */ -void Dic_search_Cros(Dictionary dic, const char* mask, char wordlist[RES_CROS_MAX][DIC_WORD_MAX]); +void Dic_search_Cros(Dictionary dic, + const wchar_t* mask, + wchar_t wordlist[RES_CROS_MAX][DIC_WORD_MAX]); /** * Search for words matching a regular expression @@ -102,7 +112,18 @@ void Dic_search_Cros(Dictionary dic, const char* mask, char wordlist[RES_CROS_MA * @param re : regular expression * @param wordlist : results */ -void Dic_search_RegE(Dictionary dic, const char* re, char wordlist[RES_REGE_MAX][DIC_WORD_MAX], struct search_RegE_list_t *list); +void Dic_search_RegE(Dictionary dic, + const wchar_t* re, + wchar_t wordlist[RES_REGE_MAX][DIC_WORD_MAX], + struct search_RegE_list_t *list); + + /** + * Internal version of Dic_search_RegE, used inside the dictionary. + * Please use Dic_search_RegE instead from outside the dic library. + */ +void Dic_search_RegE_inner(const Dictionary dic, const char* re, + char wordlist[RES_REGE_MAX][DIC_WORD_MAX], + struct search_RegE_list_t *list); #if defined(__cplusplus) } diff --git a/dic/listdic.c b/dic/listdic.c index f467077..625ba7a 100644 --- a/dic/listdic.c +++ b/dic/listdic.c @@ -156,7 +156,7 @@ print_header(char* filename) printf("0x%s nodes saved : %6d %s\n",offset(&header,&header.nodessaved),header.nodessaved,hexl(header.nodessaved)); printf("0x%s edges saved : %6d %s\n",offset(&header,&header.edgessaved),header.edgessaved,hexl(header.edgessaved)); printf("\n"); - printf("sizeof(header) = 0x%s (%d)\n",hexb(sizeof(header)),sizeof(header)); + printf("sizeof(header) = 0x%s (%lu)\n", hexb(sizeof(header)), sizeof(header)); } void diff --git a/dic/regexpmain.c b/dic/regexpmain.c index 5d0340e..b7e1e10 100644 --- a/dic/regexpmain.c +++ b/dic/regexpmain.c @@ -124,7 +124,7 @@ int main(int argc, char* argv[]) /* automaton */ init_letter_lists(&list); - Dic_search_RegE(dic,er,wordlist,&list); + Dic_search_RegE_inner(dic,er,wordlist,&list); fprintf(stdout,"résultat:\n"); for(i=0; i #include "dic.h" #include "tile.h" #include "round.h" @@ -104,15 +105,15 @@ Board::Board(): } -char Board::getChar(int iRow, int iCol) const +wchar_t Board::getChar(int iRow, int iCol) const { - char letter = 0; + wchar_t letter = 0; Tile tile = getTile(iRow, iCol); if (!tile.isEmpty()) { letter = tile.toChar(); if (isJoker(iRow, iCol)) - letter = tolower(letter); + letter = towlower(letter); } return letter; } diff --git a/game/board.h b/game/board.h index 6189806..f8589de 100644 --- a/game/board.h +++ b/game/board.h @@ -79,8 +79,8 @@ public: #define ATTR_JOKER 1 #define ATTR_TEST 2 - char getChar (int iRow, int iCol) const; - int getCharAttr(int iRow, int iCol) const; + wchar_t getChar (int iRow, int iCol) const; + int getCharAttr(int iRow, int iCol) const; Tile getTile(int iRow, int iCol) const; bool isJoker(int iRow, int iCol) const; diff --git a/game/board_search.cpp b/game/board_search.cpp index 50c70f4..8f889fa 100644 --- a/game/board_search.cpp +++ b/game/board_search.cpp @@ -219,6 +219,12 @@ static void BoardSearchAux(const Board &iBoard, { int row, col, lastanchor; Round partialword; + + list rackTiles; + iRack.getTiles(rackTiles); + list::const_iterator it; + bool match; + for (row = 1; row <= BOARD_DIM; row++) { partialword.init(); @@ -233,20 +239,35 @@ static void BoardSearchAux(const Board &iBoard, !iTilesMx[row - 1][col].isEmpty() || !iTilesMx[row + 1][col].isEmpty())) { - if (!iTilesMx[row][col - 1].isEmpty()) + // Optimization compared to the original Appel & Jacobson + // algorithm: skip Leftpart if none of the tiles of the rack + // matches the cross mask for the current anchor + match = false; + for (it = rackTiles.begin(); + !match && it != rackTiles.end(); it++) { - partialword.accessCoord().setCol(lastanchor + 1); - ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx, - iJokerMx, iRack, partialword, iResults, - Dic_root(iDic), row, lastanchor + 1, col); + if (iCrossMx[row][col].check(*it)) + { + match = true; + } } - else + if (match) { - partialword.accessCoord().setCol(col); - LeftPart(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx, - iJokerMx, iRack, partialword, iResults, - Dic_root(iDic), row, col, col - - lastanchor - 1); + if (!iTilesMx[row][col - 1].isEmpty()) + { + partialword.accessCoord().setCol(lastanchor + 1); + ExtendRight(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx, + iJokerMx, iRack, partialword, iResults, + Dic_root(iDic), row, lastanchor + 1, col); + } + else + { + partialword.accessCoord().setCol(col); + LeftPart(iBoard, iDic, iTilesMx, iCrossMx, iPointsMx, + iJokerMx, iRack, partialword, iResults, + Dic_root(iDic), row, col, col - + lastanchor - 1); + } } lastanchor = col; } diff --git a/game/coord.cpp b/game/coord.cpp index 83c4d27..8e2f793 100644 --- a/game/coord.cpp +++ b/game/coord.cpp @@ -25,9 +25,11 @@ */ #include +#include #include "coord.h" #include "board.h" // for BOARD_MIN and BOARD_MAX (TODO: remove this include) #include "debug.h" +#include "encoding.h" Coord::Coord(int iRow, int iCol, Direction iDir) @@ -37,7 +39,7 @@ Coord::Coord(int iRow, int iCol, Direction iDir) m_dir = iDir; } -Coord::Coord(const string &iStr) +Coord::Coord(const wstring &iStr) { setFromString(iStr); } @@ -62,8 +64,13 @@ void Coord::swap() m_row = tmp; } -void Coord::setFromString(const string &iStr) + +void Coord::setFromString(const wstring &iWStr) { + // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + // Temporary implementation: convert the wchar_t* string into a char* one + string iStr = convertToMb(iWStr); + char l[4]; int col; @@ -85,34 +92,35 @@ void Coord::setFromString(const string &iStr) setRow(row); } -string Coord::toString(coord_mode_t mode) const +wstring Coord::toString(coord_mode_t mode) const { ASSERT(isValid(), "Invalid coordinates"); - char res[7]; - char srow[3]; - char scol[3]; + wchar_t res[7]; + wchar_t srow[3]; + wchar_t scol[3]; - sprintf(scol, "%d", m_col); - sprintf(srow, "%c", m_row + 'A' - 1); + _swprintf(scol, 3, L"%d", m_col); + _swprintf(srow, 3, L"%c", m_row + 'A' - 1); switch (mode) { case COORD_MODE_COMPACT: - if (getDir() == HORIZONTAL) - sprintf(res,"%s%s",srow,scol); - else - sprintf(res,"%s%s",scol,srow); - break; + if (getDir() == HORIZONTAL) + _swprintf(res, 7, L"%ls%ls", srow, scol); + else + _swprintf(res, 7, L"%ls%ls", scol, srow); + break; case COORD_MODE_LONG: - if (getDir() == HORIZONTAL) - sprintf(res,"%2s %2s",srow,scol); - else - sprintf(res,"%2s %2s",scol,srow); - break; + if (getDir() == HORIZONTAL) + _swprintf(res, 7, L"%2ls %2ls", srow, scol); + else + _swprintf(res, 7, L"%2ls %2ls", scol, srow); + break; } - return string(res); + + return res; } /// Local Variables: diff --git a/game/coord.h b/game/coord.h index 888328e..32c6fd1 100644 --- a/game/coord.h +++ b/game/coord.h @@ -28,6 +28,7 @@ #define _COORD_H using std::string; +using std::wstring; class Coord { @@ -37,7 +38,7 @@ public: // Construction, destruction Coord(int iRow = -1, int iCol = -1, Direction iDir = HORIZONTAL); - Coord(const string &iStr); + Coord(const wstring &iStr); virtual ~Coord() {} // Accessors @@ -54,13 +55,14 @@ public: // Swap the coordinates (without changing the direction) void swap(); - void setFromString(const string &iStr); - typedef enum { - COORD_MODE_COMPACT, - COORD_MODE_LONG - } coord_mode_t; - string toString(coord_mode_t mode = COORD_MODE_COMPACT) const; + enum coord_mode_t + { + COORD_MODE_COMPACT, + COORD_MODE_LONG + }; + void setFromString(const wstring &iStr); + wstring toString(coord_mode_t mode = COORD_MODE_COMPACT) const; private: Direction m_dir; diff --git a/game/cross.cpp b/game/cross.cpp index 976b482..cebce18 100644 --- a/game/cross.cpp +++ b/game/cross.cpp @@ -22,45 +22,33 @@ Cross::Cross() { - // the default behaviour is to match everything + // The default behaviour is to match everything m_any = true; + m_mask = 0xFFFFFFFF; } void Cross::clear() { - m_tilesSet.clear(); m_any = false; + m_mask = 0; } bool Cross::check(const Tile& iTile) const { - if (m_any || (iTile.isJoker() && !m_tilesSet.empty())) + if (m_any || (iTile.isJoker() && m_mask != 0)) return true; - set::const_iterator it = m_tilesSet.find(iTile); - return it != m_tilesSet.end(); + return m_mask & (1 << iTile.toCode()); } bool Cross::operator==(const Cross &iOther) const { - if (isAny() && iOther.isAny()) - return true; - // Two sets are equal if they have the same size and one of them contains - // the other one - if (m_tilesSet.size() == iOther.m_tilesSet.size()) - { - set::const_iterator it; - for (it = m_tilesSet.begin(); it != m_tilesSet.end(); it++) - { - if (!iOther.check(*it)) - return false; - } - return true; - } - else - return false; + if (isAny() || iOther.isAny()) + return isAny() && iOther.isAny(); + + return m_mask == iOther.m_mask; } /// Local Variables: diff --git a/game/cross.h b/game/cross.h index e104824..18c7485 100644 --- a/game/cross.h +++ b/game/cross.h @@ -20,8 +20,8 @@ #ifndef _CROSS_H_ #define _CROSS_H_ -#include "tile.h" #include +#include "tile.h" using namespace std; @@ -44,15 +44,14 @@ public: bool operator!=(const Cross &iOther) const { return !(*this == iOther); } // Standard set methods (almost) - unsigned int size() const { return m_tilesSet.size(); } - void insert(const Tile& iTile) { m_tilesSet.insert(iTile); } + void insert(const Tile& iTile) { m_mask |= (1 << iTile.toCode()); } void clear(); private: - // Set of the tiles accepted for the cross check - set m_tilesSet; + /// Mask indicating which tiles are accepted for the cross check + unsigned int m_mask; - // When this value is true, any letter matches the cross check + /// When this value is true, any letter matches the cross check bool m_any; }; diff --git a/game/duplicate.cpp b/game/duplicate.cpp index e6d55fe..ac07137 100644 --- a/game/duplicate.cpp +++ b/game/duplicate.cpp @@ -50,7 +50,7 @@ int Duplicate::setRackRandom(int p, bool iCheck, set_rack_mode mode) } -int Duplicate::play(const string &iCoord, const string &iWord) +int Duplicate::play(const wstring &iCoord, const wstring &iWord) { /* Perform all the validity checks, and fill a round */ Round round; diff --git a/game/duplicate.h b/game/duplicate.h index 5b80d44..19fa8b1 100644 --- a/game/duplicate.h +++ b/game/duplicate.h @@ -23,6 +23,7 @@ #include "game.h" using std::string; +using std::wstring; /** @@ -58,7 +59,7 @@ public: *************************/ virtual int start(); virtual int setRackRandom(int, bool, set_rack_mode); - virtual int play(const string &iCoord, const string &iWord); + virtual int play(const wstring &iCoord, const wstring &iWord); virtual int endTurn(); int setPlayer(int); diff --git a/game/encoding.cpp b/game/encoding.cpp new file mode 100644 index 0000000..dc21d17 --- /dev/null +++ b/game/encoding.cpp @@ -0,0 +1,104 @@ +/* Eliot */ +/* Copyright (C) 1999 Antoine Fraboulet */ +/* */ +/* This file is part of Eliot. */ +/* */ +/* Eliot 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. */ +/* */ +/* Eliot 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + * \file encoding.cpp + * \brief Utility functions to ease manipulation of wide-character strings + * \author Olivier Teuliere + * \date 2005 + */ + +#include +#include +#include +#include +#include "encoding.h" + + +int _wtoi(const wchar_t *iWStr) +{ + int res = 0; + while (iswdigit(iWStr[0])) + { + res = 10 * res + (iWStr[0] - '0'); + iWStr++; + } + return res; +} + + +int _swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...) +{ + int res; + va_list argp; + va_start(argp, format); +#ifdef WIN32 + // Mingw32 does not take the maxlen argument + res = vswprintf(wcs, format, argp); +#else + res = vswprintf(wcs, maxlen, format, argp); +#endif + va_end(argp); + return res; +} + + +wstring convertToWc(const string& iStr) +{ + // Get the needed length (we _can't_ use string::size()) + size_t len = mbstowcs(NULL, iStr.c_str(), 0); + if (len == (size_t)-1) + return L""; + + wchar_t *tmp = new wchar_t[len + 1]; + len = mbstowcs(tmp, iStr.c_str(), len + 1); + wstring res = tmp; + delete[] tmp; + + return res; +} + + +string convertToMb(const wstring& iWStr) +{ + // Get the needed length (we _can't_ use wstring::size()) + size_t len = wcstombs(NULL, iWStr.c_str(), 0); + if (len == (size_t)-1) + return ""; + + char *tmp = new char[len + 1]; + len = wcstombs(tmp, iWStr.c_str(), len + 1); + string res = tmp; + delete[] tmp; + + return res; +} + + +string convertToMb(wchar_t iWChar) +{ + char res[MB_CUR_MAX + 1]; + int len = wctomb(res, iWChar); + if (len == -1) + return ""; + res[len] = '\0'; + + return res; +} + diff --git a/game/encoding.h b/game/encoding.h new file mode 100644 index 0000000..3fc0c92 --- /dev/null +++ b/game/encoding.h @@ -0,0 +1,52 @@ +/* Eliot */ +/* Copyright (C) 1999 Antoine Fraboulet */ +/* */ +/* This file is part of Eliot. */ +/* */ +/* Eliot 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. */ +/* */ +/* Eliot 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + * \file encoding.h + * \brief Utility functions to ease manipulation of wide-character strings + * \author Olivier Teuliere + * \date 2005 + */ + +#ifndef _ENCODING_H_ +#define _ENCODING_H_ + +#include + +using std::string; +using std::wstring; + + +/// Equivalent of atoi for wide-caracter strings +int _wtoi(const wchar_t *iWStr); + +/// Equivalent of swprintf, but working also with mingw32 +int _swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); + +/// Convert a multi-byte string into a wide-character string +wstring convertToWc(const string& iStr); + +/// Convert a wide-character string into a multi-byte string +string convertToMb(const wstring& iWStr); + +/// Convert a wide character into a multi-byte string +string convertToMb(wchar_t iWChar); + +#endif + diff --git a/game/freegame.cpp b/game/freegame.cpp index d7503a3..03ee459 100644 --- a/game/freegame.cpp +++ b/game/freegame.cpp @@ -18,6 +18,7 @@ *****************************************************************************/ #include +#include #include "dic.h" #include "tile.h" #include "rack.h" @@ -52,7 +53,7 @@ int FreeGame::setRackRandom(int p, bool iCheck, set_rack_mode mode) } -int FreeGame::play(const string &iCoord, const string &iWord) +int FreeGame::play(const wstring &iCoord, const wstring &iWord) { /* Perform all the validity checks, and fill a round */ Round round; @@ -188,7 +189,7 @@ void FreeGame::end() } -int FreeGame::pass(const string &iToChange, int n) +int FreeGame::pass(const wstring &iToChange, int n) { if (m_finished) return 3; @@ -204,7 +205,7 @@ int FreeGame::pass(const string &iToChange, int n) vector tilesVect; for (unsigned int i = 0; i < iToChange.size(); i++) { - Tile tile(toupper(iToChange[i])); + Tile tile(towupper(iToChange[i])); tilesVect.push_back(tile); } diff --git a/game/freegame.h b/game/freegame.h index dafa58d..8be7581 100644 --- a/game/freegame.h +++ b/game/freegame.h @@ -24,6 +24,7 @@ #include "tile.h" using std::string; +using std::wstring; using std::vector; @@ -49,9 +50,9 @@ public: *************************/ virtual int start(); virtual int setRackRandom(int, bool, set_rack_mode); - virtual int play(const string &iCoord, const string &iWord); + virtual int play(const wstring &iCoord, const wstring &iWord); virtual int endTurn(); - int pass(const string &iToChange, int n); + int pass(const wstring &iToChange, int n); private: // Private constructor and destructor to force using the GameFactory class diff --git a/game/game.cpp b/game/game.cpp index c9b68b5..67cc178 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -30,6 +30,7 @@ #include "game.h" #include "game_factory.h" #include "turn.h" +#include "encoding.h" #include "debug.h" @@ -156,8 +157,8 @@ int Game::back(int n) if (n < 0) { - debug("Game::back negative argument\n"); - n = -n; + debug("Game::back negative argument\n"); + n = -n; } debug("Game::back %d\n",n); for (i = 0; i < n; i++) @@ -167,7 +168,8 @@ int Game::back(int n) prevPlayer(); player = m_players[m_currPlayer]; const Round &lastround = m_history.getPreviousTurn().getRound(); - debug("Game::back last round %s\n",lastround.toString().c_str()); + debug("Game::back last round %s\n", + convertToMb(lastround.toString()).c_str()); /* Remove the word from the board, and put its letters back * into the bag */ m_board.removeRound(*m_dic, lastround); @@ -184,8 +186,8 @@ int Game::back(int n) /* Remove the points of this round */ player->addPoints(- lastround.getPoints()); m_points -= lastround.getPoints(); - /* Remove the turns */ - player->removeLastTurn(); + /* Remove the turns */ + player->removeLastTurn(); m_history.removeLastTurn(); } else @@ -411,7 +413,7 @@ bool Game::rackInBag(const Rack &iRack, const Bag &iBag) const /** * Set the rack of the player p manually. */ -int Game::helperSetRackManual(int p, bool iCheck, const string &iLetters) +int Game::helperSetRackManual(int p, bool iCheck, const wstring &iLetters) { int min, ret; @@ -513,8 +515,8 @@ void Game::nextPlayer() * 10: first word not horizontal * 11: first word not covering the H8 square */ -int Game::checkPlayedWord(const string &iCoord, - const string &iWord, Round &oRound) +int Game::checkPlayedWord(const wstring &iCoord, + const wstring &iWord, Round &oRound) { ASSERT(getNPlayers() != 0, "Expected at least one player"); diff --git a/game/game.h b/game/game.h index 0098d46..eb0119e 100644 --- a/game/game.h +++ b/game/game.h @@ -143,7 +143,7 @@ public: *************************/ static const int RACK_SIZE; enum set_rack_mode {RACK_ALL, RACK_NEW, RACK_MANUAL}; - int setRack(int player, set_rack_mode mode, bool check, const string& str); + int setRack(int player, set_rack_mode mode, bool check, const wstring& str); /** * Methods to access already played words. @@ -166,7 +166,7 @@ public: * Game handling */ virtual int start() = 0; - virtual int play(const string &iCoord, const string &iWord) = 0; + virtual int play(const wstring &iCoord, const wstring &iWord) = 0; virtual int endTurn() = 0; protected: @@ -206,14 +206,14 @@ protected: int helperPlayRound(const Round &iRound); int helperSetRackRandom(int p, bool iCheck, set_rack_mode mode); - int helperSetRackManual(int p, bool iCheck, const string &iLetters); + int helperSetRackManual(int p, bool iCheck, const wstring &iLetters); void prevPlayer(); void nextPlayer(); bool rackInBag(const Rack &iRack, const Bag &iBag) const; void realBag(Bag &iBag) const; - int checkPlayedWord(const string &iCoord, - const string &iWord, Round &oRound); + int checkPlayedWord(const wstring &iCoord, + const wstring &iWord, Round &oRound); /** * load games from File using the first format. diff --git a/game/game_io.cpp b/game/game_io.cpp index 5d260b1..95410e7 100644 --- a/game/game_io.cpp +++ b/game/game_io.cpp @@ -31,6 +31,7 @@ #include "player.h" #include "game.h" #include "game_factory.h" +#include "encoding.h" #include "debug.h" using namespace std; @@ -78,16 +79,16 @@ Game * Game::load(FILE *fin, const Dictionary& iDic) } if ((token = strtok(NULL, delim)) == NULL) - { - debug("Game_io::loading file format 1.4\n"); - return Game::gameLoadFormat_14(fin,iDic); - } + { + debug("Game_io::loading file format 1.4\n"); + return Game::gameLoadFormat_14(fin,iDic); + } if (string(token) == string(IDENT_FORMAT_15)) - { - debug("Game_io::loading file format 1.5\n"); - return Game::gameLoadFormat_15(fin,iDic); - } + { + debug("Game_io::loading file format 1.5\n"); + return Game::gameLoadFormat_15(fin,iDic); + } debug("Game::load unknown format %s\n",token); return NULL; @@ -109,65 +110,66 @@ Game* Game::gameLoadFormat_14(FILE *fin, const Dictionary& iDic) pGame = GameFactory::Instance()->createTraining(iDic); pGame->start(); - + /* rack word ?bonus pts coord */ /* EUOFMIE FUMEE * 26 H 4 */ - + /* read all turns until total */ - while(fgets(buff,sizeof(buff),fin)) + while (fgets(buff, sizeof(buff), fin)) { - token = strtok(buff,delim); + token = strtok(buff, delim); if (token != NULL) { - if (strcmp(token,"total")==0) + if (strcmp(token, "total") == 0) { break; } /* rack */ - strncpy(rack,token,sizeof(rack)); - ((Training*)pGame)->setRack(RACK_MANUAL,false,string(rack)); - debug("%s ",rack); + strncpy(rack, token, sizeof(rack)); + static_cast(pGame)->setRack(RACK_MANUAL, false, + convertToWc(rack)); + debug("%s ", rack); /* word */ - token = strtok(NULL,delim); - if (!token || strcmp(token,"total")==0) + token = strtok(NULL, delim); + if (!token || strcmp(token, "total") == 0) { break; } - strncpy(word,token,sizeof(word)); - debug("\t%s ",word); + strncpy(word, token, sizeof(word)); + debug("\t%s ", word); /* bonus */ - if ((token = strtok(NULL,delim)) == NULL) + if ((token = strtok(NULL, delim)) == NULL) break; /* points */ - if (token[0]=='*') + if (token[0] == '*') { - debug("%s\t",token); - if ((token = strtok(NULL,delim)) == NULL) + debug("%s\t", token); + if ((token = strtok(NULL, delim)) == NULL) break; } /* pos 1 */ - if ((token = strtok(NULL,delim)) == NULL) + if ((token = strtok(NULL, delim)) == NULL) break; - debug("(%s ",token); - strncpy(pos,token,sizeof(pos)); + debug("(%s ", token); + strncpy(pos, token, sizeof(pos)); /* pos 2 */ - if ((token = strtok(NULL,delim)) == NULL) + if ((token = strtok(NULL, delim)) == NULL) break; - debug("%s)",token); - strncat(pos,token,sizeof(pos)); - debug("%s\n",pos); + debug("%s)", token); + strncat(pos, token, sizeof(pos)); + debug("%s\n", pos); - debug(" play %s %s\n",pos, word); - pGame->play(string(pos),string(word)); + debug(" play %s %s\n", pos, word); + pGame->play(convertToWc(pos), convertToWc(word)); } } return pGame; @@ -263,7 +265,7 @@ Game* Game::gameLoadFormat_15(FILE *fin, const Dictionary& iDic) { debug(" add Computer player\n"); pGame->addAIPlayer(); - } + } } else { @@ -312,101 +314,101 @@ Game* Game::gameLoadFormat_15(FILE *fin, const Dictionary& iDic) char bonus = 0; int res = sscanf(buff, " %2d | %8s | %s | %3s | %3d | %1d | %c", &num, rack, word, ref, &pts, &player, &bonus); - + debug(" -- line %s",buff); - + if (res < 6) - { - debug(" Game::load15 invalid line -%s-\n",buff); - continue; - } - + { + debug(" Game::load15 invalid line -%s-\n",buff); + continue; + } + debug(" %2d | %8s | %s | %3s | %3d | %1d | %c \n", num, rack, word, ref, pts, player, bonus); - + // Integrity checks // TODO: add more checks if (pts < 0) - { - debug(" Game::load15 line -%s- points < 0 ?\n",buff); - continue; - } + { + debug(" Game::load15 line -%s- points < 0 ?\n",buff); + continue; + } if (player < 0 || player > pGame->getNPlayers()) - { - debug(" Game::load15 line -%s- too much player (%d>%d)",buff,player,pGame->getNPlayers()); - continue; - } + { + debug(" Game::load15 line -%s- too much player (%d>%d)",buff,player,pGame->getNPlayers()); + continue; + } if (bonus && bonus != '*') - { - debug(" Game::load15 line -%s- wring bonus sign\n",buff); - continue; - } - + { + debug(" Game::load15 line -%s- wring bonus sign\n",buff); + continue; + } + // Build a rack for the correct player PlayedRack pldrack; - if ((res = pldrack.setManual(string(rack))) > 0) + if ((res = pldrack.setManual(convertToWc(rack))) > 0) { debug(" Game::load15 set rack manual returned with error %d\n",res); } - debug(" history rack %s\n",pldrack.toString().c_str()); + debug(" history rack %s\n", convertToMb(pldrack.toString()).c_str()); // Build a round Round round; round.setPoints(pts); if (bonus == '*') round.setBonus(1); - + if (isalpha(ref[0])) + { + // Horizontal word + round.accessCoord().setDir(Coord::HORIZONTAL); + round.accessCoord().setRow(ref[0] - 'A' + 1); + round.accessCoord().setCol(atoi(ref + 1)); + + for (unsigned int i = 0; i < strlen(word); i++) { - // Horizontal word - round.accessCoord().setDir(Coord::HORIZONTAL); - round.accessCoord().setRow(ref[0] - 'A' + 1); - round.accessCoord().setCol(atoi(ref + 1)); - - for (unsigned int i = 0; i < strlen(word); i++) - { - tile = Tile(word[i]); - - if (!pGame->m_board.getTile(round.getCoord().getRow(), round.getCoord().getCol() + i).isEmpty()) - { - round.addRightFromBoard(tile); - } - else - { - round.addRightFromRack(tile, islower(word[i])); - pGame->m_bag.takeTile((islower(word[i])) ? Tile::Joker() : tile); - } - } + tile = Tile(word[i]); + + if (!pGame->m_board.getTile(round.getCoord().getRow(), round.getCoord().getCol() + i).isEmpty()) + { + round.addRightFromBoard(tile); + } + else + { + round.addRightFromRack(tile, islower(word[i])); + pGame->m_bag.takeTile((islower(word[i])) ? Tile::Joker() : tile); + } } + } else + { + // Vertical word + round.accessCoord().setDir(Coord::VERTICAL); + round.accessCoord().setRow(ref[strlen(ref) - 1] - 'A' + 1); + round.accessCoord().setCol(atoi(ref)); + + for (unsigned int i = 0; i < strlen(word); i++) { - // Vertical word - round.accessCoord().setDir(Coord::VERTICAL); - round.accessCoord().setRow(ref[strlen(ref) - 1] - 'A' + 1); - round.accessCoord().setCol(atoi(ref)); - - for (unsigned int i = 0; i < strlen(word); i++) - { - tile = Tile(word[i]); - - if (!pGame->m_board.getTile(round.getCoord().getRow() + i, round.getCoord().getCol()).isEmpty()) - { - round.addRightFromBoard(tile); - } - else - { - round.addRightFromRack(tile, islower(word[i])); - pGame->m_bag.takeTile((islower(word[i])) ? Tile::Joker() : tile); - } - } + tile = Tile(word[i]); + + if (!pGame->m_board.getTile(round.getCoord().getRow() + i, round.getCoord().getCol()).isEmpty()) + { + round.addRightFromBoard(tile); + } + else + { + round.addRightFromRack(tile, islower(word[i])); + pGame->m_bag.takeTile((islower(word[i])) ? Tile::Joker() : tile); + } } - + } + // pGame->m_currPlayer = player; // // Update the rack for the player // pGame->m_players[player]->setCurrentRack(pldrack); // // End the turn for the current player (this creates a new rack) // pGame->m_players[player]->endTurn(round,num - 1); - + // Play the round pGame->helperPlayRound(round); } @@ -425,15 +427,15 @@ Game* Game::gameLoadFormat_15(FILE *fin, const Dictionary& iDic) { // Create the played rack PlayedRack pldrack; - pldrack.setManual(string(letters)); + pldrack.setManual(convertToWc(letters)); // Give the rack to the player pGame->m_players[nb]->setCurrentRack(pldrack); } // Read next line // continue; } - - + + // Finalize the game if (pGame) { @@ -461,13 +463,13 @@ Game* Game::gameLoadFormat_15(FILE *fin, const Dictionary& iDic) void Game::save(ostream &out, game_file_format format) const { if (getMode() == kTRAINING && format == FILE_FORMAT_STANDARD) - { - gameSaveFormat_14(out); - } + { + gameSaveFormat_14(out); + } else - { - gameSaveFormat_15(out); - } + { + gameSaveFormat_15(out); + } } @@ -479,25 +481,25 @@ void Game::gameSaveFormat_14(ostream &out) const out << IDENT_STRING << endl << endl; for(i = 0; i < m_history.getSize(); i++) - { - const Turn& turn = m_history.getTurn(i); - string rack = turn.getPlayedRack().toString(PlayedRack::RACK_EXTRA); - string word = turn.getRound().getWord(); - string coord = turn.getRound().getCoord().toString(Coord::COORD_MODE_LONG); + { + const Turn& turn = m_history.getTurn(i); + string rack = convertToMb(turn.getPlayedRack().toString(PlayedRack::RACK_EXTRA)); + string word = convertToMb(turn.getRound().getWord()); + string coord = convertToMb(turn.getRound().getCoord().toString(Coord::COORD_MODE_LONG)); - // rack [space] word [space] bonus points coord - sprintf(line,"%s%s%s%s%c%4d %s", - rack.c_str(), - string(12 - rack.size(), ' ').c_str(), - word.c_str(), - string(16 - word.size(), ' ').c_str(), - turn.getRound().getBonus() ? '*' : ' ', - turn.getRound().getPoints(), - coord.c_str() - ); + // rack [space] word [space] bonus points coord + sprintf(line,"%s%s%s%s%c%4d %s", + rack.c_str(), + string(12 - rack.size(), ' ').c_str(), + word.c_str(), + string(16 - word.size(), ' ').c_str(), + turn.getRound().getBonus() ? '*' : ' ', + turn.getRound().getPoints(), + coord.c_str() + ); - out << decal << line << endl; - } + out << decal << line << endl; + } out << endl; out << decal << "total" << string(24,' '); @@ -532,18 +534,19 @@ void Game::gameSaveFormat_15(ostream &out) const // Print the game itself for (int i = 0; i < m_history.getSize(); i++) { - const Turn& turn = m_history.getTurn(i); - string word = turn.getRound().getWord(); - string coord = turn.getRound().getCoord().toString(); + const Turn& turn = m_history.getTurn(i); + string rack = convertToMb(turn.getPlayedRack().toString(PlayedRack::RACK_EXTRA)); + string word = convertToMb(turn.getRound().getWord()); + string coord = convertToMb(turn.getRound().getCoord().toString()); sprintf(line, "%2d | %8s | %s%s | %3s | %3d | %1d | %c", i + 1, - turn.getPlayedRack().toString().c_str(), /* pldrack */ - word.c_str(), /* word */ + rack.c_str(), /* pldrack */ + word.c_str(), /* word */ string(15 - word.size(), ' ').c_str(), /* fill spaces */ coord.c_str(), /* coord */ - turn.getRound().getPoints(), + turn.getRound().getPoints(), turn.getPlayer(), - turn.getRound().getBonus() ? '*' : ' '); + turn.getRound().getBonus() ? '*' : ' '); out << decal << line << endl; } @@ -566,8 +569,8 @@ void Game::gameSaveFormat_15(ostream &out) const out << endl; for (int i = 0; i < getNPlayers(); i++) { - string rack = m_players[i]->getCurrentRack().toString(); - out << "Rack " << i << ": " << rack << endl; + wstring rack = m_players[i]->getCurrentRack().toString(); + out << "Rack " << i << ": " << convertToMb(rack) << endl; } } diff --git a/game/history.cpp b/game/history.cpp index fabadb0..1c936d4 100644 --- a/game/history.cpp +++ b/game/history.cpp @@ -29,8 +29,10 @@ #include "pldrack.h" #include "round.h" #include "turn.h" -#include "debug.h" #include "history.h" +#include "encoding.h" +#include "debug.h" + /* ******************************************************** */ /* ******************************************************** */ @@ -154,19 +156,18 @@ void History::removeLastTurn() } -string History::toString() const +wstring History::toString() const { - unsigned int i; - string rs = ""; + wstring rs; #ifdef DEBUG - char buff[20]; - sprintf(buff,"%d",m_history.size()); - rs = "history size = " + string(buff) + "\n\n"; + wchar_t buff[5]; + _swprintf(buff, 4, L"%ld", m_history.size()); + rs = L"history size = " + wstring(buff) + L"\n\n"; #endif - for (i = 0; i < m_history.size(); i++) + for (unsigned int i = 0; i < m_history.size(); i++) { Turn *t = m_history[i]; - rs += t->toString() + string("\n"); + rs += t->toString() + L"\n"; } return rs; } diff --git a/game/history.h b/game/history.h index a28f5d3..9ccc70b 100644 --- a/game/history.h +++ b/game/history.h @@ -30,14 +30,13 @@ #include #include -using std::string; +using std::wstring; using std::vector; class Round; class Turn; class PlayedRack; - /** * History stores all the turns that have been played * This class is used many times in the game @@ -89,7 +88,7 @@ class History void removeLastTurn(); /// String handling - string toString() const; + wstring toString() const; private: vector m_history; diff --git a/game/player.cpp b/game/player.cpp index 4629ddf..436b369 100644 --- a/game/player.cpp +++ b/game/player.cpp @@ -26,6 +26,7 @@ #include "player.h" #include "turn.h" #include "history.h" +#include "encoding.h" #include "debug.h" @@ -76,17 +77,16 @@ void Player::removeLastTurn() m_history.removeLastTurn(); } -const string Player::toString() const +wstring Player::toString() const { - char buff[20]; - string res; + wstring res; - sprintf(buff,"Player %d\n",m_id); - res = string(buff); - res += m_history.toString(); - res += "\n"; - sprintf(buff,"score %d\n",m_score); - res += string(buff); + wchar_t buff[6]; + _swprintf(buff, 5, L"Player %d\n", m_id); + res = wstring(buff); + res += m_history.toString() + L"\n"; + _swprintf(buff, 5, L"score %d\n", m_score); + res += wstring(buff); return res; } diff --git a/game/player.h b/game/player.h index 2e638e4..5579c9b 100644 --- a/game/player.h +++ b/game/player.h @@ -69,7 +69,7 @@ public: // A new rack is created with the remaining letters void endTurn(const Round &iRound, int iTurn); - const string toString() const; + wstring toString() const; private: /// ID of the player diff --git a/game/pldrack.cpp b/game/pldrack.cpp index bee6daa..391482c 100644 --- a/game/pldrack.cpp +++ b/game/pldrack.cpp @@ -147,7 +147,7 @@ void PlayedRack::setNew(const Rack &iRack) } } -int PlayedRack::setManual(const string& iLetters) +int PlayedRack::setManual(const wstring& iLetters) { unsigned int i; reset(); @@ -157,17 +157,17 @@ int PlayedRack::setManual(const string& iLetters) return 0; /* empty is ok */ } - for (i = 0; i < iLetters.size() && iLetters[i] != '+'; i++) + for (i = 0; i < iLetters.size() && iLetters[i] != L'+'; i++) { Tile tile(iLetters[i]); if (tile.isEmpty()) { - return 1; /* */ + return 1; /* */ } addOld(tile); } - if (i < iLetters.size() && iLetters[i] == '+') + if (i < iLetters.size() && iLetters[i] == L'+') { for (i++; i < iLetters.size(); i++) { @@ -210,33 +210,33 @@ void PlayedRack::operator=(const PlayedRack &iOther) } -string PlayedRack::toString(display_mode mode) const +wstring PlayedRack::toString(display_mode mode) const { - string s(""); + wstring s; vector::const_iterator it; - + if (nOld() > 0) { - for (it = m_oldTiles.begin(); it != m_oldTiles.end(); it++) - s += it->toChar(); + for (it = m_oldTiles.begin(); it != m_oldTiles.end(); it++) + s += it->toChar(); } if (mode > RACK_SIMPLE && nOld() > 0 && nNew() > 0) { - s += "+"; + s += L"+"; } if (mode > RACK_EXTRA && reject) { - s += "-"; - // nouveau tirage : rejet - // pas après un scrabble + s += L"-"; + // new rack: reject + // not after a scrabble } if (nNew() > 0) { - for (it = m_newTiles.begin(); it != m_newTiles.end(); it++) - s += it->toChar(); + for (it = m_newTiles.begin(); it != m_newTiles.end(); it++) + s += it->toChar(); } return s; diff --git a/game/pldrack.h b/game/pldrack.h index c8ec15d..26e81ae 100644 --- a/game/pldrack.h +++ b/game/pldrack.h @@ -58,7 +58,7 @@ public: void setOld(const Rack &iRack); void setNew(const Rack &iRack); - int setManual(const string& iLetters); + int setManual(const wstring& iLetters); int nTiles() const { return nNew() + nOld(); } int nNew() const { return m_newTiles.size(); } @@ -74,12 +74,13 @@ public: void operator=(const PlayedRack &iOther); - typedef enum { - RACK_SIMPLE, - RACK_EXTRA, - RACK_DEBUG - } display_mode; - string toString(display_mode iShowExtraSigns = RACK_EXTRA) const; + enum display_mode + { + RACK_SIMPLE, + RACK_EXTRA, + RACK_DEBUG + }; + wstring toString(display_mode iShowExtraSigns = RACK_EXTRA) const; private: bool reject; diff --git a/game/rack.cpp b/game/rack.cpp index 1abdce8..5a88e3f 100644 --- a/game/rack.cpp +++ b/game/rack.cpp @@ -26,35 +26,61 @@ */ #include "rack.h" +#include "encoding.h" +#include "debug.h" +// FIXME: should not be here (duplicated from tile.cpp) +#define TILES_NUMBER 28 +#define MIN_CODE 1 + + +Rack::Rack() + : m_tiles(TILES_NUMBER, 0), m_ntiles(0) +{ +} void Rack::remove(const Tile &t) { - multiset::const_iterator it = m_tiles.find(t); - if (it != m_tiles.end()) - m_tiles.erase(it); + ASSERT(in(t), + "The rack does not contain the letter " + convertToMb(t.toChar())); + m_tiles[t.toCode()]--; + m_ntiles--; +} + + +void Rack::clear() +{ + for (unsigned int i = 0; i < m_tiles.size(); i++) + { + m_tiles[i] = 0; + } + m_ntiles = 0; } void Rack::getTiles(list &oTiles) const { - multiset::const_iterator it; - for (it = m_tiles.begin(); it != m_tiles.end(); it++) + for (unsigned int i = MIN_CODE; i < m_tiles.size(); i++) { - oTiles.push_back(*it); + for (unsigned int j = 0; j < m_tiles[i]; j++) + { + oTiles.push_back(Tile::GetTileFromCode(i)); + } } } -string Rack::toString() +wstring Rack::toString() { - string rs(""); - multiset::const_iterator it; - for (it = m_tiles.begin(); it != m_tiles.end(); it++) + wstring rs; + for (unsigned int i = MIN_CODE; i < m_tiles.size(); i++) { - rs += it->toChar(); + for (unsigned int j = 0; j < m_tiles[i]; j++) + { + rs += Tile::GetTileFromCode(i).toChar(); + } } - return rs; + return rs; } /// Local Variables: diff --git a/game/rack.h b/game/rack.h index 095c77d..7df01d9 100644 --- a/game/rack.h +++ b/game/rack.h @@ -43,22 +43,24 @@ using namespace std; class Rack { public: - Rack() {} + Rack(); virtual ~Rack() {} - int nTiles() const { return m_tiles.size(); } + int nTiles() const { return m_ntiles; } bool isEmpty() const { return nTiles() == 0; } - unsigned int in(const Tile &t) const { return m_tiles.count(t); } - void add(const Tile &t) { m_tiles.insert(t); } + unsigned int in(const Tile &t) const { return m_tiles[t.toCode()]; } + void add(const Tile &t) { m_tiles[t.toCode()]++; m_ntiles++; } void remove(const Tile &t); - void clear() { m_tiles.clear(); } + void clear(); void getTiles(list &oTiles) const; - string toString(); + wstring toString(); private: - multiset m_tiles; + /// Vector indexed by tile codes, containing the number of tiles + vector m_tiles; + int m_ntiles; }; #endif diff --git a/game/round.cpp b/game/round.cpp index a147a7b..d83a8da 100644 --- a/game/round.cpp +++ b/game/round.cpp @@ -19,8 +19,10 @@ *****************************************************************************/ #include +#include #include "tile.h" #include "round.h" +#include "encoding.h" #define FROMBOARD 0x1 @@ -141,34 +143,34 @@ void Round::removeRightToRack(Tile c, bool iJoker) m_tileOrigin.pop_back(); } -string Round::getWord() const +wstring Round::getWord() const { - char c; - string s; + wchar_t c; + wstring s; - for (int i = 0; i < getWordLen(); i++) + for (int i = 0; i < getWordLen(); i++) { - c = getTile(i).toChar(); - if (isJoker(i)) - c = tolower(c); - s += c; + c = getTile(i).toChar(); + if (isJoker(i)) + c = towlower(c); + s += c; } - return s; + return s; } -string Round::toString() const +wstring Round::toString() const { - char buff[5]; - string rs(" "); + wstring rs = L" "; if (getWord().size() > 0) { rs = getWord(); - rs += string(16 - getWord().size(), ' '); - rs += getBonus() ? '*' : ' '; - sprintf(buff,"%4d",getPoints()); + rs += wstring(16 - getWord().size(), ' '); + rs += getBonus() ? L'*' : L' '; + wchar_t buff[5]; + _swprintf(buff, 4, L"%d", getPoints()); rs += buff; - rs += " " + getCoord().toString(); + rs += L" " + getCoord().toString(); } return rs; diff --git a/game/round.h b/game/round.h index 32a2520..3136268 100644 --- a/game/round.h +++ b/game/round.h @@ -70,19 +70,20 @@ public: bool isJoker (int iIndex) const; bool isPlayedFromRack(int iIndex) const; const Tile& getTile (int iIndex) const; - - string getWord() const; - int getWordLen() const; - int getPoints() const { return m_points; } - int getBonus() const { return m_bonus; } + + wstring getWord() const; + int getWordLen() const; + int getPoints() const { return m_points; } + int getBonus() const { return m_bonus; } /************************* * Coordinates *************************/ const Coord& getCoord() const { return m_coord; } Coord& accessCoord() { return m_coord; } - - string toString() const; + + + wstring toString() const; private: vector m_word; diff --git a/game/tile.cpp b/game/tile.cpp index db99ee6..7080321 100644 --- a/game/tile.cpp +++ b/game/tile.cpp @@ -18,7 +18,8 @@ *****************************************************************************/ #include "tile.h" -#include +#include + /************************* * French tiles @@ -66,30 +67,35 @@ const unsigned int Tiles_points[TILES_NUMBER] = /*************************** ***************************/ -list Tile::m_tilesList; const Tile Tile::m_TheJoker(TILE_JOKER); const Tile Tile::m_TheDummy(0); +list Tile::m_tilesList; +vector Tile::m_tilesVect(TILES_NUMBER, Tile::dummy()); +bool Tile::m_vectInitialized(false); -Tile::Tile(char c) +Tile::Tile(wchar_t c) { if (c == TILE_JOKER) { m_joker = true; m_dummy = false; m_char = TILE_JOKER; + m_code = 27; } else if (isalpha(c)) { m_joker = islower(c); m_dummy = false; - m_char = toupper(c); + m_char = towupper(c); + m_code = m_char - 'A' + 1; } else { m_joker = false; m_dummy = true; m_char = 0; + m_code = 0; } } @@ -147,27 +153,37 @@ const list& Tile::getAllTiles() } -char Tile::toChar() const +const Tile& Tile::GetTileFromCode(unsigned int iCode) +{ + if (!m_vectInitialized) + { + // XXX: this should be filled from a "language file" instead + for (char i = TILE_IDX_START; i <= TILE_IDX_END; i++) + Tile::m_tilesVect[i] = Tile(i + 'A' - TILE_IDX_START); + m_tilesVect[TILE_IDX_JOKER] = Tile::Joker(); + m_vectInitialized = true; + } + return Tile::m_tilesVect[iCode]; +} + + +wchar_t Tile::toChar() const { if (m_dummy) return TILE_DUMMY; if (m_joker) { - if (isalpha(m_char)) - return tolower(m_char); + if (iswalpha(m_char)) + return towlower(m_char); else return TILE_JOKER; } return m_char; } -int Tile::toCode() const +unsigned int Tile::toCode() const { - if (m_dummy) - return TILE_IDX_DUMMY; - if (m_joker) - return TILE_IDX_DUMMY; - return (TILE_IDX_START + m_char - TILE_START); + return m_code; } bool Tile::operator <(const Tile &iOther) const diff --git a/game/tile.h b/game/tile.h index b06f916..ec677c3 100644 --- a/game/tile.h +++ b/game/tile.h @@ -21,9 +21,11 @@ #define _TILE_H_ #include +#include using namespace std; + /************************* * A Tile is the internal representation * used within the game library to @@ -39,7 +41,7 @@ public: // - we need to pay attention when inserting character taken // from user input - Tile(char c = 0); + Tile(wchar_t c = 0); virtual ~Tile() {} bool isEmpty() const { return m_dummy; } @@ -48,28 +50,39 @@ public: bool isConsonant() const; unsigned int maxNumber() const; unsigned int getPoints() const; - char toChar() const; - int toCode() const; + wchar_t toChar() const; + unsigned int toCode() const; static const Tile &dummy() { return m_TheDummy; } static const Tile &Joker() { return m_TheJoker; } static const list& getAllTiles(); + static const Tile &GetTileFromCode(unsigned int iCode); bool operator <(const Tile &iOther) const; bool operator ==(const Tile &iOther) const; bool operator !=(const Tile &iOther) const; private: - char m_char; + wchar_t m_char; bool m_joker; bool m_dummy; + /** + * Internal code, used in the dictionary to represent the letter. + * It is mainly used by the Cross class. + */ + int m_code; + // Special tiles are declared static static const Tile m_TheJoker; static const Tile m_TheDummy; - // List of available tiles + /// List of available tiles static list m_tilesList; + /// Vector of tiles indexed by their code, for fast look-up + static vector m_tilesVect; + /// True when m_tilesVect is correctly initialized + static bool m_vectInitialized; }; #endif diff --git a/game/training.cpp b/game/training.cpp index 6a760be..68eb41a 100644 --- a/game/training.cpp +++ b/game/training.cpp @@ -25,6 +25,7 @@ #include "pldrack.h" #include "player.h" #include "training.h" +#include "encoding.h" #include "debug.h" @@ -58,21 +59,21 @@ int Training::setRackRandom(bool iCheck, set_rack_mode mode) return res; } -int Training::setRackManual(bool iCheck, const string &iLetters) +int Training::setRackManual(bool iCheck, const wstring &iLetters) { int res; int p = m_currPlayer; - string::iterator it; - string uLetters; // uppercase letters + wstring::iterator it; + wstring uLetters; // uppercase letters // letters can be lowercase or uppercase as they are // coming from user input. We do not consider a lowercase // letter to be a joker which has been assigned to a letter. m_results.clear(); uLetters = iLetters; - for(it = uLetters.begin(); it != uLetters.end(); it ++) - { - *it = toupper(*it); - } + for (it = uLetters.begin(); it != uLetters.end(); it ++) + { + *it = towupper(*it); + } res = helperSetRackManual(p, iCheck, uLetters); // 0 : ok // 1 : not enough tiles @@ -80,25 +81,25 @@ int Training::setRackManual(bool iCheck, const string &iLetters) return res; } -int Training::setRack(set_rack_mode iMode, bool iCheck, const string &iLetters) +int Training::setRack(set_rack_mode iMode, bool iCheck, const wstring &iLetters) { int res = 0; switch(iMode) - { - case RACK_MANUAL: - res = setRackManual(iCheck, iLetters); - break; - case RACK_ALL: - res = setRackRandom(iCheck, iMode); - break; - case RACK_NEW: - res = setRackRandom(iCheck, iMode); - break; - } + { + case RACK_MANUAL: + res = setRackManual(iCheck, iLetters); + break; + case RACK_ALL: + res = setRackRandom(iCheck, iMode); + break; + case RACK_NEW: + res = setRackRandom(iCheck, iMode); + break; + } return res; } -int Training::play(const string &iCoord, const string &iWord) +int Training::play(const wstring &iCoord, const wstring &iWord) { /* Perform all the validity checks, and fill a round */ Round round; @@ -147,7 +148,7 @@ void Training::search() // Search for the current player Rack r; m_players[m_currPlayer]->getCurrentRack().getRack(r); - debug("Training::search for %s\n",r.toString().c_str()); + debug("Training::search for %s\n", convertToMb(r.toString()).c_str()); m_results.search(*m_dic, m_board, r, m_history.getSize()); } @@ -204,7 +205,7 @@ void Training::removeTestPlay() m_testRound = Round(); } -std::string Training::getTestPlayWord() const +wstring Training::getTestPlayWord() const { return m_testRound.getWord(); } diff --git a/game/training.h b/game/training.h index b2e1a7e..ba477bf 100644 --- a/game/training.h +++ b/game/training.h @@ -27,6 +27,7 @@ #include "results.h" using std::string; +using std::wstring; /** @@ -47,14 +48,14 @@ public: * Game handling *************************/ virtual int start(); - virtual int play(const string &iCoord, const string &iWord); + virtual int play(const wstring &iCoord, const wstring &iWord); virtual int endTurn(); void search(); int playResult(int); int setRackRandom(bool, set_rack_mode); - int setRackManual(bool iCheck, const string &iLetters); - int setRack(set_rack_mode iMode, bool iCheck, const string &iLetters); + int setRackManual(bool iCheck, const wstring &iLetters); + int setRack(set_rack_mode iMode, bool iCheck, const wstring &iLetters); /************************* * Override the default behaviour of these methods, because in training @@ -74,7 +75,7 @@ public: /// Remove the temporary word(s) void removeTestPlay(); /// Get the temporary word - string getTestPlayWord() const; + wstring getTestPlayWord() const; private: // Private constructor and destructor to force using the GameFactory class diff --git a/game/turn.cpp b/game/turn.cpp index 293a60f..c4ba38e 100644 --- a/game/turn.cpp +++ b/game/turn.cpp @@ -54,14 +54,14 @@ void Turn::operator=(const Turn &iOther) } #endif -string Turn::toString(bool iShowExtraSigns) const +wstring Turn::toString(bool iShowExtraSigns) const { - string rs = ""; + wstring rs = L""; if (iShowExtraSigns) { - rs = ""; // TODO + // TODO } - rs = rs + m_pldrack.toString() + " " + m_round.toString(); + rs = rs + m_pldrack.toString() + L" " + m_round.toString(); return rs; } diff --git a/game/turn.h b/game/turn.h index 418ddbd..cb9ed6b 100644 --- a/game/turn.h +++ b/game/turn.h @@ -48,7 +48,7 @@ public: #if 0 void operator=(const Turn &iOther); #endif - string toString(bool iShowExtraSigns = false) const; + wstring toString(bool iShowExtraSigns = false) const; private: int m_num; diff --git a/utils/eliottxt.cpp b/utils/eliottxt.cpp index 4d1e800..3ddde66 100644 --- a/utils/eliottxt.cpp +++ b/utils/eliottxt.cpp @@ -22,7 +22,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -35,16 +37,19 @@ #include "training.h" #include "duplicate.h" #include "freegame.h" +#include "encoding.h" /* A static variable for holding the line. */ static char *line_read = NULL; +/* Wide version of the line */ +static wchar_t *wline_read = NULL; /** * Read a string, and return a pointer to it. * Returns NULL on EOF. */ -char *rl_gets() +wchar_t *rl_gets() { // If the buffer has already been allocated, return the memory to the free // pool @@ -53,6 +58,11 @@ char *rl_gets() free(line_read); line_read = NULL; } + if (wline_read) + { + free(wline_read); + wline_read = NULL; + } // Get a line from the user line_read = readline("commande> "); @@ -61,117 +71,116 @@ char *rl_gets() if (line_read && *line_read) add_history(line_read); - return line_read; + // Convert the line into wide characters + // Get the needed length (we _can't_ use string::size()) + size_t len = mbstowcs(NULL, line_read, 0); + if (len == (size_t)-1) + return NULL; + + wline_read = new wchar_t[len + 1]; + len = mbstowcs(wline_read, line_read, len + 1); + + return wline_read; } -char * -next_token_alpha(char *cmd, const char *delim) +wchar_t * next_token_alpha(wchar_t *cmd, const wchar_t *delim, wchar_t **state) { - int i; - char *token = strtok(cmd, delim); + wchar_t *token = wcstok(cmd, delim, state); if (token == NULL) return NULL; - for (i = 0; token[i] && isalpha(token[i]); i++) + int i; + for (i = 0; token[i] && iswalpha(token[i]); i++) ; - token[i] = '\0'; + token[i] = L'\0'; return token; } -char * -next_token_alphanum(char *cmd, const char *delim) +wchar_t * next_token_alphanum(wchar_t *cmd, const wchar_t *delim, wchar_t **state) { - int i; - char *token = strtok(cmd, delim); + wchar_t *token = wcstok(cmd, delim, state); if (token == NULL) return NULL; - for (i = 0; token[i] && isalnum(token[i]); i++) + int i; + for (i = 0; token[i] && iswalnum(token[i]); i++) ; - token[i] = '\0'; + token[i] = L'\0'; return token; } -char * -next_token_alphaplusjoker(char *cmd, const char *delim) +wchar_t * next_token_alphaplusjoker(wchar_t *cmd, const wchar_t *delim, wchar_t **state) { - int i; - char *token = strtok(cmd, delim); + wchar_t *token = wcstok(cmd, delim, state); if (token == NULL) return NULL; - for (i = 0; token[i] && (isalpha(token[i]) || - token[i] == '?' || - token[i] == '+'); + int i; + for (i = 0; token[i] && (iswalpha(token[i]) || + token[i] == L'?' || + token[i] == L'+'); i++) ; - token[i] = '\0'; + token[i] = L'\0'; return token; } -char * -next_token_digit(char *cmd, const char *delim) +wchar_t * next_token_digit(wchar_t *cmd, const wchar_t *delim, wchar_t **state) { - int i; - char *token = strtok(cmd, delim); + wchar_t *token = wcstok(cmd, delim, state); if (token == NULL) return NULL; - for (i = 0; token[i] && (isdigit(token[i]) || token[i] == '-'); i++) + int i; + for (i = 0; token[i] && (iswdigit(token[i]) || token[i] == L'-'); i++) ; - token[i] = '\0'; + token[i] = L'\0'; return token; } -char * -next_token_cross(char *cmd, const char *delim) +wchar_t * next_token_cross(wchar_t *cmd, const wchar_t *delim, wchar_t **state) { - int i; - char *token = strtok(cmd, delim); + wchar_t *token = wcstok(cmd, delim, state); if (token == NULL) return NULL; + int i; for (i = 0; token[i] && - (isalpha(token[i]) || token[i] == '.'); + (iswalpha(token[i]) || token[i] == L'.'); i++) ; - token[i] = '\0'; + token[i] = L'\0'; return token; } -char * -next_token_filename(char *cmd, const char *delim) +wchar_t * next_token_filename(wchar_t *cmd, const wchar_t *delim, wchar_t **state) { - int i; - char *token = strtok(cmd, delim); + wchar_t *token = wcstok(cmd, delim, state); if (token == NULL) return NULL; - for (i = 0; token[i] && (isalnum(token[i]) || - token[i] == '.' || - token[i] == '_'); i++) + int i; + for (i = 0; token[i] && (iswalnum(token[i]) || + token[i] == L'.' || + token[i] == L'_'); i++) ; - token[i] = '\0'; + token[i] = L'\0'; return token; } -void -eliottxt_get_cross(const Dictionary &iDic, char* cros) +void eliottxt_get_cross(const Dictionary &iDic, wchar_t *cros) { - int i; - // (Dictionary dic, char* regx, char wordlist[RES_REGX_MAX][DIC_WORD_MAX]) - char wordlist[RES_CROS_MAX][DIC_WORD_MAX]; + wchar_t wordlist[RES_CROS_MAX][DIC_WORD_MAX]; Dic_search_Cros(iDic, cros, wordlist); - for (i = 0; i(iGame), @@ -323,18 +328,18 @@ display_data(const Game &iGame, const char *delim) else GameIO::printSearchResults(cout, static_cast(iGame), - atoi(token)); + _wtoi(token)); break; - case 's': + case L's': GameIO::printPoints(cout, iGame); break; - case 'S': + case L'S': GameIO::printAllPoints(cout, iGame); break; - case 't': + case L't': GameIO::printPlayedRack(cout, iGame, iGame.getHistory().getSize()); break; - case 'T': + case L'T': GameIO::printAllRacks(cout, iGame); break; default: @@ -344,12 +349,12 @@ display_data(const Game &iGame, const char *delim) } -void -loop_training(Training &iGame) +void loop_training(Training &iGame) { - char *token; - char *commande = NULL; - char delim[] = " \t"; + wchar_t *token; + wchar_t *state; + wchar_t *commande = NULL; + wchar_t delim[] = L" \t"; int quit = 0; cout << "mode entraînement\n"; @@ -357,37 +362,43 @@ loop_training(Training &iGame) while (quit == 0) { commande = rl_gets(); - token = strtok(commande, delim); + token = wcstok(commande, delim, &state); if (token) { switch (token[0]) { - case '?': + case L'?': help_training(); break; - case 'a': - display_data(iGame, delim); + case L'a': + display_data(iGame, delim, &state); break; - case 'd': - token = next_token_alpha(NULL, delim); + case L'd': + token = next_token_alpha(NULL, delim, &state); if (token == NULL) help_training(); else { if (Dic_search_word(iGame.getDic(), token)) - printf("le mot -%s- existe\n", token); + { + printf("le mot -%s- existe\n", + convertToMb(token).c_str()); + } else - printf("le mot -%s- n'existe pas\n", token); + { + printf("le mot -%s- n'existe pas\n", + convertToMb(token).c_str()); + } } break; - case 'j': - token = next_token_alpha(NULL, delim); + case L'j': + token = next_token_alpha(NULL, delim, &state); if (token == NULL) help_training(); else { int res; - char *coord = next_token_alphanum(NULL, delim); + wchar_t *coord = next_token_alphanum(NULL, delim, &state); if (coord == NULL) { help_training(); @@ -401,13 +412,13 @@ loop_training(Training &iGame) } } break; - case 'n': - token = next_token_digit(NULL, delim); + case L'n': + token = next_token_digit(NULL, delim, &state); if (token == NULL) help_training(); else { - int n = atoi(token); + int n = _wtoi(token); if (n <= 0) iGame.back(n == 0 ? 1 : -n); else @@ -417,45 +428,47 @@ loop_training(Training &iGame) } } break; - case 'r': + case L'r': iGame.search(); break; - case 't': - token = next_token_alphaplusjoker(NULL, delim); + case L't': + token = next_token_alphaplusjoker(NULL, delim, &state); if (token == NULL) help_training(); else if (iGame.setRackManual(0, token)) printf("le sac ne contient pas assez de lettres\n"); break; - case 'x': - token = next_token_cross(NULL, delim); + case L'x': + token = next_token_cross(NULL, delim, &state); if (token == NULL) help_training(); else eliottxt_get_cross(iGame.getDic(), token); break; - case '*': + case L'*': iGame.setRackRandom(false, Game::RACK_ALL); break; - case '+': + case L'+': iGame.setRackRandom(false, Game::RACK_NEW); break; - case 's': - token = next_token_filename(NULL, delim); + case L's': + token = next_token_filename(NULL, delim, &state); if (token != NULL) { - ofstream fout(token); + string filename = convertToMb(token); + ofstream fout(filename.c_str()); if (fout.rdstate() == ios::failbit) { - printf("impossible d'ouvrir %s\n", token); + printf("impossible d'ouvrir %s\n", + filename.c_str()); break; } iGame.save(fout); fout.close(); } break; - case 'q': + case L'q': quit = 1; break; default: @@ -468,12 +481,12 @@ loop_training(Training &iGame) } -void -loop_freegame(FreeGame &iGame) +void loop_freegame(FreeGame &iGame) { - char *token; - char *commande = NULL; - char delim[] = " \t"; + wchar_t *token; + wchar_t *state; + wchar_t *commande = NULL; + wchar_t delim[] = L" \t"; int quit = 0; printf("mode partie libre\n"); @@ -481,37 +494,43 @@ loop_freegame(FreeGame &iGame) while (quit == 0) { commande = rl_gets(); - token = strtok(commande, delim); + token = wcstok(commande, delim, &state); if (token) { switch (token[0]) { - case '?': + case L'?': help_freegame(); break; - case 'a': - display_data(iGame, delim); + case L'a': + display_data(iGame, delim, &state); break; - case 'd': - token = next_token_alpha(NULL, delim); + case L'd': + token = next_token_alpha(NULL, delim, &state); if (token == NULL) help_freegame(); else { if (Dic_search_word(iGame.getDic(), token)) - printf("le mot -%s- existe\n", token); + { + printf("le mot -%s- existe\n", + convertToMb(token).c_str()); + } else - printf("le mot -%s- n'existe pas\n", token); + { + printf("le mot -%s- n'existe pas\n", + convertToMb(token).c_str()); + } } break; - case 'j': - token = next_token_alpha(NULL, delim); + case L'j': + token = next_token_alpha(NULL, delim, &state); if (token == NULL) help_freegame(); else { int res; - char *coord = next_token_alphanum(NULL, delim); + wchar_t *coord = next_token_alphanum(NULL, delim, &state); if (coord == NULL) { help_freegame(); @@ -525,30 +544,32 @@ loop_freegame(FreeGame &iGame) } } break; - case 'p': - token = next_token_alpha(NULL, delim); + case L'p': + token = next_token_alpha(NULL, delim, &state); /* You can pass your turn without changing any letter */ if (token == NULL) - token = ""; + token = L""; if (iGame.pass(token, iGame.currPlayer()) != 0) break; break; - case 's': - token = next_token_filename(NULL, delim); + case L's': + token = next_token_filename(NULL, delim, &state); if (token != NULL) { - ofstream fout(token); + string filename = convertToMb(token); + ofstream fout(filename.c_str()); if (fout.rdstate() == ios::failbit) { - printf("impossible d'ouvrir %s\n", token); + printf("impossible d'ouvrir %s\n", + filename.c_str()); break; } iGame.save(fout); fout.close(); } break; - case 'q': + case L'q': quit = 1; break; default: @@ -561,12 +582,12 @@ loop_freegame(FreeGame &iGame) } -void -loop_duplicate(Duplicate &iGame) +void loop_duplicate(Duplicate &iGame) { - char *token; - char *commande = NULL; - char delim[] = " \t"; + wchar_t *token; + wchar_t *state; + wchar_t *commande = NULL; + wchar_t delim[] = L" \t"; int quit = 0; printf("mode duplicate\n"); @@ -574,37 +595,43 @@ loop_duplicate(Duplicate &iGame) while (quit == 0) { commande = rl_gets(); - token = strtok(commande, delim); + token = wcstok(commande, delim, &state); if (token) { switch (token[0]) { - case '?': + case L'?': help_duplicate(); break; - case 'a': - display_data(iGame, delim); + case L'a': + display_data(iGame, delim, &state); break; - case 'd': - token = next_token_alpha(NULL, delim); + case L'd': + token = next_token_alpha(NULL, delim, &state); if (token == NULL) help_duplicate(); else { if (Dic_search_word(iGame.getDic(), token)) - printf("le mot -%s- existe\n", token); + { + printf("le mot -%s- existe\n", + convertToMb(token).c_str()); + } else - printf("le mot -%s- n'existe pas\n", token); + { + printf("le mot -%s- n'existe pas\n", + convertToMb(token).c_str()); + } } break; - case 'j': - token = next_token_alpha(NULL, delim); + case L'j': + token = next_token_alpha(NULL, delim, &state); if (token == NULL) help_duplicate(); else { int res; - char *coord = next_token_alphanum(NULL, delim); + wchar_t *coord = next_token_alphanum(NULL, delim, &state); if (coord == NULL) { help_duplicate(); @@ -618,34 +645,36 @@ loop_duplicate(Duplicate &iGame) } } break; - case 'n': - token = next_token_digit(NULL, delim); + case L'n': + token = next_token_digit(NULL, delim, &state); if (token == NULL) help_duplicate(); else { - int res = iGame.setPlayer(atoi(token)); + int res = iGame.setPlayer(_wtoi(token)); if (res == 1) fprintf(stderr, "Numéro de joueur invalide\n"); else if (res == 2) fprintf(stderr, "Impossible de choisir un joueur non humain\n"); } break; - case 's': - token = next_token_filename(NULL, delim); + case L's': + token = next_token_filename(NULL, delim, &state); if (token != NULL) { - ofstream fout(token); + string filename = convertToMb(token); + ofstream fout(filename.c_str()); if (fout.rdstate() == ios::failbit) { - printf("impossible d'ouvrir %s\n", token); + printf("impossible d'ouvrir %s\n", + filename.c_str()); break; } iGame.save(fout); fout.close(); } break; - case 'q': + case L'q': quit = 1; break; default: @@ -658,55 +687,54 @@ loop_duplicate(Duplicate &iGame) } -void -eliot_regexp_build_default_llist(struct search_RegE_list_t &llist) +void eliot_regexp_build_default_llist(struct search_RegE_list_t &llist) { - memset (&llist,0,sizeof(llist)); + memset(&llist, 0, sizeof(llist)); llist.minlength = 1; llist.maxlength = 15; - + llist.symbl[0] = RE_ALL_MATCH; llist.symbl[1] = RE_VOWL_MATCH; llist.symbl[2] = RE_CONS_MATCH; llist.symbl[3] = RE_USR1_MATCH; llist.symbl[5] = RE_USR2_MATCH; - + llist.valid[0] = 1; // all letters llist.valid[1] = 1; // vowels llist.valid[2] = 1; // consonants llist.valid[3] = 0; // user defined list 1 llist.valid[4] = 0; // user defined list 2 - - for(int i=0; i < DIC_SEARCH_REGE_LIST; i++) - { - memset(llist.letters[i],0,sizeof(llist.letters[i])); - } - + + for (int i = 0; i < DIC_SEARCH_REGE_LIST; i++) + { + memset(llist.letters[i], 0, sizeof(llist.letters[i])); + } + const list& allTiles = Tile::getAllTiles(); list::const_iterator it; for (it = allTiles.begin(); it != allTiles.end(); it++) + { + if (! it->isJoker() && ! it->isEmpty()) { - if (! it->isJoker() && ! it->isEmpty()) - { - // all tiles - llist.letters[0][it->toCode()] = 1; - // vowels - if (it->isVowel()) - { - llist.letters[1][it->toCode()] = 1; - } - // consonants - if (it->isConsonant()) - { - llist.letters[2][it->toCode()] = 1; - } - } + // all tiles + llist.letters[0][it->toCode()] = 1; + // vowels + if (it->isVowel()) + { + llist.letters[1][it->toCode()] = 1; + } + // consonants + if (it->isConsonant()) + { + llist.letters[2][it->toCode()] = 1; + } } + } } -void -eliot_regexp(const Dictionary iDic) +void eliot_regexp(const Dictionary& iDic, wchar_t *cmd, + const wchar_t *delim, wchar_t **state) { /* printf(" x [] {1} {2} {3} : expressions rationnelles\n"); @@ -718,26 +746,23 @@ eliot_regexp(const Dictionary iDic) #define DIC_RE_MAX (3*DIC_WORD_MAX) // yes, it's 3 - char re[DIC_RE_MAX]; - char buff[RES_REGE_MAX][DIC_WORD_MAX]; struct search_RegE_list_t llist; eliot_regexp_build_default_llist(llist); - char *exp, *cnres, *clmin, *clmax; + wchar_t *exp, *cnres, *clmin, *clmax; + + exp = wcstok(NULL, delim, state); + cnres = wcstok(NULL, delim, state); + clmin = wcstok(NULL, delim, state); + clmax = wcstok(NULL, delim, state); - char delim[] = " \t"; - exp = strtok(NULL,delim); - cnres = strtok(NULL,delim); - clmin = strtok(NULL,delim); - clmax = strtok(NULL,delim); - if (exp == NULL) { return; } - int nres = cnres ? atoi(cnres) : 50; - int lmin = clmin ? atoi(clmin) : 1; - int lmax = clmax ? atoi(clmax) : DIC_WORD_MAX - 1; + int nres = cnres ? _wtoi(cnres) : 50; + int lmin = clmin ? _wtoi(clmin) : 1; + int lmax = clmax ? _wtoi(clmax) : DIC_WORD_MAX - 1; if (lmax <= (DIC_WORD_MAX - 1) && lmin >= 1 && lmin <= lmax) { @@ -746,54 +771,60 @@ eliot_regexp(const Dictionary iDic) } else { - printf("bad length -%s,%s-\n",(const char*)clmin,(const char*)clmax); + printf("bad length -%s,%s-\n", (const char*)clmin, (const char*)clmax); return; } - - strncpy(re,exp,DIC_RE_MAX); - printf("search for %s (%d,%d,%d)\n",re,nres,lmin,lmax); - Dic_search_RegE(iDic,re,buff,&llist); - + wchar_t re[DIC_RE_MAX]; + wcsncpy(re, exp, DIC_RE_MAX); + wchar_t buff[RES_REGE_MAX][DIC_WORD_MAX]; + + printf("search for %s (%d,%d,%d)\n", convertToMb(exp).c_str(), + nres, lmin, lmax); + Dic_search_RegE(iDic, re, buff, &llist); + int nresult = 0; - for(int i=0; i < RES_REGE_MAX && i < nres && buff[i][0]; i++) + for (int i = 0; i < RES_REGE_MAX && i < nres && buff[i][0]; i++) { - printf("%s\n",buff[i]); + printf("%s\n", convertToMb(buff[i]).c_str()); nresult++; } - printf("%d printed results\n",nresult); + printf("%d printed results\n", nresult); } -void -main_loop(const Dictionary &iDic) + +void main_loop(const Dictionary &iDic) { - char *token; - char *commande = NULL; - char delim[] = " \t"; + wchar_t *token; + wchar_t *state; + wchar_t *commande = NULL; + wchar_t delim[] = L" \t"; int quit = 0; printf("[?] pour l'aide\n"); while (quit == 0) { commande = rl_gets(); - token = strtok(commande, delim); + token = wcstok(commande, delim, &state); if (token) { switch (token[0]) { - case '?': + case L'?': help(); break; - case 'c': - token = next_token_filename(NULL, delim); + case L'c': + token = next_token_filename(NULL, delim, &state); if (token == NULL) {} else { + string filename = convertToMb(token); FILE* fin; - if ((fin = fopen(token, "r")) == NULL) + if ((fin = fopen(filename.c_str(), "r")) == NULL) { - printf("impossible d'ouvrir %s\n", token); + printf("impossible d'ouvrir %s\n", + filename.c_str()); break; } Game *game = Game::load(fin, iDic); @@ -813,7 +844,7 @@ main_loop(const Dictionary &iDic) } } break; - case 'e': + case L'e': { // New training game Training *game = GameFactory::Instance()->createTraining(iDic); @@ -822,59 +853,59 @@ main_loop(const Dictionary &iDic) GameFactory::Instance()->releaseGame(*game); break; } - case 'd': + case L'd': { int i; // New duplicate game - token = next_token_digit(NULL, delim); + token = next_token_digit(NULL, delim, &state); if (token == NULL) { help(); break; } Duplicate *game = GameFactory::Instance()->createDuplicate(iDic); - for (i = 0; i < atoi(token); i++) + for (i = 0; i < _wtoi(token); i++) game->addHumanPlayer(); - token = next_token_digit(NULL, delim); + token = next_token_digit(NULL, delim, &state); if (token == NULL) { help(); break; } - for (i = 0; i < atoi(token); i++) + for (i = 0; i < _wtoi(token); i++) game->addAIPlayer(); game->start(); loop_duplicate(*game); GameFactory::Instance()->releaseGame(*game); break; } - case 'l': + case L'l': { int i; // New free game - token = next_token_digit(NULL, delim); + token = next_token_digit(NULL, delim, &state); if (token == NULL) { help(); break; } FreeGame *game = GameFactory::Instance()->createFreeGame(iDic); - for (i = 0; i < atoi(token); i++) + for (i = 0; i < _wtoi(token); i++) game->addHumanPlayer(); - token = next_token_digit(NULL, delim); + token = next_token_digit(NULL, delim, &state); if (token == NULL) { help(); break; } - for (i = 0; i < atoi(token); i++) + for (i = 0; i < _wtoi(token); i++) game->addAIPlayer(); game->start(); loop_freegame(*game); GameFactory::Instance()->releaseGame(*game); break; } - case 'D': + case L'D': { // New duplicate game Duplicate *game = GameFactory::Instance()->createDuplicate(iDic); @@ -885,7 +916,7 @@ main_loop(const Dictionary &iDic) GameFactory::Instance()->releaseGame(*game); break; } - case 'L': + case L'L': { // New free game FreeGame *game = GameFactory::Instance()->createFreeGame(iDic); @@ -896,11 +927,11 @@ main_loop(const Dictionary &iDic) GameFactory::Instance()->releaseGame(*game); break; } - case 'x': - // Regular expression tests - eliot_regexp(iDic); + case L'x': + // Regular expression tests + eliot_regexp(iDic, NULL, delim, &state); break; - case 'q': + case L'q': quit = 1; break; default: @@ -912,11 +943,13 @@ main_loop(const Dictionary &iDic) } -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { char dic_path[100]; + // Let the user choose the locale + setlocale(LC_ALL, ""); + Dictionary dic = NULL; if (argc != 2 && argc != 3) @@ -968,9 +1001,11 @@ main(int argc, char *argv[]) Dic_destroy(dic); - // Free the readline static variable + // Free the readline static variable and its wide equivalent if (line_read) free(line_read); + if (wline_read) + free(wline_read); return 0; } diff --git a/utils/game_io.cpp b/utils/game_io.cpp index 42b2fb4..2e2dfd2 100644 --- a/utils/game_io.cpp +++ b/utils/game_io.cpp @@ -20,11 +20,13 @@ #include #include +#include "stdlib.h" #include "game_io.h" #include "game.h" #include "training.h" #include "player.h" +#include "encoding.h" using namespace std; @@ -124,7 +126,7 @@ void GameIO::printBoardMultipliers2(ostream &out, const Game &iGame) out << " " << (char)(row - BOARD_MIN + 'A') << " "; for (col = BOARD_MIN; col <= BOARD_MAX; col++) { - char l = iGame.getBoard().getChar(row, col); + wchar_t l = iGame.getBoard().getChar(row, col); int wm = iGame.getBoard().getWordMultiplier(row, col); int tm = iGame.getBoard().getLetterMultiplier(row, col); @@ -134,7 +136,7 @@ void GameIO::printBoardMultipliers2(ostream &out, const Game &iGame) out << " " << ((tm == 3) ? '*' : '+'); else out << " -"; - out << (l ? l : '-'); + out << (l ? convertToMb(l) : "-"); } out << endl; } @@ -150,7 +152,7 @@ void GameIO::printNonPlayed(ostream &out, const Game &iGame) { if (iGame.getBag().in(it->toChar()) > 9) out << " "; - out << setw(2) << it->toChar(); + out << setw(2) << convertToMb(it->toChar()); } out << endl; @@ -164,7 +166,7 @@ void GameIO::printNonPlayed(ostream &out, const Game &iGame) void GameIO::printPlayedRack(ostream &out, const Game &iGame, int n) { - out << iGame.getCurrentPlayer().getCurrentRack().toString(PlayedRack::RACK_SIMPLE) << endl; + out << convertToMb(iGame.getCurrentPlayer().getCurrentRack().toString(PlayedRack::RACK_SIMPLE)) << endl; } @@ -173,7 +175,7 @@ void GameIO::printAllRacks(ostream &out, const Game &iGame) for (int j = 0; j < iGame.getNPlayers(); j++) { out << "Joueur " << j << ": "; - out << iGame.getPlayer(j).getCurrentRack().toString(PlayedRack::RACK_SIMPLE) << endl; + out << convertToMb(iGame.getPlayer(j).getCurrentRack().toString(PlayedRack::RACK_SIMPLE)) << endl; } } @@ -182,13 +184,13 @@ static void searchResultLine(ostream &out, const Training &iGame, int num) { const Results &res = iGame.getResults(); Round r = res.get(num); - string word = r.getWord(); + wstring word = r.getWord(); if (word.size() == 0) return; - out << word << string(16 - word.size(), ' ') + out << convertToMb(word) << string(16 - word.size(), ' ') << (r.getBonus() ? '*' : ' ') << setw(4) << r.getPoints() - << ' ' << r.getCoord().toString(); + << ' ' << convertToMb(r.getCoord().toString()); } diff --git a/utils/ncurses.cpp b/utils/ncurses.cpp index fa16fe2..b1545cb 100644 --- a/utils/ncurses.cpp +++ b/utils/ncurses.cpp @@ -38,6 +38,7 @@ #include "player.h" #include "history.h" #include "turn.h" +#include "encoding.h" using namespace std; @@ -199,9 +200,9 @@ void CursesIntf::drawScoresRacks(WINDOW *win, int y, int x) const drawBox(win, y + yOff, x, m_game->getNPlayers() + 2, 25, _(" Racks ")); for (int i = 0; i < m_game->getNPlayers(); i++) { - string rack = m_game->getPlayer(i).getCurrentRack().toString(PlayedRack::RACK_SIMPLE); if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer()) attron(A_BOLD); + string rack = convertToMb(m_game->getPlayer(i).getCurrentRack().toString(PlayedRack::RACK_SIMPLE)); mvwprintw(win, y + yOff + i + 1, x + 2, _("Player %d: %s"), i, rack.c_str()); if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer()) @@ -212,7 +213,7 @@ void CursesIntf::drawScoresRacks(WINDOW *win, int y, int x) const // Display a message when the search is complete if (m_game->getMode() == Game::kTRAINING && - static_cast(m_game)->getHistory().getSize()) + static_cast(m_game)->getResults().size()) { mvwprintw(win, y + 2*yOff - 1, x + 2, _("Search complete")); } @@ -231,7 +232,7 @@ void CursesIntf::drawResults(WINDOW *win, int y, int x) drawBox(win, y, x, h, 25, _(" Search results ")); m_boxY = y + 1; m_boxLines = h - 2; - m_boxLinesData = tr_game->getHistory().getSize(); + m_boxLinesData = tr_game->getResults().size(); int i; const Results& res = tr_game->getResults(); @@ -239,12 +240,12 @@ void CursesIntf::drawResults(WINDOW *win, int y, int x) i < m_boxStart + m_boxLines; i++) { const Round &r = res.get(i); - string coord = r.getCoord().toString(); + wstring coord = r.getCoord().toString(); boxPrint(win, i, x + 1, "%3d %s%s %3s", r.getPoints(), - r.getWord().c_str(), + convertToMb(r.getWord()).c_str(), string(h - 3 - r.getWordLen(), ' ').c_str(), - coord.c_str()); + convertToMb(coord).c_str()); } // Complete the list with empty lines, to avoid trails for (; i < m_boxStart + m_boxLines; i++) @@ -275,12 +276,12 @@ void CursesIntf::drawHistory(WINDOW *win, int y, int x) { const Turn& t = m_game->getHistory().getTurn(i); const Round& r = t.getRound(); - string word = r.getWord(); - string coord = r.getCoord().toString(); + string word = convertToMb(r.getWord()); + string coord = convertToMb(r.getCoord().toString()); boxPrint(win, i + 2, x + 2, "%2d %8s %s%s %3s %3d %1d %c", - i + 1, t.getPlayedRack().toString().c_str(), word.c_str(), - string(15 - word.size(), ' ').c_str(), + i + 1, convertToMb(t.getPlayedRack().toString()).c_str(), + word.c_str(), string(15 - word.size(), ' ').c_str(), coord.c_str(), r.getPoints(), t.getPlayer(), r.getBonus() ? '*' : ' '); } @@ -362,7 +363,7 @@ void CursesIntf::playWord(WINDOW *win, int y, int x) if (readString(win, y + 1, x + xOff, 15, word) && readString(win, y + 2, x + xOff, 3, coord)) { - int res = m_game->play(coord, word); + int res = m_game->play(convertToWc(coord), convertToWc(word)); if (res) { drawStatus(win, LINES - 1, 0, _("Incorrect or misplaced word")); @@ -382,7 +383,7 @@ void CursesIntf::checkWord(WINDOW *win, int y, int x) string word; if (readString(win, y + 2, x + 2, 15, word)) { - int res = Dic_search_word(m_game->getDic(), word.c_str()); + int res = Dic_search_word(m_game->getDic(), convertToWc(word).c_str()); char s[100]; if (res) snprintf(s, 100, _("The word '%s' exists"), word.c_str()); @@ -471,7 +472,7 @@ void CursesIntf::passTurn(WINDOW *win, int y, int x, FreeGame &iGame) string letters; if (readString(win, y + 2, x + 2, 7, letters)) { - int res = iGame.pass(letters, m_game->currPlayer()); + int res = iGame.pass(convertToWc(letters), m_game->currPlayer()); if (res) { drawStatus(win, LINES - 1, 0, _("Cannot pass the turn")); @@ -491,7 +492,7 @@ void CursesIntf::setRack(WINDOW *win, int y, int x, Training &iGame) string letters; if (readString(win, y + 2, x + 2, 7, letters, kJOKER)) { - iGame.setRackManual(false, letters); + iGame.setRackManual(false, convertToWc(letters)); } m_state = DEFAULT; clearRect(win, y, x, 4, 32); @@ -718,7 +719,7 @@ int CursesIntf::handleKey(int iKey) else m_state = RESULTS; m_boxStart = 0; - clear(); + clearRect(m_win, 3, 54, 30, 25); return 1; // Toggle dots display diff --git a/wxwin/auxframes.cc b/wxwin/auxframes.cc index 8fe8227..6792d55 100644 --- a/wxwin/auxframes.cc +++ b/wxwin/auxframes.cc @@ -41,6 +41,7 @@ #include "training.h" #include "player.h" #include "game.h" +#include "encoding.h" #include "configdb.h" #include "auxframes.h" @@ -258,7 +259,7 @@ VerifFrame::verif() result->SetLabel(wxT("pas de dictionnaire")); return; } - if (Dic_search_word(dic, word->GetValue().mb_str())) + if (Dic_search_word(dic, word->GetValue().wc_str())) result->SetLabel(wxT("existe")); else result->SetLabel(wxT("n'existe pas")); @@ -294,7 +295,7 @@ AuxFrameList::AuxFrameList(wxFrame* parent, int _id, wxString _name, wxString _c { game = g; - savedword = ""; + savedword = L""; wxBoxSizer *sizer_v = new wxBoxSizer(wxVERTICAL); listbox = new wxListBox(this, ListBoxID); @@ -380,20 +381,19 @@ AuxFrameList::Refresh(refresh_t force) void Plus1Frame::refresh() { - std::string rack; //debug(" Plus1Frame::refresh start\n"); - rack = game->getCurrentPlayer().getCurrentRack().toString(); + std::wstring rack = game->getCurrentPlayer().getCurrentRack().toString(); //debug(" CurrentPlayer -> rack : %s\n",rack.c_str()); if (savedword == rack) - { - noresult = false; // keep old results - //debug(" Plus1Frame::refresh end, no change\n"); - return; - } + { + noresult = false; // keep old results + //debug(" Plus1Frame::refresh end, no change\n"); + return; + } savedword = rack; - char buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX]; + wchar_t buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX]; Dic_search_7pl1(game->getDic(), rack.c_str(), buff, config.getJokerPlus1()); listbox->Clear(); @@ -403,15 +403,15 @@ Plus1Frame::refresh() for (int i = 0; i < DIC_LETTERS; i++) { if (i && buff[i][0][0]) - { - res[resnum++] = wxString(wxT("+")) + (wxChar)(i + 'A' - 1); - noresult = false; - } - for (int j = 0; j < RES_7PL1_MAX && buff[i][j][0]; j++) - { - res[resnum++] = wxString(wxT(" ")) + wxU(buff[i][j]); - noresult = false; - } + { + res[resnum++] = wxString(wxT("+")) + (wxChar)(i + 'A' - 1); + noresult = false; + } + for (int j = 0; j < RES_7PL1_MAX && buff[i][j][0]; j++) + { + res[resnum++] = wxString(wxT(" ")) + wxU(buff[i][j]); + noresult = false; + } } listbox->Set(resnum, res); //debug(" Plus1Frame::refresh end\n"); @@ -424,30 +424,28 @@ Plus1Frame::refresh() void BenjFrame::refresh() { - std::string word; - if (game->getMode() != Game::kTRAINING) - return; + return; - word = ((Training*)game)->getTestPlayWord(); + std::wstring word = static_cast(game)->getTestPlayWord(); if (savedword == word) - { - noresult = false; // keep old results - return; - } + { + noresult = false; // keep old results + return; + } savedword = word; //debug(" BenjFrame::refresh : %s\n",word.c_str()); - char wordlist[RES_BENJ_MAX][DIC_WORD_MAX]; + wchar_t wordlist[RES_BENJ_MAX][DIC_WORD_MAX]; Dic_search_Benj(game->getDic(), word.c_str(), wordlist); wxString res[RES_BENJ_MAX]; int resnum = 0; for (int i = 0; (i < RES_BENJ_MAX) && (wordlist[i][0]); i++) - { - res[resnum++] = wxU(wordlist[i]); - //debug(" BenjFrame : %s (%d)\n",wordlist[i],resnum); - noresult = false; - } + { + res[resnum++] = wxU(wordlist[i]); + //debug(" BenjFrame : %s (%d)\n",wordlist[i],resnum); + noresult = false; + } listbox->Set(resnum, res); } @@ -459,30 +457,28 @@ BenjFrame::refresh() void RaccFrame::refresh() { - std::string word; - if (game->getMode() != Game::kTRAINING) - return; + return; - word = ((Training*)game)->getTestPlayWord(); + std::wstring word = static_cast(game)->getTestPlayWord(); if (savedword == word) - { - noresult = false; // keep old results - return; - } + { + noresult = false; // keep old results + return; + } savedword = word; //debug(" RaccFrame::refresh : %s\n",word.c_str()); - char wordlist[RES_RACC_MAX][DIC_WORD_MAX]; + wchar_t wordlist[RES_RACC_MAX][DIC_WORD_MAX]; Dic_search_Racc(game->getDic(), word.c_str(), wordlist); wxString res[RES_RACC_MAX]; int resnum = 0; for (int i = 0; (i < RES_RACC_MAX) && (wordlist[i][0]); i++) - { - res[resnum++] = wxU(wordlist[i]); - //debug(" RaccFrame : %s (%d)\n",wordlist[i],resnum); - noresult = false; - } + { + res[resnum++] = wxU(wordlist[i]); + //debug(" RaccFrame : %s (%d)\n",wordlist[i],resnum); + noresult = false; + } listbox->Set(resnum, res); } @@ -532,10 +528,10 @@ GameFrame::Refresh(refresh_t force) #ifdef DEBUG mos << std::string(30,'-') << std::endl; mos << "Player History\n"; - mos << m_game.getPlayer(0).toString(); + mos << convertToMb(m_game.getPlayer(0).toString()); mos << std::string(30,'-') << std::endl; mos << "Game History\n"; - mos << m_game.getHistory().toString(); + mos << convertToMb(m_game.getHistory().toString()); #endif textbox->Clear(); textbox->AppendText( wxU( mos.str().c_str() ) ); @@ -570,30 +566,30 @@ void ResultFrame::Refresh(refresh_t WXUNUSED(force)) { if (reslist != NULL) - { - reslist->Show(false); - //debug("ResultFrame refresh\n"); - reslist->Refresh(); - reslist->Show(true); - } + { + reslist->Show(false); + //debug("ResultFrame refresh\n"); + reslist->Refresh(); + reslist->Show(true); + } } void ResultFrame::Search() { if (reslist != NULL) - { - reslist->Search(); - } + { + reslist->Search(); + } } int ResultFrame::GetSelected() { if (reslist != NULL) - { - return reslist->GetSelected(); - } + { + return reslist->GetSelected(); + } return -1; } diff --git a/wxwin/auxframes.h b/wxwin/auxframes.h index b371595..09a01cf 100644 --- a/wxwin/auxframes.h +++ b/wxwin/auxframes.h @@ -78,12 +78,12 @@ protected: ConfigDB config; public: - AuxFrame (wxFrame*, int, wxString, wxString); + AuxFrame(wxFrame*, int, wxString, wxString); ~AuxFrame(); typedef enum { - REFRESH, - FORCE_REFRESH + REFRESH, + FORCE_REFRESH } refresh_t; void SwitchDisplay(); @@ -99,7 +99,7 @@ class AuxFrameList: public AuxFrame { protected: bool noresult; - string savedword; + wstring savedword; Game *game; wxButton *button; wxListBox *listbox; diff --git a/wxwin/gfxresult.cc b/wxwin/gfxresult.cc index 77c1dee..d98bba9 100644 --- a/wxwin/gfxresult.cc +++ b/wxwin/gfxresult.cc @@ -57,7 +57,7 @@ GfxResult::GfxResult(wxFrame *parent, MainFrame* _mf, Game* _game) : { mf = _mf; game = _game; - savedrack = std::string(""); + savedrack = L""; results = new wxListCtrl(this, ListCtrl_ID); #if defined(ENABLE_LC_NO_HEADER) results->SetSingleStyle(wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); @@ -99,7 +99,7 @@ void GfxResult::SetGame(Game* g) { game = g; - savedrack = std::string(""); + savedrack = L""; results->DeleteAllItems(); } @@ -110,21 +110,21 @@ void GfxResult::Refresh() { if (game == NULL) - return; + return; debug(" GfxResult::Refresh : "); - std::string rack = game->getCurrentPlayer().getCurrentRack().toString(); + std::wstring rack = game->getCurrentPlayer().getCurrentRack().toString(); if (savedrack != rack) - { - debug("changed (%s -> %s)",savedrack.c_str(),rack.c_str()); - savedrack = rack; - results->DeleteAllItems(); - } + { + debug("changed (%ls -> %ls)",savedrack.c_str(),rack.c_str()); + savedrack = rack; + results->DeleteAllItems(); + } else - { - debug("unchanged"); - } + { + debug("unchanged"); + } debug("\n"); } @@ -136,7 +136,7 @@ GfxResult::Search() { debug("GfxResult::Search()\n"); if (game == NULL) - return; + return; ((Training*)game)->search(); @@ -146,21 +146,21 @@ GfxResult::Search() const Results &res = ((Training*)game)->getResults(); debug(" GfxResult::Search size = %d\n",res.size()); for (int i = 0; i < res.size(); i++) - { - Round r = res.get(i); - //debug(" adding %s\n",r.toString().c_str()); - wxString pts; - wxString word = wxU(r.getWord().c_str()); - wxString coords = wxU(r.getCoord().toString().c_str()); - wxChar bonus = r.getBonus() ? wxT('*') : wxT(' '); - pts << r.getPoints(); + { + Round r = res.get(i); + //debug(" adding %s\n",r.toString().c_str()); + wxString pts; + wxString word = wxU(r.getWord().c_str()); + wxString coords = wxU(r.getCoord().toString().c_str()); + wxChar bonus = r.getBonus() ? wxT('*') : wxT(' '); + pts << r.getPoints(); - long tmp = results->InsertItem(i, word); - results->SetItemData(tmp, i); - tmp = results->SetItem(i, 1, bonus); - tmp = results->SetItem(i, 2, coords); - tmp = results->SetItem(i, 3, pts); - } + long tmp = results->InsertItem(i, word); + results->SetItemData(tmp, i); + tmp = results->SetItem(i, 1, bonus); + tmp = results->SetItem(i, 2, coords); + tmp = results->SetItem(i, 3, pts); + } for (int i = 0; i < 4; i++) results->SetColumnWidth(i, wxLIST_AUTOSIZE); @@ -168,10 +168,10 @@ GfxResult::Search() //results->Show(); if (res.size() > 0) - { - results->SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED | wxLIST_MASK_STATE); - ((Training*)game)->testPlay(0); - } + { + results->SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED | wxLIST_MASK_STATE); + ((Training*)game)->testPlay(0); + } } /* ************************************************** */ @@ -194,9 +194,9 @@ GfxResult::OnListCtrlSelected(wxListEvent& event) { //debug(" GfxResult::OnListCtrlSelected\n"); if (event.m_itemIndex > -1) - { - mf->TestPlay(event.m_itemIndex); - } + { + mf->TestPlay(event.m_itemIndex); + } } /* ************************************************** */ @@ -207,10 +207,10 @@ GfxResult::OnListCtrlActivated(wxListEvent& event) { //debug(" GfxResult::OnListCtrlActivated"); if (event.m_itemIndex > -1) - { - mf->Play(1); - results->DeleteAllItems(); - } + { + mf->Play(1); + results->DeleteAllItems(); + } } /* ************************************************** */ diff --git a/wxwin/gfxresult.h b/wxwin/gfxresult.h index ad60580..2b9e6a7 100644 --- a/wxwin/gfxresult.h +++ b/wxwin/gfxresult.h @@ -27,18 +27,17 @@ #ifndef _RESLIST_H #define _RESLIST_H -/** - * - */ +#include #include class MainFrame; + class GfxResult : public wxControl { private: MainFrame *mf; - std::string savedrack; + std::wstring savedrack; Game *game; wxListCtrl *results; ConfigDB config; diff --git a/wxwin/mainframe.cc b/wxwin/mainframe.cc index 70f398f..bbd3fce 100644 --- a/wxwin/mainframe.cc +++ b/wxwin/mainframe.cc @@ -443,12 +443,12 @@ MainFrame::OnMenuGameOpen(wxCommandEvent&) return; } - std::string r = ""; + std::wstring r; if (m_game->getHistory().getSize() >= 0) - { - r = m_game->getCurrentPlayer().getCurrentRack().toString(); - } + { + r = m_game->getCurrentPlayer().getCurrentRack().toString(); + } rack->SetValue(wxU(r.c_str())); // update gfxboard and all frames @@ -962,13 +962,12 @@ void MainFrame::SetRack(Game::set_rack_mode mode, wxString srack) { int res = 0; - std::string str; wxString msg; bool check = config.getRackChecking(); - ((Training*)m_game)->removeTestPlay(); - str = (const char*)srack.mb_str(); - res = ((Training*)m_game)->setRack(mode, check, str); + static_cast(m_game)->removeTestPlay(); + std::wstring str = srack.c_str(); + res = static_cast(m_game)->setRack(mode, check, str); switch (res) { @@ -993,8 +992,8 @@ MainFrame::SetRack(Game::set_rack_mode mode, wxString srack) break; } - std::string r = m_game->getCurrentPlayer().getCurrentRack().toString(); - debug("MainFrame::SetRack : setvalue %s\n",r.c_str()); + std::wstring r = m_game->getCurrentPlayer().getCurrentRack().toString(); + debug("MainFrame::SetRack : setvalue %ls\n",r.c_str()); rack->SetValue(wxU(r.c_str())); UpdateFrames(); UpdateStatusBar(); diff --git a/wxwin/searchpanel.cc b/wxwin/searchpanel.cc index c9a0006..0a00245 100644 --- a/wxwin/searchpanel.cc +++ b/wxwin/searchpanel.cc @@ -139,8 +139,8 @@ void PCross::compute_enter(wxCommandEvent&) { int i; - char rack[DIC_WORD_MAX]; - char buff[RES_CROS_MAX][DIC_WORD_MAX]; + wchar_t rack[DIC_WORD_MAX]; + wchar_t buff[RES_CROS_MAX][DIC_WORD_MAX]; if (!check_dic()) return; @@ -154,7 +154,7 @@ PCross::compute_enter(wxCommandEvent&) return; } - strncpy(rack, t->GetValue().mb_str(), DIC_WORD_MAX); + wcsncpy(rack, t->GetValue().wc_str(), DIC_WORD_MAX); Dic_search_Cros(dic,rack,buff); int resnum = 0; @@ -183,8 +183,8 @@ void PPlus1::compute_enter(wxCommandEvent&) { int i,j; - char rack[DIC_WORD_MAX]; - char buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX]; + wchar_t rack[DIC_WORD_MAX]; + wchar_t buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX]; if (!check_dic()) return; @@ -198,7 +198,7 @@ PPlus1::compute_enter(wxCommandEvent&) return; } - strncpy(rack, t->GetValue().mb_str(), DIC_WORD_MAX); + wcsncpy(rack, t->GetValue().wc_str(), DIC_WORD_MAX); Dic_search_7pl1(dic,rack,buff,TRUE); int resnum = 0; @@ -308,15 +308,15 @@ PRegExp::panel_options() void PRegExp::compute_enter(wxCommandEvent&) { - char re[DIC_RE_MAX]; - char buff[RES_REGE_MAX][DIC_WORD_MAX]; + wchar_t re[DIC_RE_MAX]; + wchar_t buff[RES_REGE_MAX][DIC_WORD_MAX]; if (!check_dic()) return; build_letter_lists(); - strncpy(re, t->GetValue().mb_str(),DIC_RE_MAX); - debug("PRegExp::compute_enter for %s",re); + wcsncpy(re, t->GetValue().wc_str(),DIC_RE_MAX); + debug("PRegExp::compute_enter for %ls",re); int lmin = atoi((const char*)omin->GetValue().mb_str()); int lmax = atoi((const char*)omax->GetValue().mb_str());