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

📄 player.c

📁 支持网络和单机的麻将游戏
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Header: /home/jcb/newmj/RCS/player.c,v 11.3 2002/03/30 22:49:22 jcb Rel $ * player.c * Implements functions on players. *//****************** COPYRIGHT STATEMENT ********************** * This file is Copyright (c) 2000 by J. C. Bradfield.       * * Distribution and use is governed by the LICENCE file that * * accompanies this file.                                    * * The moral rights of the author are asserted.              * *                                                           * ***************** DISCLAIMER OF WARRANTY ******************** * This code is not warranted fit for any purpose. See the   * * LICENCE file for further information.                     * *                                                           * *************************************************************/static const char rcs_id[] = "$Header: /home/jcb/newmj/RCS/player.c,v 11.3 2002/03/30 22:49:22 jcb Rel $";#define PLAYER_C /* so that PlayerP is not const */#include "player.h"#include "sysdep.h"/* At present, this function is not exported. If it becomes   exported, the name should perhaps be made better.   player_has_mah_jong: return true if the player's hand in its   current state of organization is a complete mah-jong hand.   (That is, the hand has been organized into four sets and a pair, etc.)   The last arg is flags for seven pairs etc.*/static int player_has_mah_jong(PlayerP p,MJSpecialHandFlags flags);/* utility function: copy player record into (already allocated)   space. Returns new (for consistency with memcpy) */PlayerP copy_player(PlayerP new,const PlayerP old) {  return (PlayerP) memcpy((void *)new, (void *)old, sizeof(Player));}  int num_tiles_in_set(TileSetP tp) {  switch ( tp->type ) {  case Empty:    return 0;  case Pair:  case ClosedPair:    return 2;  case Chow:  case ClosedChow:  case Pung:  case ClosedPung:    return 3;  case Kong:  case ClosedKong:    return 4;  default:    warn("num_tiles_in_set: unknown tile set type %d\n",tp->type);    /* this will cause chaos, but that's the idea ... */    return -1;  }}void initialize_player(PlayerP p) {  p->err = NULL;  p->id = 0;  p->name = NULL;  p->wind = UnknownWind;  p->flags = 0;  p->cumulative_score = 0;  player_newhand(p,UnknownWind);}void player_newhand(PlayerP p,TileWind w) {  int i;  p->err = NULL;  p->wind = w;  p->num_concealed = 0;  for ( i = 0; i < MAX_CONCEALED; i++ ) (p->concealed)[i] = HiddenTile;  for ( i = 0; i < MAX_TILESETS; i++ ) {    (p->tilesets)[i].type = Empty;    (p->tilesets)[i].tile = HiddenTile;    (p->tilesets)[i].annexed = 0;  }  p->num_specials = 0;  for ( i = 0; i < 8; i++ ) (p->specials)[i] = HiddenTile;  psetflag(p,Hidden);  pclearflag(p,HandDeclared);  pclearflag(p,MahJongged);  psetflag(p,NoDiscard);  pclearflag(p,Calling);  pclearflag(p,OriginalCall);  for (i=0; i < NUM_SEATS; i++) p->dflags[i] = 0;  p->hand_score = -1;}void set_player_id(PlayerP p, int id) {  p->err = NULL;  p->id = id;}void set_player_name(PlayerP p, const char *n) {  p->err = NULL;  if ( p->name ) free(p->name);  if ( n ) {    p->name = (char *)malloc(strlen(n)+1);    strcpy(p->name,n);  } else p->name = (char *)0;}void set_player_cumulative_score(PlayerP p, int s) {  p->err = NULL;  p->cumulative_score = s;}void change_player_cumulative_score(PlayerP p, int d) {  p->err = NULL;  p->cumulative_score += d;}void set_player_hand_score(PlayerP p, int h) {  p->err = NULL;  p->hand_score = h;}void set_player_userdata(PlayerP p, void *ud) {  p->err = NULL;  p->userdata = ud;}/* utility functions. Maybe they should be exported.   But we should probably adhere to the convention that exported   functions do not leave data structures in intermediate states,   as these do.*//* player_count_tile: looks for copies of t in p's concealed tiles.   returns number found or -1 on error.   Should not be called on unknown players.*/int player_count_tile(PlayerP p, Tile t) {  int n,i;  p->err = NULL;  if ( pflag(p,Hidden) ) {    p->err = "Can't count tiles of hidden player";    return -1;  }  for ( i = 0, n = 0 ; i < p->num_concealed ; i++ ) {    if ( p->concealed[i] == t ) n++ ;  }  return n;}/* add_tile: adds t to p's concealed tiles. Should not be called   on hidden players.*/static int add_tile(PlayerP p, Tile t) {  assert(!pflag(p,Hidden)); /* nonsense to call this on hidden player */  assert(p->num_concealed < MAX_CONCEALED);  p->concealed[p->num_concealed++] = t;  return 1;}/* remove_tile: removes one instance of t from p's concealed tiles.   Returns 1 on success, 0 on failure.   Should not be called on hidden players.*/static int remove_tile(PlayerP p, Tile t) {  int i;  assert(!pflag(p,Hidden)); /* nonsense to call this on hidden player */  i = 0;  while ( i < p->num_concealed && p->concealed[i] != t ) i++ ;  if ( i == p->num_concealed ) return 0;  while ( i+1 < p->num_concealed ) {    p->concealed[i] = p->concealed[i+1];    i++ ;  }  p->num_concealed -= 1 ;  return 1;}/* add_tileset: adds a tile set of type ty and tile t to p.   Returns 1 on success, 0 on failure.   Always sets the annexed flag to 0.*/static int add_tileset(PlayerP p, TileSetType ty, Tile t) {  int s = 0;  while ( s < MAX_TILESETS && p->tilesets[s].type != Empty ) s++ ;  assert(s < MAX_TILESETS); /* serious problem if run out of slots */  p->tilesets[s].type = ty;  p->tilesets[s].tile = t;  p->tilesets[s].annexed = 0;  return 1;}int player_draws_tile(PlayerP p, Tile t) {  p->err = NULL;  if ( p->num_concealed == 0 ) {    if ( t == HiddenTile ) psetflag(p,Hidden);    else pclearflag(p,Hidden);  }  if ( pflag(p,Hidden) ) p->num_concealed++;  else {    if ( t == HiddenTile ) {      p->err = "player_draws_tile: HiddenTile, but we know the player!";      return 0;    }    if ( add_tile(p,t) == 0 ) {      p->err = "player_draws_tile: add_tile failed";      return 0;    }  }  return 1;}int player_draws_loose_tile(PlayerP p, Tile t) {  p->err = NULL;  if ( pflag(p,Hidden) ) p->num_concealed++;  else {    if ( t == HiddenTile ) {      p->err = "player_draws_loose_tile: HiddenTile, but we know the player!";      return 0;    }    if ( add_tile(p,t) == 0 ) {      p->err = "player_draws_loose_tile: add_tile failed";      return 0;    }  }  return 1;}/* NOTE: it is a required feature of the following functions that   if they fail, they leave the player structure unchanged. *//* implements the two following functions */static int int_pds(PlayerP p, Tile spec, int testonly) {  p->err = NULL;  if ( ! is_special(spec) ) {    p->err = "player_declares_special: the special tile isn't special\n";    return 0;  }  /* paranoid, but why not? */  if ( p->num_specials == 8 ) {    p->err = "player_declares_special: player already has all specials!";    return 0;  }  if ( pflag(p,Hidden) ) {    if ( p->num_concealed < 1 ) {      p->err = "player_can_declare_special: player has no tiles\n";      return 0;    }    if ( testonly ) return 1;    p->specials[p->num_specials++] = spec;    p->num_concealed--;    return 1;  }  if ( player_count_tile(p,spec) < 1 ) return 0;  if ( testonly ) return 1;  /* now do it */  p->specials[p->num_specials++] = spec;  remove_tile(p,spec);  return 1;}int player_declares_special(PlayerP p, Tile spec) {  return int_pds(p,spec,0);}int player_can_declare_special(PlayerP p, Tile spec) {  return int_pds(p,spec,1);}/* implements the several pung functions.   Determines whether p can use d to form a pung; and if not testonly,   does it.   If the last arg is 0, then d is a discard; otherwise, if the last arg is    1, d is also to be found in hand, and we are forming a closed pung   (this is used in scoring).*/   static int int_pp(PlayerP p, Tile d, int testonly, int tileinhand) {  p->err = NULL;  if ( pflag(p,Hidden) ) {    /* just assume it can be done */    if ( p->num_concealed < (tileinhand ? 3 : 2) ) {      p->err = "player_pungs: can't pung with too few concealed tiles\n";      return 0;    }    if ( testonly ) return 1;    p->num_concealed -= (tileinhand ? 3: 2);    add_tileset(p,(tileinhand ? ClosedPung : Pung),d);    if ( p->num_concealed == 0 ) psetflag(p,HandDeclared);    return 1;  }  /* otherwise, we know the player, and need to check legality */  if ( player_count_tile(p,d) < (tileinhand ? 3 : 2) ) {    p->err = "player_pungs: not enough matching tiles\n";    return 0;  }  /* OK, it's legal */  if ( testonly ) return 1;  /* add the tileset */  add_tileset(p, (tileinhand ? ClosedPung : Pung), d);  /* remove the tiles from the hand */  remove_tile(p,d);  remove_tile(p,d);  if ( tileinhand ) remove_tile(p,d);  if ( p->num_concealed == 0 ) psetflag(p,HandDeclared);  return 1;}int player_pungs(PlayerP p, Tile d) {  return int_pp(p,d,0,0);}int player_can_pung(PlayerP p, Tile d) {  return int_pp(p,d,1,0);}  int player_forms_closed_pung(PlayerP p, Tile d) {  return int_pp(p, d, 0, 1);}int player_can_form_closed_pung(PlayerP p, Tile d) {  return int_pp(p, d, 1, 1);}/* likewise implements the several pair functions.   Determines whether p can use d to form a pair; and if not testonly,   does it.   If the last arg is 0, then d is a discard; otherwise, if the last arg is    1, d is also to be found in hand, and we are forming a closed pair   (this is used in scoring).*/   static int int_ppr(PlayerP p, Tile d, int testonly, int tileinhand) {  p->err = NULL;    if ( pflag(p,Hidden) ) {    /* just assume it can be done */    if ( p->num_concealed < (tileinhand ? 2 : 1) ) {      p->err = "player_pairs: can't pair with too few concealed tiles\n";      return 0;    }    p->num_concealed -= (tileinhand ? 2: 1);    add_tileset(p,(tileinhand ? ClosedPair : Pair),d);    if ( p->num_concealed == 0 ) psetflag(p,HandDeclared);    return 1;  }  /* otherwise, we know the player, and need to check legality */  if ( player_count_tile(p,d) < (tileinhand ? 2 : 1) ) {    p->err = "player_pairs: not enough matching tiles\n";    return 0;  }  /* OK, it's legal */  if ( testonly ) return 1;  /* add the tileset */  add_tileset(p, (tileinhand ? ClosedPair : Pair), d);  /* remove the tiles from the hand */  remove_tile(p,d);  if ( tileinhand ) remove_tile(p,d);  if ( p->num_concealed == 0 ) psetflag(p,HandDeclared);  return 1;}int player_pairs(PlayerP p, Tile d) {  return int_ppr(p,d,0,0);}int player_can_pair(PlayerP p, Tile d) {  return int_ppr(p,d,1,0);}int player_forms_closed_pair(PlayerP p, Tile t) {  return int_ppr(p,t,0,1);}int player_can_form_closed_pair(PlayerP p, Tile t) {  return int_ppr(p,t,1,1);}  /* implements several following functions;   testonly and tileinhand as before */static int int_pk(PlayerP p, Tile d, int testonly, int tileinhand) {  p->err = NULL;  if ( pflag(p,Hidden) ) {    /* just assume it can be done */    if ( p->num_concealed < (tileinhand ? 4 : 3) ) {      p->err = "player_kongs: can't kong with too few concealed tiles\n";      return 0;    }    p->num_concealed -= (tileinhand ? 4 : 3); /* lose three/four, gain replacement */    add_tileset(p,(tileinhand ? ClosedKong : Kong), d);    return 1;  }  /* otherwise, we know the player, and need to check legality */  if ( player_count_tile(p,d) < (tileinhand ? 4 : 3) ) {    p->err = "player_kongs: not enough matching tiles\n";    return 0;  }  /* OK, it's legal */  if ( testonly ) return 1;  /* add the tileset */  add_tileset(p,(tileinhand ? ClosedKong : Kong),d);  /* remove the tiles from the hand */  remove_tile(p,d);  remove_tile(p,d);  remove_tile(p,d);  if ( tileinhand ) remove_tile(p,d);  return 1;}int player_kongs(PlayerP p, Tile d) {  return int_pk(p,d,0,0);}int player_can_kong(PlayerP p, Tile d) {  return int_pk(p, d, 1, 0);}int player_declares_closed_kong(PlayerP p, Tile d) {  return int_pk(p, d, 0, 1);}int player_can_declare_closed_kong(PlayerP p, Tile d) {  return int_pk(p, d, 1, 1);}/* Implements two following functions. */static int int_pap(PlayerP p, Tile t, int testonly) {  int i;    p->err = NULL;  /* First check that the player has an exposed pung of the tile */  for ( i=0 ; i < MAX_TILESETS ; i++ ) {    if ( p->tilesets[i].type == Pung && p->tilesets[i].tile == t )      break;  }  if ( i == MAX_TILESETS ) {    p->err = "player_adds_to_pung called with no pung";    return 0;  }  /* now check (if poss) that the tile is in hand */  if ( pflag(p,Hidden) ) {    /* can't see the tiles, so trust it */    if ( p->num_concealed < 1 ) {      /* err, this is actually impossible */      p->err = "player_adds_to_pung: no concealed tiles";      return 0;    }    /* lose one concealed tile */    p->num_concealed--;    p->tilesets[i].type = Kong;    p->tilesets[i].annexed = 1;    return 1;  }  /* otherwise, we know the player and need to check legality */  if ( player_count_tile(p,t) < 1 ) {    p->err = "player_adds_to_pung: tile not found in hand";    return 0;  }    /* OK, it's legal */  if ( testonly ) return 1;  /* modify the tileset */  p->tilesets[i].type = Kong;  p->tilesets[i].annexed = 1;  /* remove the tile from the hand */  remove_tile(p,t);  return 1;}int player_adds_to_pung(PlayerP p, Tile t) {  return int_pap(p,t,0);}int player_can_add_to_pung(PlayerP p,Tile t) {  return int_pap(p,t,1);}/* player_kong_robbed: the player has formed a kong of t, and it is robbed */int player_kong_is_robbed(PlayerP p, Tile t) {  int i;  p->err = NULL;  /* find the kong in question */  for ( i=0 ; i < MAX_TILESETS ; i++ ) {    if ( p->tilesets[i].tile == t 	 && ( p->tilesets[i].type == Kong	      || p->tilesets[i].type == ClosedKong ) )      break;  }  if ( i == MAX_TILESETS ) {    p->err = "player_kong_is_robbed called with no kong";    return 0;  }  /* and downgrade it */  if ( p->tilesets[i].type == Kong ) p->tilesets[i].type = Pung ;  else p->tilesets[i].type = ClosedPung;  p->tilesets[i].annexed = 0;  return 1;}/* the chow handling function */static int int_pc(PlayerP p, Tile d, ChowPosition r, int testonly, int tileinhand) {  Tile low, mid, high;  p->err = NULL;  if ( ! is_suit(d) ) {    p->err = "Can't chow a non-suit tile\n";    return 0;  }  if ( r == AnyPos ) {    if ( !testonly ) {      p->err = "Can't make a chow with AnyPos";      return 0;    }    return

⌨️ 快捷键说明

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