📄 greedy.c
字号:
} return 1;}/* do something when it's our turn. */static void do_something(void) { int i; MJSpecialHandFlags mjspecflags; mjspecflags = 0; if ( game_get_option_value(the_game,GOSevenPairs,NULL) ) mjspecflags |= MJSevenPairs; /* if the game is paused, and we haven't said we're ready, say so */ if ( the_game->paused ) { if ( !the_game->ready[our_seat] ) { PMsgReadyMsg pm; pm.type = PMsgReady; send_packet(&pm); } return; } /* if the game state is handcomplete, do nothing */ if ( the_game->state == HandComplete ) return; /* If the game state is discarded, then it must mean this has been called in response to a StartPlay message after resuming an old hand. So actually we want to check the discard, unless of course we are the discarder, or we have already claimed. */ if ( the_game->state == Discarded ) { if ( the_game->player != our_seat && the_game->claims[our_seat] == UnknownClaim ) check_discard(our_player,&curstrat); return; } /* If the game state is Dealing, then we should not do anything. */ if ( the_game->state == Dealing ) return; /* if we're called in declaring specials or discarding, but it's not our turn, do nothing */ if ( (the_game->state == DeclaringSpecials || the_game->state == Discarding) && the_game->player != our_seat ) return; /* if we're waiting to draw another tile, do nothing */ if ( the_game->needs != FromNone ) return; /* if we have a special, declare it. N.B. we'll be called again as a result of this, so only look for first. */ for ( i=0; i < our_player->num_concealed && ! is_special(our_player->concealed[i]) ; i++); if ( i < our_player->num_concealed ) { PMsgDeclareSpecialMsg m; m.type = PMsgDeclareSpecial; m.tile = our_player->concealed[i]; send_packet(&m); return; } /* OK, no specials */ if ( the_game->state == DeclaringSpecials ) { PMsgDeclareSpecialMsg m; m.type = PMsgDeclareSpecial; m.tile = HiddenTile; send_packet(&m); /* and at this point, we should decide our strategy */ maybe_switch_strategy(&curstrat); return; } /* if the game is in the mahjonging state, and our hand is not declared, then we should declare a set. */ if ( the_game->state == MahJonging ) { TileSet *tsp; PMsgUnion m; if ( pflag(our_player,HandDeclared) ) return; /* as courtesy, if we're not the winner, we shouldn't score until the winner has */ if ( our_seat != the_game->player && ! pflag(the_game->players[the_game->player],HandDeclared) ) return; /* get the list of possible decls */ tsp = client_find_sets(our_player, (the_game->player == our_seat && the_game->mjpending) ? the_game->tile : HiddenTile, the_game->player == our_seat, (PlayerP *)0,mjspecflags); if ( !tsp && our_player->num_concealed > 0 ) { m.type = PMsgShowTiles; send_packet(&m); return; } /* just do the first one */ switch ( tsp->type ) { case Kong: /* we can't declare a kong now, so declare the pung instead */ case Pung: m.type = PMsgPung; m.pung.discard = 0; break; case Chow: m.type = PMsgChow; m.chow.discard = 0; m.chow.cpos = the_game->tile - tsp->tile; break; case Pair: m.type = PMsgPair; break; case ClosedPung: m.type = PMsgFormClosedPung; m.formclosedpung.tile = tsp->tile; break; case ClosedChow: m.type = PMsgFormClosedChow; m.formclosedchow.tile = tsp->tile; break; case ClosedPair: m.type = PMsgFormClosedPair; m.formclosedpair.tile = tsp->tile; break; case Empty: /* can't happen, just to suppress warning */ case ClosedKong: /* ditto */ ; } send_packet(&m); return; } /* if we can declare MahJong, do it */ if ( player_can_mah_jong(our_player,HiddenTile,mjspecflags) ) { PMsgMahJongMsg m; m.type = PMsgMahJong; m.discard = 0; send_packet(&m); return; } else if ( the_game->whence != FromDiscard ) { /* check for concealed kongs and melded kongs. Just declare them. */ int i; double val; Player pc; val = evalhand(our_player,&curstrat); /* a side effect of the above call is that our concealed tiles are sorted (in reverse order), so we can avoid duplicating effort */ for (i=0;i<our_player->num_concealed;i++) { /* don't look at same tile twice */ if ( i && our_player->concealed[i] == our_player->concealed[i-1] ) continue; if ( player_can_declare_closed_kong(our_player,our_player->concealed[i]) ) { PMsgDeclareClosedKongMsg m; copy_player(&pc,our_player); player_declares_closed_kong(&pc,our_player->concealed[i]); if ( evalhand(&pc,&curstrat) > val ) { m.type = PMsgDeclareClosedKong; m.tile = our_player->concealed[i]; send_packet(&m); return; } } } /* Now check for pungs we can meld to */ for (i=0;i<MAX_TILESETS;i++) { if ( our_player->tilesets[i].type == Pung && player_can_add_to_pung(our_player,our_player->tilesets[i].tile) ) { PMsgAddToPungMsg m; copy_player(&pc,our_player); player_adds_to_pung(&pc,our_player->tilesets[i].tile); if ( evalhand(&pc,&curstrat) > val ) { m.type = PMsgAddToPung; m.tile = our_player->tilesets[i].tile; send_packet(&m); return; } } } } /* if we get here, we have to discard */ { PMsgDiscardMsg m; Tile t; /* strategy switching only after drawing tile from wall */ if ( the_game->whence != FromDiscard || !strategy_chosen) { maybe_switch_strategy(&curstrat); } t = decide_discard(our_player,NULL,&curstrat); m.type = PMsgDiscard; m.tile = t; m.calling = 0; /* we don't bother looking for original call */ send_packet(&m); return; }}/* Check if we want the discard, and claim it. Arg is strategy. Also called to check whether a kong can be robbed */static void check_discard(PlayerP p, strategy *strat) { PMsgUnion m; double bestval,val; int canmj; char buf[100]; MJSpecialHandFlags mjspecflags; mjspecflags = 0; if ( game_get_option_value(the_game,GOSevenPairs,NULL) ) mjspecflags |= MJSevenPairs; if ( the_game->state == Discarding || the_game->state == DeclaringSpecials ) { /* this means we're being called to check whether a kong can be robbed. Since robbing a kong gets us an extra double, this is probably always worth doing, unless we're trying for some limit hand */ if ( player_can_mah_jong(p,the_game->tile,mjspecflags) ) { m.type = PMsgMahJong; m.mahjong.discard = the_game->serial; } else { m.type = PMsgNoClaim; m.noclaim.discard = the_game->serial; } send_packet(&m); return; } if ( debugeval ) { player_print_tiles(buf,p,0); printf("Hand: %s ; discard %s\n",buf,tile_code(the_game->tile)); } bestval = evalhand(p,strat); if ( debugeval ) { printf("Hand value before claim %.3f\n",bestval); } canmj = player_can_mah_jong(p,the_game->tile,mjspecflags); m.type = PMsgNoClaim; m.noclaim.discard = the_game->serial; if ( player_can_kong(p,the_game->tile) ) { Player pc; copy_player(&pc,p); player_kongs(&pc,the_game->tile); val = evalhand(&pc,strat); /* we won't discard a tile here */ if ( debugeval ) { printf("Hand after kong %.3f\n",val); } if ( val > bestval ) { m.type = PMsgKong; m.kong.discard = the_game->serial; bestval = val; } else if ( debugeval ) { printf("Chose not to kong\n"); } } if ( player_can_pung(p,the_game->tile) ) { Player pc; copy_player(&pc,p); player_pungs(&pc,the_game->tile); decide_discard(&pc,&val,&curstrat); if ( debugeval ) { printf("Hand after pung %.3f\n",val); } if ( val > bestval ) { m.type = PMsgPung; m.pung.discard = the_game->serial; bestval = val; } else if ( debugeval ) { printf("Chose not to pung\n"); } } if ( (canmj || our_seat == (the_game->player+1)%NUM_SEATS) && is_suit(the_game->tile) ) { ChowPosition cpos = (unsigned) -1; Player pc; int chowposs = 0; Tile t = the_game->tile; copy_player(&pc,p); if ( player_chows(&pc,t,Lower) ) { decide_discard(&pc,&val,&curstrat); if ( debugeval ) { printf("Hand after lower chow: %.3f\n",val); } chowposs = 1; if ( val > bestval ) { bestval = val; cpos = Lower; } copy_player(&pc,p); } if ( player_chows(&pc,t,Middle) ) { decide_discard(&pc,&val,&curstrat); if ( debugeval ) { printf("Hand after middle chow: %.3f\n",val); } chowposs = 1; if ( val > bestval ) { bestval = val; cpos = Middle; } copy_player(&pc,p); } if ( player_chows(&pc,t,Upper) ) { chowposs = 1; decide_discard(&pc,&val,&curstrat); if ( debugeval ) { printf("Hand after upper chow: %.3f\n",val); } if ( val > bestval ) { bestval = val; cpos = Upper; } copy_player(&pc,p); } if ( cpos != (unsigned)-1 ) { m.type = PMsgChow; m.chow.discard = the_game->serial; m.chow.cpos = cpos; } else if ( debugeval ) { if ( chowposs ) fprintf(stdout,"chose not to chow\n"); } } /* mah jong */ if ( canmj ) { m.type = PMsgMahJong; m.mahjong.discard = the_game->serial;#if 1 /* if we're following a concealed strategy, and we still have four chances (ex?cluding this one) of going out, then don't claim */ /* instead of four chances, make it depend on number of tiles left */ /* test: if hidden >1, then never claim */ if ( (strat->hiddenness > 1.0) || (strat->hiddenness*chances_to_win(p) * (the_game->wall.live_end-the_game->wall.live_used) / (the_game->wall.dead_end-the_game->wall.live_used) >= 1.5) ) { m.type = PMsgNoClaim; m.noclaim.discard = the_game->serial; }#endif if ( m.type != PMsgNoClaim ) { if ( debugeval && strat->hiddenness > 0.0 ) printf("claiming mahjong on hidden strategy\n"); m.type = PMsgMahJong; m.mahjong.discard = the_game->serial; } else { if ( debugeval ) { printf("CHOSE NOT TO MAHJONG\n"); } } } if ( debugeval ) { printf("Result: %s",encode_pmsg((PMsgMsg *)&m)); } send_packet(&m);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -