📄 scoring.c
字号:
/* this ridiculous amount of code deals with filling the only place. All this work for two points... */ /* this is a sanity check; if this fails, the controller code has not put the right player in the caller slot */ /* we don't give this for seven pairs either */ if ( numpairs == 1 ) { if ( winner ) { if ( p->id != gextras(g)->caller->id ) { warn("Wrong player found in caller slot of game structure!"); } else { PlayerP pp = gextras(g)->caller; int n = 0; int i; Tile t; /* see how many tiles can complete the hand in theory */ t = HiddenTile; while ( (t = tile_iterate(t,0)) != HiddenTile ) { /* if all four copies of the tile are exposed, it doesn't count as available */ /* However, if this is the tile that was claimed for Mah-Jong, it wasn't all exposed when we called, even if the exposed count is now 4. */ if ( g->exposed_tile_count[t] == 4 && g->tile != t ) continue; i = player_can_mah_jong(pp,t,mjspecflags); if ( i < 0 ) { warn("error in player_can_mah_jong while checking only place") ; } else n += i; } if ( n <= 1 ) { doscore("extra",2,"filling the only place"); } } } }#define dbl(n,ex) doscore("",n DBLS,ex) /* Now start looking for doubles from the tilesets */ for ( i = 0; i < MAX_TILESETS; i++ ) { TileSetP t = (TileSetP) &p->tilesets[i]; if ( t->type == Empty ) continue; if ( num_tiles_in_set(t) >= 3 ) { if ( is_dragon(t->tile) ) doscore(tileset_string(t),1 DBLS,"pung/kong of dragons"); if ( is_wind(t->tile) && (TileWind)value_of(t->tile) == p->wind ) doscore(tileset_string(t),1 DBLS,"pung/kong of own wind"); if ( is_wind(t->tile) && (TileWind)value_of(t->tile) == g->round ) doscore(tileset_string(t),1 DBLS,"pung/kong of prevailing wind"); } }/* We may want to suppress these when comparing strategies, as they introduce a lot of randomness */ /* Flower and season doubles */ if ( ! no_special_scores ) { int ownflower = 0, ownseason = 0; int numflowers = 0; int numseasons = 0; int i; for ( i = 0; i < p->num_specials; i++ ) { if ( suit_of(p->specials[i]) == FlowerSuit ) { numflowers++; if ( (TileWind)value_of(p->specials[i]) == p->wind ) ownflower = 1; } if ( suit_of(p->specials[i]) == SeasonSuit ) { numseasons++; if ( (TileWind)value_of(p->specials[i]) == p->wind ) ownseason = 1; } } if ( ownflower ) doscore("",(int)game_get_option_value(g,GOFlowersOwnEach,NULL), "own flower"); if ( ownseason ) doscore("",(int)game_get_option_value(g,GOFlowersOwnEach,NULL), "own season"); if ( ownflower && ownseason ) doscore("",(int)game_get_option_value(g,GOFlowersOwnBoth,NULL), "own flower and season"); if ( numflowers == 4 ) doscore("",(int)game_get_option_value(g,GOFlowersBouquet,NULL), "all four flowers"); if ( numseasons == 4 ) doscore("",(int)game_get_option_value(g,GOFlowersBouquet,NULL), "all four seasons"); } /* doubles applying to all hands */ /* Little/Big Three Dragons */ if ( dragonsets == 3 ) { dbl(2,"Big Three Dragons"); if ( winner ) psetdflags(p,s,DangerDragon); } else if ( dragonsets == 2 && dragonpairs ) { dbl(1,"Little Three Dragons"); if ( winner ) psetdflags(p,s,DangerDragon); } /* Little/Big Four Joys */ if ( windsets == 4 ) { dbl(2,"Big Four Joys"); if ( winner ) psetdflags(p,s,DangerWind); } else if ( windsets == 3 && windpairs ) { dbl(1,"Little Four Joys"); if ( winner ) psetdflags(p,s,DangerWind); } /* three concealed pungs */ if ( numclosedpks >= 3 ) { dbl(1,"three concealed pungs"); } /* other doubles mostly applying only to the mahjong hand */ if ( winner ) { if ( numchows == 0 && numpairs == 1 ) dbl(1,"no chows"); if ( noscore ) dbl(1,"no score hand"); } /* some losers want these doubles to apply to losing hands also */ if ( winner || game_get_option_value(g,GOLosersPurity,NULL) ) { if ( allhonours ) { /* This should score 2 doubles, and then get a double for all majors. However, we must be careful not to give it the double for one-suit-with-honours! */ dbl(2,"all honours"); psetdflags(p,s,DangerHonour); } else if ( allterminals ) { /* This should score 2 doubles, and then get a double for all majors. */ dbl(2,"all terminals"); psetdflags(p,s,DangerTerminal); } if ( allmajors ) { dbl(1,"all majors"); } } /* double for fully concealed hand */ if ( winner ) { /* we may have claimed a discard for a special set */ if ( g->whence == FromDiscard ) allclosed = 0; if ( allclosed ) doscore("",(int)game_get_option_value( g,GOConcealedFully,NULL),"concealed hand"); } /* double for almost concealed hand. This is a pain */ if ( winner && !allclosed ) { int semiclosed = 1; /* need to check the hand before mahjong. Hooray, another use for the caller slot ! */ if ( p->id != gextras(g)->caller->id ) { warn("Wrong player found in caller slot of game structure!"); semiclosed = 0; } else { PlayerP pp = gextras(g)->caller; int i; for ( i = 0; i < MAX_TILESETS; i++ ) { switch ( pp->tilesets[i].type ) { case Chow: case Pung: case Kong: case Pair: semiclosed = 0; break; default: break; /* keep ANSI quiet */ } } } if ( semiclosed ) doscore("",(int)game_get_option_value( g,GOConcealedAlmost,NULL),"almost concealed hand"); } else if ( !winner && allclosed && game_get_option_value(g,GOLosersPurity,NULL) ) { doscore("",(int)game_get_option_value( g,GOConcealedAlmost,NULL),"almost concealed hand"); } /* we may give these to losers, if somebody really wants */ if ( winner || game_get_option_value(g,GOLosersPurity,NULL) ) { /* NB. If no suit tiles, then we already have all honours, and don't give another double! */ if ( allbamboo || allcharacter || allcircle ) { dbl(3,"one suit only"); if ( allbamboo ) psetdflags(p,s,DangerBamboo); if ( allcharacter ) psetdflags(p,s,DangerCharacter); if ( allcircle ) psetdflags(p,s,DangerCircle); } else if ( !allhonours && (allbamboohonour || allcharacterhonour || allcirclehonour) ) { dbl(1,"one suit with honours"); } } if ( winner ) { /* Should the following two be exclusive? */ /* loose tile */ if ( g->whence == FromLoose ) dbl(1,"winning with loose tile"); /* last tile. This is >=, not ==, because if playing with a replenishing dead wall, it's possible to move the end of the live wall back past tiles already taken, if the last tile is a redeemed for a loose tile with 13 in the dead wall. */ if ( g->wall.live_used >= g->wall.live_end ) dbl(1,"winning with last tile"); /* robbing a kong */ if ( g->whence == FromRobbedKong ) dbl(1,"robbing a kong"); /* original call */ if ( pflag(p,OriginalCall) ) dbl(1,"completing Original Call"); } /* having done all that work, we now look for limit hands. Note that all the danger signals except all green have already been set while we were looking for doubles */#define limh(l) doscore("",LIMIT,l) /* we may as well record all the attained limits! */ if ( winner ) { if ( g->player == east && pflag(p,NoDiscard) ) { /* heaven's blessing */ limh("Heaven's Blessing"); } if ( g->player != east && pflag(p,NoDiscard) && g->whence == FromDiscard ) { seats s; int eb = 1; /* might be earth's blessing, but we need to check that nobody else has discarded in between */ for ( s = south; s < NUM_SEATS; s++ ) { if ( !pflag(g->players[s],NoDiscard) ) eb = 0; } if ( eb ) limh("Earth's Blessing"); } if ( g->whence == FromLoose && g->tile == make_tile(CircleSuit,5) ) { limh("Gathering Plum Blossom from the Roof"); } if ( g->tile == make_tile(CircleSuit,1) && g->wall.live_used == g->wall.live_end && g->whence == FromWall ) { limh("Catching the Moon from the Bottom of the Sea"); } if ( g->whence == FromRobbedKong && g->tile == make_tile(BambooSuit,2) ) { limh("Scratching a Carrying Pole"); } if ( game_flag(g,GFKongUponKong) ) { limh("Kong upon Kong"); } if ( numkongs == 4 ) { limh("Fourfold Plenty"); } if ( allclosed && numpungs+numkongs == 4 ) { limh("Buried Treasure"); } if ( player_can_thirteen_wonders(p,HiddenTile) ) { limh("Thirteen Unique Wonders"); } if ( dragonsets == 3 && numchows == 0 ) { limh("Three Great Scholars"); } if ( windsets == 4 ) { limh("Four Blessing o'er the Door"); } if ( allhonours ) { limh("All Honours"); } if ( allterminals ) { limh("Heads and Tails"); } if ( allclosed && (allbamboo || allcharacter || allcircle) ) { limh("Concealed Clear Suit"); } if ( g->hands_as_east == 12 && g->player == east ) { /* sic */ limh("East's 13th consecutive win"); } if ( allgreen ) { limh("Imperial Jade"); psetdflags(p,s,DangerGreen); } /* Nine Gates */ if ( allbamboo || allcharacter || allcircle ) { /* worth checking in this case */ PlayerP pp = gextras(g)->caller; int ng = 1; if ( pp->id != p->id ) { warn("Wrong player found in caller slot of game structure!"); ng = 0; } else { int i; if ( is_honour(g->tile) ) { ng = 0; } else { int s = suit_of(g->tile); player_sort_tiles(pp); if ( pp->num_concealed < 13 ) ng = 0; for ( i = 0 ; i < 3 ; i++ ) { if ( pp->concealed[i] != make_tile(s,1) ) ng = 0; } for ( i = 2 ; i < 11 ; i++ ) { if ( pp->concealed[i] != make_tile(s,i-1) ) ng = 0; } for ( i = 11 ; i < 13 ; i++ ) { if ( pp->concealed[i] != make_tile(s,9) ) ng = 0; } } } if ( ng ) limh("Nine Gates"); } /* The Wriggling Snake, another silly hand */ if ( allbamboo || allcharacter || allcircle ) { /* check for it */ int i; int set1=0,set9=0,pair2=0,pair5=0,pair8=0, chow2=0,chow3=0,chow5=0,chow6=0; for ( i = 0 ; i < MAX_TILESETS ; i++ ) { switch( p->tilesets[i].type ) { case Empty: break; case Pung: case ClosedPung: case Kong: case ClosedKong: set1 |= (value_of(p->tilesets[i].tile) == 1); set9 |= (value_of(p->tilesets[i].tile) == 9); break; case Pair: case ClosedPair: pair2 |= (value_of(p->tilesets[i].tile) == 2); pair5 |= (value_of(p->tilesets[i].tile) == 5); pair8 |= (value_of(p->tilesets[i].tile) == 8); break; case Chow: case ClosedChow: chow2 |= (value_of(p->tilesets[i].tile) == 2); chow3 |= (value_of(p->tilesets[i].tile) == 3); chow5 |= (value_of(p->tilesets[i].tile) == 5); chow6 |= (value_of(p->tilesets[i].tile) == 6); break; } } if ( set1 && set9 && ( (pair2 && chow3 && chow6) || (pair5 && chow2 && chow6) || (pair8 && chow2 && chow5) ) ) limh("Wriggling Snake"); } } /* display the total points so far */ sprintf(tbuf,"%-11s %3d\n","total pts",tot.value); strcat(buf,tbuf); /* add the double descriptions */ strcat(buf,dblsbuf); /* calculate the doubles */ sprintf(tbuf,"%-12s %2d\n","total dbls",doubles); strcat(buf,tbuf); /* to avoid arithmetic overflow when people set crazy options, we'll put a hard limit of 1E8 in */ while ( doubles-- > 0 ) { tot.value *= 2; if ( tot.value > 100000000 ) tot.value = 100000000 ; } if ( ! nolimit && tot.value > limit ) { sprintf(tbuf,"%-9s %5d (over limit)\n","score:",tot.value); strcat(buf,tbuf); tot.value = limit; } /* and the limit descriptions */ strcat(buf,limsbuf); /* calculate the limit */ if ( centilims ) { if ( nolimit ) { if ( centilims*limit/100 > tot.value ) tot.value = centilims*limit/100; } else { tot.value = centilims*limit/100; /* all the scoring info is irrelevant */ strcpy(buf,limsbuf); } } sprintf(tbuf,"%-9s %5d","SCORE:",tot.value); strcat(buf,tbuf); /* just return what we've got, to see if it's working */ return tot;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -