⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 greedy.c

📁 支持网络和单机的麻将游戏
💻 C
📖 第 1 页 / 共 4 页
字号:
  return;}/* Here is a data structure to track the number of (assumed)   available tiles elsewhere. The update fn should be called on every CMsg. */static void update_tilesleft(CMsgUnion *m) {  int i;  /* note that we don't need to check whether the tile is blank,     since the HiddenTile entry of tilesleft has no meaning.  */  switch ( m->type ) {  case CMsgNewHand:    for (i=0; i < MaxTile; i++) {      tilesleft[i] = 4;      rightdiscs[i] = 0;    }    return;  case CMsgPlayerDeclaresSpecial:    return;  case CMsgPlayerDraws:    tilesleft[m->playerdraws.tile]--;    return;  case CMsgPlayerDrawsLoose:    tilesleft[m->playerdrawsloose.tile]--;    return;  case CMsgPlayerDiscards:    /* if this is us, we've already counted it */    if ( m->playerdiscards.id != our_id )      tilesleft[m->playerdiscards.tile]--;    if ( game_id_to_seat(the_game,m->playerdiscards.id)	 == (our_seat+1)%4 )       rightdiscs[m->playerdiscards.tile] = m->playerdiscards.discard;    return;  case CMsgPlayerPungs:    /* if somebody else pungs, then two more tiles become dead       (the discard was already noted).       If we pung, nothing new is known */    if ( m->playerpungs.id != our_id )      tilesleft[m->playerpungs.tile] -= 2;    return;  case CMsgPlayerKongs:    /* if somebody else kongs, then three more tiles become dead       (the discard was already noted). */    if ( m->playerkongs.id != our_id )      tilesleft[m->playerkongs.tile] -= 3;    return;  case CMsgPlayerDeclaresClosedKong:    if ( m->playerdeclaresclosedkong.id != our_id )      tilesleft[m->playerdeclaresclosedkong.tile] -= 4;    return;  case CMsgPlayerAddsToPung:    if ( m->playeraddstopung.id != our_id )      tilesleft[m->playeraddstopung.tile]--;    return;  case CMsgPlayerChows:    if ( m->playerchows.id != our_id ) {      Tile t = m->playerchows.tile;      ChowPosition c = m->playerchows.cpos;      tilesleft[(c==Lower)?t+1:(c==Middle)?t-1:t-2]--;      tilesleft[(c==Lower)?t+2:(c==Middle)?t+1:t-1]--;    }    return;  case CMsgSwapTile:    tilesleft[m->swaptile.oldtile]++;    tilesleft[m->swaptile.newtile]--;    return;  default:    return;  }}/* This sorts the tiles (as below) into reverse order.   Why reverse order? So that HiddenTile terminates the hand.*/static void tsort(Tile *tp) {  int i,m;  Tile t;  /* bubblesort */  m = 1;  while ( m ) {    m = 0;    for (i=0; i<MAX_CONCEALED+1-1;i++)      if ( tp[i] < tp[i+1] ) {	t = tp[i];	tp[i] = tp[i+1];	tp[i+1] = t;	m = 1;      }  }}/* This function attempts to evaluate a partial hand.   The input is a (pointer to an) array of tiles   (length MAX_CONCEALED+1; some will be blank).   The value is a floating point number, calculated thus:   for the first tile in the set, form all possible sets   and partial sets (incl. singletons) with that tile;   then recurse on the remainder. The value is then the   max over the partial sets of the inherent value of the   set (explained below) and the recursive value of the remaining hand.   This would have the slightly awkward consequence that pairs get counted   twice in pungs, since given 222... we see 22 2 and also 2 22.   Hence, if we form a pung, we don't form a pair also.   (Nothing special is done about kongs; it should be.)   **** The input is sorted in place. *****//* debugging format:   SSTT:mmmm+ (recursive)   tttt(nnnn)   where SS is a set code (Pu,Pr,Ch,In,Ou,Si),   TT is the tile code, mmmm is the set value,   tttt is the total, nnnn is the residual   Hence the recursive call should indent all lines except the first   by reclevel*11 characters, and the base case call should emit   a newline.*//* other parameters:   strat: current strategy   reclevel: recursion level. Should start at 0.   ninc: number of incomplete sets (including pairs) in     the chain so far.   npr: number of pairs in the chain so far.   breadth is something to try to count the number of ways a hand   can be evaluated. Every time we hit bottom, we'll increment   breadth by 1/reclevel.*/static double eval(Tile *tp,strategy *strat,double *stratpoints,		   int reclevel,		   int *ninc,		   int *npr,		   double *breadth) {  Tile copy[MAX_CONCEALED+1],copy2[MAX_CONCEALED+1];  int i;  double mval = -1000, pval = -1000, val = -1000,    pvalr = -1000, mvalr = -1000, valr = -1000;  int ppr, mpr; int spr;  char prefix[200];  static char totbuf[200];  char tb[20];  int notfirst=0;  tsort(tp);    if ( reclevel == -1 ) {    /*evaluate each suit in turn*/    mval = 0.0;    tcopy(copy,tp);    while ( suit_of(copy[0]) ) {      tcopy(copy2,copy);      for ( i = 0; suit_of(copy[i]) == suit_of(copy[0]); i++ );      for ( ; i < MAX_CONCEALED+1 ; i++ ) copy[i] = HiddenTile;      val = eval(copy,strat,stratpoints,0,ninc,npr,breadth);      mval += val ;      if ( debugeval ) printf("Evaling suit %d returned v=%.2f, b=%.2f\n",			      suit_of(copy[0]),val,*breadth);      tcopy(copy,copy2);      for ( i= 0; suit_of(copy[i]) == suit_of(copy2[0]) ; i++ )	copy[i] = HiddenTile;      tsort(copy);    }    if ( debugeval ) printf("Level 0 returned %.2f\n",mval);    return mval;  }  if ( debugeval ) {    /* The total buffer. A call at recursion level n writes the total into bytes       11(n-1) to 11n-1  of the buffer (right justified in the first 4 chars;        spaces in the rest.       A base case terminates the total buffer with null.       When a second set is printed, or when we terminate at level zero,       then the total buffer is printed.    */    for (i=0;i<reclevel*11;i++) prefix[i]=' ';    prefix[i]=0;  }  if ( tp[0] == HiddenTile ) {    if ( debugeval > 1 ) {      printf("\n");       if (reclevel) sprintf(&totbuf[11*(reclevel-1)+4],"\n");    }    /* if there is one "incomplete" set and one pair, we have a complete       hand */#if 0    if ( ninc == 1 && npr == 1 ) val = stratpoints[mjbonus];    else val = 0.0;#else    val = 0.0;#endif    if ( debugeval > 1 ) {      sprintf(tb,"%4.1f",val);      strncpy(&totbuf[11*reclevel],tb,4);    }    return val;  }  /* does it pung? */  ppr = 0;  if ( tp[1] == tp[0] ) {    if ( tp[2] == tp[0] ) {      val = 0.0;      /* add the value of this set.      */      val += stratpoints[pungbase];      /* if we're trying for a no score hand, scoring pairs are bad */      if ( is_doubler(tp[0]) ) val += (-strat->chowness)  * 6.0;      if ( is_major(tp[0]) ) { 	val += 2.0;      } else {	val -= 25.0*strat->majorness;      }      if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) 	val *= stratpoints[suitfactor];      if ( debugeval > 1 ) {	printf("%sPu%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);      }      /* remove the tiles and recurse */      tcopy(copy,tp);      copy[0] = copy[1] = copy[2] = HiddenTile;      valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&ppr,breadth);      if ( debugeval > 1 ) {	sprintf(tb,"%4.1f",val);	strncpy(&totbuf[11*reclevel],tb,4);      }      val += valr;      if ( val > pval ) { pval = val; pvalr = valr ; }    } else {      val = 0.0;      /* A pair is worth something for itself, plus something	 for its chances of becoming a pung.	 A doubler pair is worth an extra 2 points.	 A major pair is worth an extra point.	 Beware the risk of arranging effect that a chow and 	 a pair is worth much more than a pung and an inner sequence,	 so that we'd break a pung rather than a chow.      */      ppr++;      val += stratpoints[partpung]*stratpoints[pungbase] * tilesleft[tp[0]];      /* doublers are bad for noscore */      if ( is_doubler(tp[0]) ) val += 2 - (strat->chowness)*4.0;      if ( is_major(tp[0]) ) {	val += 1.0;      } else {	val -= 12.0*strat->majorness;      }      if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) 	val *= stratpoints[suitfactor];      if ( debugeval > 1 ) {	printf("%sPr%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);      }      /* remove the tiles and recurse */      tcopy(copy,tp);      copy[0] = copy[1] = HiddenTile;      (*ninc)++;      valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&ppr,breadth);      val += valr;      if ( debugeval > 1 ) {	sprintf(tb,"%4.1f",val);	strncpy(&totbuf[11*reclevel],tb,4);      }      if ( val > pval ) { pval = val; pvalr = valr; }    }  }  /* OK, now deal with chows. */  mpr = 0;  if ( is_suit(tp[0]) ) {    Tile t1,t2; int i1,i2; /* other tiles, and their indices */    /* NB tiles are in reverse order!!!!! */    t1 = ((value_of(tp[0]) > 1) ? tp[0]-1 : 0);    t2 = ((value_of(tp[0]) > 2) ? tp[0]-2 : 0);    for (i1=0;t1 && tp[i1] && tp[i1]!=t1;i1++);    if ( ! tp[i1] ) i1=0;    for (i2=0;t2 && tp[i2] && tp[i2]!=t2;i2++);    if ( ! tp[i2] ) i2=0;    /* if we have a chow */    if ( i1 && i2 ) {      val = 0.0;      /* A chow is deemed to be worth 12 points also.	 (Quick and dirty ... hike pungbonus to avoid chows.)      */     val += stratpoints[chowbase];      if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) 	val *= stratpoints[suitfactor];     if ( debugeval > 1 ) {       if ( notfirst ) printf("%s%s",prefix,&totbuf[11*reclevel]);       printf("%sCh%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);     }      /* remove the tiles and recurse */      tcopy(copy,tp);      copy[0] = copy[i1] = copy[i2] = HiddenTile;      valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&mpr,breadth);      val += valr;      if ( debugeval > 1 ) {	sprintf(tb,"%4.1f",val);	strncpy(&totbuf[11*reclevel],tb,4);      }      if ( val > mval ) { mval = val; mvalr = valr; }    }    /* If we have an inner sequence... note that it's intentional       that we do this as well, since maybe if we split the chow,       we'll find a pung. But we'    */    if ( i1 ) {      val = 0.0;      /* An inner sequence is worth the number of chances of completion,	 allowing for the fact that on average, the tiles in right	 and opposite and half the tiles in the wall will not be available	 for completing a chow.	 NOTE: this needs to change when we're nearly at MahJong.      */      val += stratpoints[seqbase];      if ( value_of(tp[0]) < 9 ) {	val += stratpoints[partchow]*stratpoints[chowbase] * tilesleft[tp[0]+1];      }      if ( value_of(t1) > 1 ) {	val += stratpoints[partchow]*stratpoints[chowbase] * tilesleft[t1-1];      }      if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) 	val *= stratpoints[suitfactor];      if ( debugeval > 1 ) {	if ( notfirst ) printf("%s%s",prefix,&totbuf[11*reclevel]);	printf("%sIn%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);      }      /* remove the tiles and recurse */      tcopy(copy,tp);      copy[0] = copy[i1] = HiddenTile;      valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&mpr,breadth);      val += valr;      if ( debugeval > 1 ) {	sprintf(tb,"%4.1f",val);	strncpy(&totbuf[11*reclevel],tb,4);      }      if ( val > mval ) { mval = val; mvalr = valr; }    }    /* If we have a split sequence ... Here we don't do this if there's       been a chow. Hmm, why not? I thought I had a reason. Fill it in       sometime. */    else if ( i2 ) {      val = 0.0;      /* Likewise */      val += stratpoints[seqbase];      val += stratpoints[partchow]*stratpoints[chowbase] * tilesleft[t1];      if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) 	val *= stratpoints[suitfactor];      if ( debugeval > 1 ) {	if ( notfirst ) printf("%s%s",prefix,&totbuf[11*reclevel]);	printf("%sOu%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);      }      /* remove the tiles and recurse */      tcopy(copy,tp);      copy[0] = copy[i2] = HiddenTile;      valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&mpr,breadth);      val += valr;      if ( debugeval > 1 ) {	sprintf(tb,"%4.1f",val);	strncpy(&totbuf[11*reclevel],tb,4);      }      if ( val > mval ) { mval = val; mvalr = valr; }    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -