/* Eliot */ /* Copyright (C) 1999 Antoine Fraboulet */ /* antoine.fraboulet@free.fr */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: game.c,v 1.1 2004/04/08 09:43:06 afrab Exp $ */ #include #include #include #include #include "dic.h" #include "tiles.h" #include "bag.h" #include "rack.h" #include "round.h" #include "pldrack.h" #include "results.h" #include "board.h" #include "game.h" #include "gameio.h" #include "game_internals.h" #include "debug.h" /********************************************************* *********************************************************/ Game Game_create(Dictionary dic) { int i; Game g; g = (Game)malloc(sizeof(struct tgame)); if (g == NULL) return NULL; g->dic = dic; g->bag = Bag_create(); g->board = Board_create(); g->searchresults = Results_create(); for(i=0; i < PLAYEDRACK_MAX; i++) { g->playedrounds[i] = Round_create(); g->playedracks[i] = Playedrack_create(); } Game_init(g); return g; } void Game_destroy(Game g) { int i; if (g) { Bag_destroy(g->bag); Board_destroy(g->board); Results_destroy(g->searchresults); for(i=0; i < PLAYEDRACK_MAX; i++) { Round_destroy(g->playedrounds[i]); Playedrack_destroy(g->playedracks[i]); } free(g); } } /********************************************************* *********************************************************/ void Game_init(Game g) { int i; Bag_init(g->bag); Board_init(g->board); Results_init(g->searchresults); for(i=0; i < PLAYEDRACK_MAX; i++) { Round_init(g->playedrounds[i]); Playedrack_init(g->playedracks[i]); } g->points = 0; g->nrounds = 0; } int Game_load(Game game, FILE* fin) { return Game_read_game(fin,game); } void Game_save(Game game, FILE* fout) { Game_print_game(fout,game); } /********************************************************* *********************************************************/ Dictionary Game_getdic(Game g) { return g->dic; } void Game_setdic(Game g, Dictionary d) { g->dic = d; } /********************************************************* *********************************************************/ int Game_search(Game game) { Rack rack; if (game->dic == NULL) return 1; Game_removetestplay(game); Results_init(game->searchresults); rack = Rack_create(); Playedrack_getrack(game->playedracks[game->nrounds],rack); if (game->nrounds) Board_search(game->dic,game->board, rack, game->searchresults); else Board_search_first(game->dic,game->board, rack, game->searchresults); Rack_destroy(rack); return 0; } /* This function returns a rack "dest" with the unplayed tiles from the current round. 03 sept 2000 : We have to sort the tiles according to the new rules */ static void Game_restfromround(Playedrack dest, Playedrack source, Round round) { tile_t i; Rack r; r = Rack_create(); Playedrack_getrack(source,r); /* we remove the played tiles from rack r */ for(i=0; i < Round_wordlen(round); i++) { if (Round_playedfromrack(round,i)) { if (Round_joker(round,i)) Rack_remove(r,(tile_t)JOKER_TILE); else Rack_remove(r,Round_gettile(round,i)); } } Playedrack_init(dest); Playedrack_setold(dest,r); Rack_destroy(r); } int Game_play(Game game, int n) { /* * We remove tiles from the bag only when they are played * on the board. When going back in the game, we must only * replace played tiles. * We test a rack when it is set but tiles are left in * the bag. */ int i; Round round; if (game->dic == NULL) return 1; if ((round = Results_get(game->searchresults,n))==NULL) return 2; Round_copy(game->playedrounds[game->nrounds],round); Board_addround(game->dic,game->board,round); game->points += Round_points(round); Game_restfromround(game->playedracks[game->nrounds + 1], game->playedracks[game->nrounds], round); for(i=0; i < Round_wordlen(round); i++) { if (Round_playedfromrack(round,i)) { if (Round_joker(round,i)) Bag_taketile(game->bag,(tile_t)JOKER_TILE); else Bag_taketile(game->bag,Round_gettile(round,i)); } } game->nrounds++; Results_init(game->searchresults); return 0; } int Game_back(Game game, int n) { int i,j; Round lastround; if (game->dic == NULL) return 1; for(i=0 ; i < n; i++) { if (game->nrounds) { game->nrounds--; lastround = game->playedrounds[game->nrounds]; game->points -= Round_points(lastround); Board_removeround(game->dic,game->board,lastround); for(j=0; j < Round_wordlen(lastround); j++) { if (Round_playedfromrack(lastround,j)) { if (Round_joker(lastround,j)) Bag_replacetile(game->bag,JOKER_TILE); else Bag_replacetile(game->bag,Round_gettile(lastround,j)); } } Round_init(lastround); } } return 0; } int Game_testplay(Game game, int n) { Round round; if ((round = Results_get(game->searchresults,n))==NULL) return 2; Board_testround(game->board,round); return 0; } int Game_removetestplay(Game game) { Board_removetestround(game->board); return 0; } /********************************************************* *********************************************************/ int Game_getpoints(Game g) { return g->points; } char Game_getboardchar(Game g, int r, int c) { tile_t t; char l = 0; t = Board_tile(g->board,r,c); if (t) { l = codetochar(t); if (Board_joker(g->board,r,c)) l = tolower(l); } return l; } int Game_getboardcharattr(Game g,int r,int c) { int t = Board_gettestchar(g->board,r,c); int j = Board_joker(g->board,r,c); return (t << 1) | j; } int Game_getboardwordmultiplier(Game g,int r,int c) { return Board_getwordmultiplier(g->board,r,c); } int Game_getboardlettermultiplier(Game g,int r,int c) { return Board_getlettermultiplier(g->board,r,c); } /********************************************************* *********************************************************/ int Game_setrack_random(Game game, int check, set_rack_mode mode) { int i,c,v,min,nold; tile_t l; Bag b; Playedrack p; /* create a copy of the bag in which we can do everything we want */ b = Bag_create(); Bag_copy(b,game->bag); if (Bag_ntiles(b) == 0) return 1; v = Bag_nvowels(b); c = Bag_nconsonants(b); min = 0; if (check) { if (v == 0 || c == 0) return 1; if (Bag_nvowels(b) > 1 && Bag_nconsonants(b) > 1 && Game_getnrounds(game) < 15) min = 2; else min = 1; } p = game->playedracks[game->nrounds]; nold = Playedrack_nold(p); /* "complement" with an empty rack is equivalent to ALL */ if (mode == RACK_ALL || nold == 0) { Playedrack_init(p); for(i=0; (Bag_ntiles(b) != 0) && (i < RACK_MAX); i++) { l = Bag_select_random(b); Bag_taketile(b,l); Playedrack_addold(p,l); } } else { tile_t ttmp[RACK_MAX]; int oldc = 0; int oldv = 0; /* we flush the "new" part of the rack */ Playedrack_resetnew(p); /* "old" part must be taken into account in the bag */ Playedrack_getoldtiles(p,ttmp); for(i=0; ttmp[i] ; i++) { if (Tiles_consonants[ttmp[i]]) oldc++; if (Tiles_vowels[ttmp[i]]) oldv++; Bag_taketile(b,ttmp[i]); } /* make sure we can complete the rack */ if (check) { /* RACK_MAX - nold is the number of letters to add */ if (min > oldc + RACK_MAX - nold || min > oldv + RACK_MAX - nold) return 3; } /* take new tiles from the bag */ for(i=nold; (Bag_ntiles(b) != 0) && (i < RACK_MAX); i++) { l = Bag_select_random(b); Bag_taketile(b,l); Playedrack_addnew(p,l); } } Bag_destroy(b); if (check) return Playedrack_check_rack(p, min) ? 0 : 2; else return 0; /* everything is ok */ } static int Game_rackinbag(Rack r, Bag b) { int i; for(i=0; i < TILES_NUMBER; i++) if (Rack_in(r,i) > Bag_in(b,i)) return 0; return 1; } int Game_setrack_manual(Game game, int check, const char *t) { int i,min,ret; tile_t l; Playedrack p; Rack rack; p = game->playedracks[game->nrounds]; if (t == NULL || t[0] == 0) { Playedrack_init(p); return 0; } Playedrack_init(p); for(i=0; t[i] != 0 && t[i] != '+'; i++) { if ((l = chartocode(t[i]))==0) { return 1; } Playedrack_addold(p,l); } if (t[i] == '+') { for(i++; t[i] ; i++) { if ((l = chartocode(t[i])) == 0) { return 1; } Playedrack_addnew(p,l); } } rack = Rack_create(); Playedrack_getrack(p,rack); if ((ret = Game_rackinbag(rack,game->bag)) == 0) { Playedrack_init(p); Rack_destroy(rack); return 1; } Rack_destroy(rack); if (check) { if (Bag_nvowels(game->bag) > 1 && Bag_nconsonants(game->bag) > 1 && Game_getnrounds(game) < 15) min = 2; else min = 1; return Playedrack_check_rack(p, min) ? 0 : 2; } else return 0; /* everything is ok */ } /********************************************************* *********************************************************/ int Game_getcharinbag(Game g, char c) { return Bag_in(g->bag,chartocode(c)); } /********************************************************* *********************************************************/ int Game_getnrounds(Game g) { return g->nrounds; } void Game_getplayedrack(Game g, int num, char buff[RACK_SIZE_MAX]) { int i,l = 0; Playedrack p; tile_t bt[RACK_SIZE_MAX]; buff[0] = 0; if (num < 0 || num > g->nrounds) return; p = g->playedracks[num]; Playedrack_getoldtiles(p, bt); for(i=0; bt[i]; i++) buff[l++] = codetochar(bt[i]); Playedrack_getnewtiles(p, bt); if (i && bt[0]) buff[l++] = '+'; for(i=0; bt[i]; i++) buff[l++] = codetochar(bt[i]); buff[l] = 0; } void Game_getplayedword(Game g, int num, char buff[WORD_SIZE_MAX]) { Round r; char c; int i,l = 0; buff[0] = 0; if (num < 0 || num >= g->nrounds) return; r = g->playedrounds[num]; for(i=0; i < Round_wordlen(r); i++) { c = codetochar(Round_gettile(r,i)); if (Round_joker(r,i)) c = tolower(c); buff[l++] = c; } buff[i] = 0; } void Game_getplayedfirstcoord (Game g,int num,char buff[COOR_SIZE_MAX]) { Round r; buff[0] = 0; if (num < 0 || num >= g->nrounds) return; r = g->playedrounds[num]; if (Round_dir(r) == HORIZONTAL) sprintf(buff,"%c",Round_row(r) + 'A' - 1); else sprintf(buff,"%d",Round_column(r)); } void Game_getplayedsecondcoord(Game g,int num,char buff[COOR_SIZE_MAX]) { Round r; buff[0] = 0; if (num < 0 || num >= g->nrounds) return; r = g->playedrounds[num]; if (Round_dir(r) == HORIZONTAL) sprintf(buff,"%d",Round_column(r)); else sprintf(buff,"%c",Round_row(r) + 'A' - 1); } void Game_getplayedcoord(Game g, int num, char buff[COOR_SIZE_MAX]) { char c1[COOR_SIZE_MAX]; char c2[COOR_SIZE_MAX]; Game_getplayedfirstcoord(g,num,c1); Game_getplayedsecondcoord(g,num,c2); sprintf(buff,"%2s%2s",c1,c2); } int Game_getplayedpoints(Game g, int num) { if (num < 0 || num >= g->nrounds) return 0; return Round_points(g->playedrounds[num]); } int Game_getplayedbonus(Game g, int num) { if (num < 0 || num >= g->nrounds) return 0; return Round_bonus(g->playedrounds[num]); } /********************************************************* *********************************************************/ int Game_getnresults(Game g) { return Results_in(g->searchresults); } void Game_getsearchedword(Game g, int num ,char buff[WORD_SIZE_MAX]) { Round r; char c; int i,l = 0; buff[0] = 0; if (num < 0 || num >= Results_in(g->searchresults)) return; r = Results_get(g->searchresults,num); for(i=0; i < Round_wordlen(r); i++) { c = codetochar(Round_gettile(r,i)); if (Round_joker(r,i)) c = tolower(c); buff[l++] = c; } buff[i] = 0; } void Game_getsearchedfirstcoord(Game g,int num,char buff[COOR_SIZE_MAX]) { Round r; buff[0] = 0; if (num < 0 || num >= Results_in(g->searchresults)) return; r = Results_get(g->searchresults,num); if (Round_dir(r) == HORIZONTAL) sprintf(buff,"%c",Round_row(r) + 'A' - 1); else sprintf(buff,"%d",Round_column(r)); } void Game_getsearchedsecondcoord(Game g, int num, char buff[COOR_SIZE_MAX]) { Round r; buff[0] = 0; if (num < 0 || num >= Results_in(g->searchresults)) return; r = Results_get(g->searchresults,num); if (Round_dir(r) == HORIZONTAL) sprintf(buff,"%d",Round_column(r)); else sprintf(buff,"%c",Round_row(r) + 'A' - 1); } void Game_getsearchedcoord(Game g, int num, char buff[COOR_SIZE_MAX]) { char c1[COOR_SIZE_MAX]; char c2[COOR_SIZE_MAX]; Game_getsearchedfirstcoord(g,num,c1); Game_getsearchedsecondcoord(g,num,c2); sprintf(buff,"%2s%2s",c1,c2); } int Game_getsearchedpoints(Game g, int num) { if (num < 0 || num >= Results_in(g->searchresults)) return 0; return Round_points(Results_get(g->searchresults,num)); } int Game_getsearchedbonus(Game g, int num) { if (num < 0 || num >= Results_in(g->searchresults)) return 0; return Round_bonus(Results_get(g->searchresults,num)); }