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

📄 player.c

📁 支持网络和单机的麻将游戏
💻 C
📖 第 1 页 / 共 2 页
字号:
      int_pc(p,d,Lower,testonly,tileinhand)      || int_pc(p,d,Middle,testonly,tileinhand)      || int_pc(p,d,Upper,testonly,tileinhand);  }  if ( r == Lower ) {    if ( value_of(d) > 7 ) {      p->err = "Impossible chow\n";      return 0;    }    low = d;    mid = d+1;    high = d+2;  } else if ( r == Middle ) {    if ( value_of(d) == 1 || value_of(d) == 9 ) {      p->err = "Impossible chow\n";      return 0;    }    mid = d;    low = d-1;    high = d+1;  } else /* r == Upper */ {    if ( value_of(d) < 3 ) {      p->err = "Impossible chow\n";      return 0;    }    high = d;    mid = d-1;    low = d-2;  }  if ( pflag(p,Hidden) ) {    if ( testonly ) return 1;    p->num_concealed -= (tileinhand ? 3 : 2);    add_tileset(p,(tileinhand ? ClosedChow : Chow),low);    if ( p->num_concealed == 0 ) psetflag(p,HandDeclared);    return 1;  }  /* Check we have the tiles */  if ( tileinhand || r != Lower ) {    if ( player_count_tile(p,low) < 1 ) {      p->err = "Don't have the other tiles for the chow";      return 0;    }  }  if ( tileinhand || r != Middle ) {    if ( player_count_tile(p,mid) < 1 ) {      p->err = "Don't have the other tiles for the chow";      return 0;    }  }  if ( tileinhand || r != Upper ) {    if ( player_count_tile(p,high) < 1 ) {      p->err = "Don't have the other tiles for the chow";      return 0;    }  }  /* OK, we're ready to go */  if ( testonly ) return 1;  /* this might fail if the state is inconsistent, in which case     we should leave p unchanged. Hence it comes first.  */  if ( !add_tileset(p,(tileinhand ? ClosedChow : Chow),low) ) {    p->err = "int_pc: add_tileset failed!";    return 0;  }  /* remove the tiles */   if ( tileinhand || r != Lower ) {    remove_tile(p,low);  }  if ( tileinhand || r != Middle ) {    remove_tile(p,mid);  }  if ( tileinhand || r != Upper ) {    remove_tile(p,high);  }  if ( p->num_concealed == 0 ) psetflag(p,HandDeclared);  return 1;}int player_chows(PlayerP p, Tile d, ChowPosition r) {  return int_pc(p,d,r,0,0);}int player_can_chow(PlayerP p, Tile d, ChowPosition r) {  return int_pc(p,d,r,1,0);}int player_forms_closed_chow(PlayerP p, Tile d, ChowPosition r) {  return int_pc(p,d,r,0,1);}int player_can_form_closed_chow(PlayerP p, Tile d, ChowPosition r) {  return int_pc(p,d,r,1,1);}/* discarding a tile */static int int_pd(PlayerP p, Tile t, int testonly) {  p->err = NULL;  if ( pflag(p,Hidden) ) {    if ( p->num_concealed < 1 ) {      p->err = "No tiles to discard!\n";      return 0;    }    if ( testonly ) return 1;    p->num_concealed -= 1;    return 1;  }  if ( player_count_tile(p,t) < 1 ) {    p->err = "Tile not found in hand\n";    return 0;  }  if ( testonly ) return 1;  remove_tile(p,t);  pclearflag(p,NoDiscard);  return 1;}int player_discards(PlayerP p, Tile t) {  return int_pd(p,t,0);}int player_can_discard(PlayerP p, Tile t) {  return int_pd(p,t,1);}/* player_can_mah_jong: determine whether this hand (perhaps with   an added discard tile) is a mah-jong hand.   This function is completely brain-dead about finding a possible   mah jong; given the small search space, there seems no point in   being at all clever.*/int player_can_mah_jong(PlayerP p,Tile d,MJSpecialHandFlags flags) {  Player pcopy; /* we will manipulate this copy of the player */  PlayerP pcp = &pcopy;  int answer = 0;  Tile t;  p->err = NULL;  /* Technique is depth-first search of possible hands: just     try applying making all possible tilesets until we succeed */  /* The base case of the recursion */  if ( d == HiddenTile && p->num_concealed <= 1 ) {    answer = player_has_mah_jong(p,flags);    goto done;  }  /* otherwise, try making tilesets.     First deal with the discard tile, if it exists.     For each possible way of using the discard,     make a copy of the player, use the discard, and see     if the result is mah-jongable.  */  if ( d != HiddenTile ) {    copy_player(pcp,p);    answer = (player_pungs(pcp,d)	      && player_can_mah_jong(pcp,HiddenTile,flags));    if (answer) goto done;    copy_player(pcp,p);    answer = (player_chows(pcp,d,Lower)	      && player_can_mah_jong(pcp,HiddenTile,flags));    if (answer) goto done;    copy_player(pcp,p);    answer = (player_chows(pcp,d,Middle)	      && player_can_mah_jong(pcp,HiddenTile,flags));    if (answer) goto done;    copy_player(pcp,p);    answer = (player_chows(pcp,d,Upper)	      && player_can_mah_jong(pcp,HiddenTile,flags));    if (answer) goto done;    copy_player(pcp,p);    answer = (player_pairs(pcp,d)	      && player_can_mah_jong(pcp,HiddenTile,flags));    goto done;  } else {    /* otherwise, for each concealed tile, try making something of it */    int i;    for ( i = 0; i < p->num_concealed; i++ ) {      t = p->concealed[i];      copy_player(pcp,p);      answer = (player_forms_closed_pung(pcp,t)		&& player_can_mah_jong(pcp,HiddenTile,flags));      if (answer) goto done;      copy_player(pcp,p);      answer = (player_forms_closed_chow(pcp,t,Lower)		&& player_can_mah_jong(pcp,HiddenTile,flags));      if (answer) goto done;            copy_player(pcp,p);      answer = (player_forms_closed_pair(pcp,t)		&& player_can_mah_jong(pcp,HiddenTile,flags));      if (answer) goto done;    }  } done:  /* if all else fails, try 13 unique wonders */  if ( (! answer)       && ((p->num_concealed == 13 && d != HiddenTile)	   || (p->num_concealed == 14 && d == HiddenTile)))    answer = player_can_thirteen_wonders(p,d);  return answer;}/* does the player have 13 unique wonders? */int player_can_thirteen_wonders(PlayerP p, Tile d) {  Player pcopy; /* we will manipulate this copy of the player */  PlayerP pcp = &pcopy;  int answer = 0;  int i, havetwo, n;  if ( d != HiddenTile ) {    copy_player(pcp,p);    answer = (player_draws_tile(pcp,d)	      && player_can_thirteen_wonders(pcp,HiddenTile));  } else {    answer = 1;    havetwo = 0;    for ( i=0; i < 13; i++ ) {      n = player_count_tile(p,thirteen_wonders[i]);      if ( n > 2 ) { answer = 0; break; }      else if ( n == 2 ) {	if ( havetwo ) { answer = 0; break; }	else { havetwo = 1; }      } else if ( n == 0 ) { answer = 0; break; }    }  }  return answer;}/* This internal function defines the mah jong hands.   (Currently it does not include thirteen wonders).   Last arg allows seven pairs etc.*/static int player_has_mah_jong(PlayerP p,MJSpecialHandFlags flags) {  int i,s,n;  int answer;  p->err = NULL;  /* all tiles must be in sets */  if ( p->num_concealed > 0 ) return 0;  answer = 0;  /* there must be exactly  five non-empty sets, exactly     one of which must be a pair */  for (i=0, n=0, s=0; i<MAX_TILESETS; i++) {    if ( p->tilesets[i].type != Empty ) s++;    if ( num_tiles_in_set(&(p->tilesets[i])) == 2) n++;  }  if ( s == 5 && n == 1 ) answer = 1;  /* seven pairs may be allowed */  if ( (flags & MJSevenPairs) && s == 7 && n == 7 ) answer = 1;  /* that's it */  return answer;}  /* sort the player's concealed tiles.*/void player_sort_tiles(PlayerP p) {  int nconc; int i,j;  Tile *tp = p->concealed;  Tile t;  p->err = NULL;  if ( pflag(p,Hidden) ) return; /* pretty dumb ... */  nconc = p->num_concealed;  /* bubble sort */  for ( i = 0 ; i < nconc-1 ; i++ ) {    if ( tp[i+1] < tp[i] ) {      /* sink it to the bottom */      for ( j = i+1 ; tp[j] < tp[j-1] && j > 0 ; j-- ) {	t = tp[j-1]; tp[j-1] = tp[j]; tp[j] = t;      }    }  }}/* This function generates a string repn of a players tiles. */void player_print_tiles(char *buf, PlayerP p, int hide) {  int i,j;  Tile *tp; Tile t;  Tile ctiles[MAX_CONCEALED]; int nconc;    p->err = NULL;  if ( pflag(p,Hidden) ) hide = 1; /* can't see the tiles anyway */  /* copy the concealed files and sort them.     This assumes knowledge that Tiles are shorts.  */  nconc = p->num_concealed;  if ( ! hide ) {    memcpy(ctiles,p->concealed,nconc*sizeof(Tile));    tp = ctiles;    /* bubble sort */    for ( i = 0 ; i < nconc-1 ; i++ ) {      if ( tp[i+1] < tp[i] ) {	/* sink it to the bottom */	for ( j = i+1 ; tp[j] < tp[j-1] && j > 0 ; j-- ) {	  t = tp[j-1]; tp[j-1] = tp[j]; tp[j] = t;	}      }    }  }  buf[0] = '\000' ;  for (i=0; i < nconc; i++) {    if ( i > 0 ) strcat(buf," ");    strcat(buf, hide ? "--" : tile_code(ctiles[i]));  }  strcat(buf," *");    for (i = 0; i<MAX_TILESETS; i++) {    if ( p->tilesets[i].type == Empty ) continue;    strcat(buf," ");    strcat(buf,tileset_string(&p->tilesets[i]));  }  strcat(buf," * ");  for (i=0; i < p->num_specials; i++) {    if ( i > 0 ) strcat(buf," ");    strcat(buf,tile_code(p->specials[i]));  }}int set_player_tiles(PlayerP p,char *desc) {  int i = 0;  char tc[3]; /* for tile codes */  int ts;  int closed, annexed;  Tile tile;  TileSetType ttype;    p->err = NULL;  /* clear the current information */  p->num_concealed = 0;  for (i=0; i < MAX_TILESETS ; i++) p->tilesets->type = Empty;  p->num_specials = 0;  pclearflag(p,Hidden);    while ( *desc && isspace(*desc) ) desc++;  /* read the tiles in hand */  while ( *desc && *desc != '*' ) {    tc[0] = *(desc++);    tc[1] = *(desc++);    tc[2] = '\000';    tile = tile_decode(tc);    if ( tile == ErrorTile ) {      warn("format error in set_player_tile");      return 0;    }    if ( tile == HiddenTile ) {      p->num_concealed++;      psetflag(p,Hidden);    } else {      p->concealed[p->num_concealed++] = tile;    }    while ( *desc && isspace(*desc) ) desc++;  }  if ( ! *desc ) {    warn("format error in set_player_tiles");    return 0;  }  desc++; /* skip the * */  while ( *desc && isspace(*desc) ) desc++;  /* parse the tilesets */  ts = 0;  while ( *desc && *desc != '*' ) {    annexed = 0;    closed = 0;    tc[0] = *(desc++);    tc[1] = *(desc++);    tc[2] = 0;    tile = tile_decode(tc);    if ( tile == ErrorTile ) {      warn("format error in set_player_tiles");      return 0;    }    if ( *(desc++) == '+' ) closed = 1;    /* we're lazy now: if the next tile is different,       we know it's a chow; otherwise we just skip to        the next white space, counting letters */    tc[0] = *(desc++);    tc[1] = *(desc++);    if ( tile_decode(tc) != tile ) {      ttype = closed ? ClosedChow : Chow;      desc += 3; /* skip last tile */    } else if ( isspace(*desc) ) {      /* two tiles; it's a pair */      ttype = closed ? ClosedPair : Pair;    } else {      /* skip next tile */      desc += 3;      if ( isspace(*desc) ) {	/* it's a pung */	ttype = closed ? ClosedPung : Pung;      } else {	/* it's a kong */	ttype = closed ? ClosedKong : Kong;	/* millington rules ? */	if ( ! closed )	  annexed = (*desc == '-');	desc += 3;      }    }    p->tilesets[ts].type = ttype;    p->tilesets[ts].tile = tile;    p->tilesets[ts].annexed = annexed;    ts++;    while ( *desc && isspace(*desc) ) desc++;  } /* end of matching tilesets loop */  if ( ! *desc ) {    warn("format error in set_player_tiles");    return 0;  }  desc++; /* skip the * */  while ( *desc && isspace(*desc) ) desc++;  /* parse the specials */  while ( *desc && *desc != '*' ) {    tc[0] = *(desc++);    tc[1] = *(desc++);    tc[2] = '\000';    tile = tile_decode(tc);    if ( tile == ErrorTile ) {      warn("format error in set_player_tile");      return 0;    }    p->specials[p->num_specials++] = tile;    while ( *desc && isspace(*desc) ) desc++;  }  /* phew */  return 1;}int player_shows_tiles(PlayerP p, char *desc) {  char tc[3];  Tile tile;    p->err = NULL;  /* If the player is not hidden, then we needn't     do anything to the tiles */  if ( pflag(p,Hidden) ) {    /* clear the current information */    p->num_concealed = 0;    pclearflag(p,Hidden);        while ( *desc && isspace(*desc) ) desc++;    /* read the tiles in hand */    while ( *desc ) {      tc[0] = *(desc++);      tc[1] = *(desc++);      tc[2] = '\000';      tile = tile_decode(tc);      if ( tile == ErrorTile ) {	warn("format error in player_shows_tiles");	return 0;      }      p->concealed[p->num_concealed++] = tile;      while ( *desc && isspace(*desc) ) desc++;    }  }  psetflag(p,HandDeclared);  return 1;}/* player_swap_tile: swaps the oldtile for the newtile in the   concealed tiles. Only used in testing, of course */int player_swap_tile(PlayerP p, Tile oldtile, Tile newtile) {  p->err = NULL;  if ( ! remove_tile(p,oldtile) ) {    p->err = "player doesn't have old tile";    return 0;  }  add_tile(p,newtile);  return 1;}/* return string representing a tileset */char *tileset_string(TileSetP tp) {  char *sep;  static char buf[20];  short v; TileSuit s;  int j;  buf[0] = '\000';  sep = "-";  switch ( tp->type ) {  case ClosedPung:  case ClosedKong:  case ClosedPair:    sep = "+";  case Pung:  case Kong:  case Pair:    for ( j = 0; j < num_tiles_in_set(tp); j++ ) {      if ( tp->type == Kong 	&& !tp->annexed 	&& j == num_tiles_in_set(tp) - 1 )	sep = "+";      if ( j > 0 ) strcat(buf,sep);      strcat(buf,tile_code(tp->tile));    }    break;  case ClosedChow:    sep = "+";  case Chow:    v = value_of(tp->tile);    s = suit_of(tp->tile);    strcat(buf,tile_code(tp->tile));    strcat(buf,sep);    strcat(buf,tile_code(make_tile(s,v+1)));    strcat(buf,sep);    strcat(buf,tile_code(make_tile(s,v+2)));    break;  case Empty:    /* errrr */    return "";  }  return buf;}/* enum functions */#include "player-enums.c"

⌨️ 快捷键说明

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