📄 greedy.c
字号:
} /* Finally, the score for a singleton. */ /* let's also add .25 times the number of neighbouring tiles */ spr = 0; val = 0.0; val += stratpoints[sglbase] * (tilesleft[tp[0]] + ( is_suit(tp[0]) ? (0.5*strat->chowness*(tilesleft[tp[0]-1]+ tilesleft[tp[0]+1])) : 0)) * (3.0-strat->chowness); if ( is_doubler(tp[0]) ) { if (tilesleft[tp[0]] == 0) val -= 5.0; /* completely useless */ else { if ( (0.5-strat->chowness) > 0 ) val += (tilesleft[tp[0]])*stratpoints[sglbase]*(0.5-strat->chowness); else val += (3-tilesleft[tp[0]])*stratpoints[sglbase]*(0.5-strat->chowness); } } if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) { /* val could be negative, in which case we don't want to shrink it. So just substract a constant */ val -= 0.5*strat->suitness*stratpoints[sglbase]; } if ( ! is_major(tp[0]) ) { val -= 0.5*strat->majorness*stratpoints[sglbase]; } if ( debugeval > 1 ) { if ( notfirst ) printf("%s%s",prefix,&totbuf[11*reclevel]); printf("%sSi%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val); } tcopy(copy,tp); copy[0] = HiddenTile; valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&spr,breadth); val += valr; if ( debugeval > 1 ) { sprintf(tb,"%4.1f",val); strncpy(&totbuf[11*reclevel],tb,4); } /* at this point, we have pair/seq/single based scores. */ if ( mval > pval ) { if ( val > mval ) { if ( spr ) (*npr)++; mval = val; } else { if ( mpr ) (*npr)++; } } else { if ( val > pval ) { mval = val; if ( spr ) (*npr)++; } else { mval = pval; if ( ppr ) (*npr)++; } } if ( debugeval > 1 ) { if ( reclevel ) { sprintf(tb,"(%4.1f) ",mval); strncpy(&totbuf[11*(reclevel-1)+4],tb,7); } else printf(totbuf); } return mval;}/* This function uses the above to evaluate a player's hand, including the completed sets. */static double evalhand(PlayerP p,strategy *strat) { Tile tcopy[MAX_CONCEALED+1]; double val,breadth; int i, npr, ninc; double stratpoints[weight+1]; if ( debugeval ) { char buf[100]; printf("eval with strat params c=%.1f, h=%.1f, m=%.1f, s=%.1f (%d)\n", strat->chowness,strat->hiddenness,strat->majorness, strat->suitness,strat->suit); player_print_tiles(buf,p,0); printf("Hand: %s\n",buf); } /* calculate old style strategy values from new ones */ stratpoints[pungbase] = 12.0 - ( strat->chowness > 0 ? strat->chowness * 12.0 : strat->chowness * 2.0 ); stratpoints[pungbase] *= (1.0 + 0.15 * strat->hiddenness); stratpoints[pairbase] = 1.0*(4.0 + (2.0*fabs(strat->chowness))); stratpoints[chowbase] = 12.0 + ( strat->chowness > 0 ? strat->chowness * 4.0 : strat->chowness * 12.0 ); stratpoints[chowbase] *= (1.0 + 0.15 * strat->hiddenness) * (1.0 - strat->majorness); stratpoints[seqbase] = 0*(1.0 + ( strat->chowness < 0 ? strat->chowness : 0)) * (1.0 - strat->majorness); stratpoints[sglbase] = 0.025; stratpoints[partpung] = 0.4*(0.34)*(1-0.4*strat->hiddenness); stratpoints[partchow] = 0.4*(1.0/12.0)*(1-0.3*strat->hiddenness) * (1.0 - strat->majorness); stratpoints[exposedpungpenalty] = 2.0 + strat->hiddenness * stratpoints[pungbase] + ( (strat->chowness > 0) ? 25.0 * strat->chowness : 0.0 ); stratpoints[exposedchowpenalty] = 2.0 + strat->hiddenness * stratpoints[chowbase] + ( (strat->chowness < 0) ? -25.0 * strat->chowness : 0.0 ) + 25.0 * strat->majorness; stratpoints[mjbonus] = 60.0; stratpoints[kongbonus] = 3.0; stratpoints[suitfactor] = ((strat->suitness >= 1.0) ? 0.01 : (1.0 - 0.99*strat->suitness)); stratpoints[weight] = 1.0 + (strat->suitness >= 1.0 ? 0.2*(strat->suitness-1.0) : 0.2*strat->suitness) + 0.25*strat->majorness; for (i=0; i<p->num_concealed; i++) tcopy[i] = p->concealed[i]; for ( ; i < MAX_CONCEALED+1; i++) tcopy[i] = HiddenTile; val = 0.0; ninc = npr = 0; /* number of "incomplete"/pairs in hand */ /* note that if we see any closed pungs in here, they are actually hacks representing hypothetical open sets */ for (i=0; i<5; i++) { double sval = 0.0; switch (p->tilesets[i].type) { case Chow: case ClosedChow: sval -= stratpoints[exposedchowpenalty]; sval += stratpoints[chowbase]; break; case ClosedKong: sval += stratpoints[exposedpungpenalty]; /* cancel the penalty later */ case Kong: sval += stratpoints[kongbonus]; case Pung: case ClosedPung: sval -= stratpoints[exposedpungpenalty]; sval += stratpoints[pungbase]; /* these shadow evalhand above */ if ( is_doubler(p->tilesets[i].tile) ) sval += (-strat->chowness) * 6.0; if ( is_major(p->tilesets[i].tile) ) { sval += 2.0 ; /* small bonus for luck */ } else { sval -= 25.0*strat->majorness; } break; case Pair: case ClosedPair: ninc = npr = 1; /* for correct evaluation of pairs */ sval += stratpoints[pairbase]; break; default: ; } if ( p->tilesets[i].type != Empty && is_suit(p->tilesets[i].tile) && suit_of(p->tilesets[i].tile) != strat->suit ) sval -= 10.0*strat->suitness; if ( debugeval > 1 ) { printf("Set %s: %.1f\n",player_print_TileSetType(p->tilesets[i].type), sval); } val += sval; } breadth = 0.0; val += eval(tcopy,strat,stratpoints,-1,&ninc,&npr,&breadth); /* add the pairbase if we have at least one pair */ if ( npr > 0 ) { if ( debugeval > 1 ) printf("+pairbase %.1f\n",stratpoints[pairbase]); val += stratpoints[pairbase]; } val *= stratpoints[weight];#if 0 /* randomization seems to be a lose */ /* now add a small random offset */ r = (2.0*rand())/RAND_MAX - 1.0; r = 4*r*r; return val+r;#else if ( debugeval ) printf("Value %.2f\n",val); return val;#endif}/* compute the number of ways a calling hand can go out */static int chances_to_win(PlayerP p) { Tile t; int n; MJSpecialHandFlags mjspecflags; mjspecflags = 0; if ( game_get_option_value(the_game,GOSevenPairs,NULL) ) mjspecflags |= MJSevenPairs; t = HiddenTile; n = 0; while ( (t = tile_iterate(t,0)) != HiddenTile ) { if ( tilesleft[t] && player_can_mah_jong(p,t,mjspecflags) ) n += tilesleft[t]; } return n;}/* compute tile to discard. Return value is tile. Second arg returns score of resulting hand. Third arg returns the new strategy.*/static Tile decide_discard(PlayerP p, double *score, strategy *strat) { /* how do we choose a tile to discard? remove the tile, and evaluate the remaining hand. Discard the tile giving the greatest residual value. */ int i,best; double values[MAX_CONCEALED+1]; Tile tilesa[MAX_CONCEALED+1],tiles[MAX_CONCEALED+1] UNUSED; char buf[80]; const Tile *t = p->concealed; for (i=0;i<MAX_CONCEALED+1;i++) values[i]=0; for (i=0;i<p->num_concealed;i++) tilesa[i] = t[i]; for (;i<MAX_CONCEALED+1;i++) tilesa[i] = HiddenTile; if ( debugeval ) { player_print_tiles(buf,p,0); printf("Hand: %s\n",buf); } best = 0; tsort(tilesa); /* no point in looking at same tile twice */ for (i=0;i<p->num_concealed;i++) { Player cp; if ( i && tilesa[i] == tilesa[i-1] ) continue; if ( debugeval ) { printf("Trying %s: \n",tile_code(tilesa[i])); } copy_player(&cp,p); player_discards(&cp,tilesa[i]); values[i] = evalhand(&cp,strat); /* add a bonus for tiles recently discarded by the player to the right */ if ( rightdiscs[tilesa[i]] ) values[i] += 0.5; /* /(the_game->serial-rightdiscs[tilesa[i]]) */; if ( is_suit(tilesa[i]) && ((value_of(tilesa[i]) < 7 && rightdiscs[tilesa[i]+3]) || (value_of(tilesa[i]) > 3 && rightdiscs[tilesa[i]-3])) ) values[i] += 0.4; /* the 1-4-7 argument */ /* Best tile to discard leaves highest residual score */ if ( values[i] > values[best] ) best = i; if ( debugeval ) { printf("Tile %s has value %.1f\n",tile_code(tilesa[i]),values[i]); } } if ( debugeval ) { printf("Discarding %s\n",tile_code(tilesa[best])); } if ( score ) *score = values[best]; return tilesa[best];}/* Maybe switch strategy: takes a strat pointer as argument, and updates it in place. */static void maybe_switch_strategy(strategy *strat) { strategy tmpstrat; int i,j; double val,oval, bestval; strategy beststrat; int dofast; PlayerP p = our_player; oval = evalhand(p,strat); bestval = -1000.0; tmpstrat.chowness = stratparams[chowness].values[0]; tmpstrat.hiddenness = stratparams[hiddenness].values[0]; tmpstrat.majorness = stratparams[majorness].values[0]; /* it makes no sense to try to evaluate pung/chowness with a non-zero suitness, cos we don't know which suit, and evaluating with suit=0 is equiv to all honours! */ /* tmpstrat.suitness = stratparams[suitness].values[0]; */ tmpstrat.suitness = 0.0; tmpstrat.suit = 0; beststrat.chowness = tmpstrat.chowness; for ( i=0 ; i < stratparams[chowness].ncomps ; i++ ) { tmpstrat.chowness = stratparams[chowness].values[i]; val = evalhand(p,&tmpstrat); if ( val > bestval ) { bestval = val ; beststrat.chowness = tmpstrat.chowness; } } tmpstrat.chowness = beststrat.chowness; beststrat.hiddenness = tmpstrat.hiddenness; /* from i = 1, since we had [0] just above */ for ( i = 1 ; i < stratparams[hiddenness].ncomps ; i++ ) { tmpstrat.hiddenness = stratparams[hiddenness].values[i]; val = evalhand(p,&tmpstrat); if ( val > bestval ) { bestval = val ; beststrat.hiddenness = tmpstrat.hiddenness; } } /* and for suit */ tmpstrat.hiddenness = beststrat.hiddenness; /* now we need to reset the best val, since only now are we considering the values the user had */ bestval = -1000; for ( i = 0; i < stratparams[suitness].ncomps; i++ ) { tmpstrat.suitness = stratparams[suitness].values[i]; /* j = 0 corresponds to all honours, which we shd get if we can ?? */ for ( j = 0 ; j <= ((tmpstrat.suitness == 0.0)? 0 : 3) ; j++ ) { tmpstrat.suit = j; val = evalhand(p,&tmpstrat); if ( val > bestval ) { bestval = val ; beststrat = tmpstrat; } } } /* we'll now try for all majors... */ /* however, there's no point in doing this unless we already think that a pung-based strategy is best */ if ( beststrat.chowness < 0.0 ) { tmpstrat = beststrat; for ( i = 1; i < stratparams[majorness].ncomps; i++ ) { tmpstrat.majorness = stratparams[majorness].values[i]; val = evalhand(p,&tmpstrat); if ( val > bestval ) { bestval = val ; beststrat = tmpstrat; } } } /* if some other player has four sets declared, then switch to Fast */ dofast = 0;#if 0 for ( i = 0 ; i < NUM_SEATS ; i++ ) { PlayerP p1 = the_game->players[i]; if ( p1 == p ) continue; if ( p1->num_concealed <= 1 ) dofast = 1; }#endif if ( dofast ) { /* strat = Fast; */ if ( debugeval ) { printf("Using fast\n"); } } else { if ( bestval >= oval + hysteresis ) { *strat = beststrat; if ( debugeval ) { static char buf[128]; printf("Switching to strat c=%.1f h=%.1f s=%.1f (%d) m=%.1f\n", strat->chowness,strat->hiddenness, strat->suitness,strat->suit,strat->majorness); player_print_tiles(buf,p,0); printf(" with hand %s\n",buf); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -