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

📄 greedy.c

📁 支持网络和单机的麻将游戏
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Header: /home/jcb/newmj/RCS/greedy.c,v 11.6 2003/03/30 21:33:27 jcb Rel $ * greedy.c * This is a computer player. Currently offensive only. * Options not documented. *//****************** 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/greedy.c,v 11.6 2003/03/30 21:33:27 jcb Rel $";static int debugeval = 0;#include <stdlib.h>#include <stdio.h>#include <math.h>#include "client.h"#include "sysdep.h"#include "version.h"/* is this tile a doubling tile (or scoring pair) */#define is_doubler(t) (is_dragon(t) || (is_wind(t) && \ (suit_of(t) == our_player->wind || suit_of(t) == the_game->round)))Game *the_game;int our_id = 0;PlayerP our_player;seats our_seat;/* New style strategy */typedef struct {  double chowness; /* how much do we like/dislike chows? 		      From -1.0 (no chows) to +1.0 (no pungs) */  double hiddenness; /* how much do we want to keep things concealed?			From 0.0 (don't care) to 1.0 (absolutely no claims) */  double majorness; /* are we trying to get all majors? 		       From 0.0 (don't care) to 1.0 (discard all minors) */  double suitness; /* are we trying to collect one suit? From 0.0 to 1.0 */  TileSuit suit;   /* if so, which? */} strategy;/* values to try out */typedef enum { chowness, hiddenness, majorness, suitness } stratparamtype;struct { int ncomps; double values[5]; } stratparams[suitness+1] = { { 3, { 0.0, -0.9, 0.5 } } , /* chowness */   { 2, { 0.0, 0.8 } } , /* hiddenness */   { 1, { 0.0 } } , /* majorness */   { 2, { 0.0, 0.5 } } /* suitness */ } ;/* routine to parse a comma separated list of floats into   the given strat param. Return num of comps, or -1 on error */static int parsefloatlist(const char *fl, stratparamtype spt) {  char *start, *end;  int i;  if ( ! fl ) { warn("null arg to parsefloatlist"); return -1; }  start = (char *)fl;  i = 0;  while ( i < 5 ) {    /* it is a feature that this will return zero on an empty       string, since we shd have at least one value */    stratparams[spt].values[i] = strtod(start,&end);    i++;    start = end;    if ( ! *start ) break;    if ( *start == ',' ) start++;  }  if ( *start ) warn("too many components, ignoring excess");  stratparams[spt].ncomps = i;  return i;}static strategy curstrat;/* These are names for computed strategy values. See the awful mess   below... */enum {pungbase,pairbase,chowbase,seqbase,sglbase,      partpung,partchow,exposedpungpenalty,exposedchowpenalty,      suitfactor, mjbonus, kongbonus,weight};/* the value of a new strategy must exceed the current   by this amount for it to be chosen */static double hysteresis = 4.0; /* Used to note availability of tiles */static int tilesleft[MaxTile];/* track discards of player to right */static int rightdiscs[MaxTile]; /* disc_ser of last of each tile discarded */static int strategy_chosen;static int despatch_line(char *line);static void do_something(void);static void check_discard(PlayerP p,strategy *strat);static Tile decide_discard(PlayerP p, double *score, strategy *newstrat);static void update_tilesleft(CMsgUnion *m);static void maybe_switch_strategy(strategy *strat);static double eval(Tile *tp, strategy *strat, double *stratpoints,int reclevel, int *ninc, int *npr, double *breadth);static double evalhand(PlayerP p, strategy *strat);static int chances_to_win(PlayerP p);/* copy old tile array into new */#define tcopy(new,old) memcpy((void *)new,(void *)old,(MAX_CONCEALED+1)*sizeof(Tile))/* Convenience function */#define send_packet(m) client_send_packet(the_game,(PMsgMsg *)m)static void usage(char *pname,char *msg) {  fprintf(stderr,"%s: %s\nUsage: %s [ --id N ] [ --name NAME ] [ --server ADDR ]\n\  [ undocumented options ]\n",	  pname,msg,pname);  exit(1);}int main(int argc, char *argv[]) {  char buf[1000];  char *l;  int i;  char *evalh = NULL ; /* just evaluate hand with default strategy			  and all debugging, and exit */  char *address = ":5000";  char *name = NULL;  /* options. I should use getopt ... */  for (i=1;i<argc;i++) {    if ( strcmp(argv[i],"--id") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --id");      our_id = atoi(argv[i]);    } else if ( strcmp(argv[i],"--server") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --server");      address = argv[i];    } else if ( strcmp(argv[i],"--address") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --address");      address = argv[i];    } else if ( strcmp(argv[i],"--name") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --name");      name = argv[i];    } else if ( strcmp(argv[i],"--debug") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --debug");      debugeval = atoi(argv[i]);    } else if ( strcmp(argv[i],"--eval") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --eval");      evalh = argv[i];      debugeval = 99;    } else if ( strcmp(argv[i],"--hysteresis") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --hysteresis");      hysteresis = atof(argv[i]);    } else if ( strcmp(argv[i],"--chowness") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --chowness");      parsefloatlist(argv[i],chowness);    } else if ( strcmp(argv[i],"--hiddenness") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --hiddenness");      parsefloatlist(argv[i],hiddenness);    } else if ( strcmp(argv[i],"--majorness") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --majorness");      parsefloatlist(argv[i],majorness);    } else if ( strcmp(argv[i],"--suitness") == 0 ) {      if ( ++i == argc ) usage(argv[0],"missing argument to --suitness");      parsefloatlist(argv[i],suitness);    }    else {      fprintf(stderr,argv[i]);      usage(argv[0],"unknown option or argument");    }  }  srand(time(NULL));  if ( evalh ) {    Player pp;    Game g;        g.round = EastWind;    the_game = &g;    pp.wind = EastWind;    initialize_player(&pp);    set_player_tiles(&pp,evalh);    our_player = &pp;    evalhand(&pp,&curstrat);    exit(0);  }  the_game = client_init(address);  if ( ! the_game ) exit(1);  sprintf(buf,"Robot(%d)",getpid());  client_connect(the_game,our_id,name ? name : buf);  while ( 1 ) {   l = get_line(the_game->fd);    if ( ! l ) {      exit(1);    }    despatch_line(l);  }}/* despatch_line: this is the mega-switch which deals with   the input from the controller */static int despatch_line(char *line) {  CMsgMsg *cm;  if ( line == NULL ) {    warn("receive error on controller connexion\n");    exit(1);  }  cm = decode_cmsg(line);  if ( cm == NULL ) {    warn("Protocol error on controller connexion; ignoring\n");    return 0;  }  update_tilesleft((CMsgUnion *)cm);  switch ( cm->type ) {  case CMsgError:    break; /* damn all we can do */  case CMsgGameOver:    exit(0);  case CMsgInfoTiles:    /* We ignore these. */    break;  case CMsgCanMahJong:    /* Currently we ignore these, as we don't issue queries */    break;  case CMsgConnectReply:    game_handle_cmsg(the_game,cm);    our_id = the_game->players[0]->id;    our_player = the_game->players[0];    break;    /* In these cases, our seat might have changed, so we need to calculate it */  case CMsgGame:    /* In this case, we need to ask for the game options */    {      PMsgListGameOptionsMsg plgom;      plgom.type = PMsgListGameOptions;      plgom.include_disabled = 0;      send_packet(&plgom);    }    /* and then ... */  case CMsgNewRound:  case CMsgNewHand:    game_handle_cmsg(the_game,cm);    our_seat = game_id_to_seat(the_game,our_id);    if ( debugeval ) printf("New hand\n");    /* reset strategy to default */    curstrat.chowness = stratparams[chowness].values[0];    curstrat.hiddenness = stratparams[hiddenness].values[0];    curstrat.majorness = stratparams[majorness].values[0];    curstrat.suitness = stratparams[suitness].values[0];    curstrat.suit = 0;    break;    /* in all these cases, game_handle_cmsg does all the work we want */  case CMsgPlayer:  case CMsgStopPlay:  case CMsgClaimDenied:  case CMsgPlayerDoesntClaim:  case CMsgPlayerClaimsPung:  case CMsgPlayerClaimsKong:  case CMsgPlayerClaimsChow:  case CMsgPlayerClaimsMahJong:  case CMsgPlayerShowsTiles:  case CMsgDangerousDiscard:  case CMsgGameOption:  case CMsgChangeManager:  case CMsgWall:  case CMsgComment:  case CMsgStateSaved:  case CMsgMessage:    game_handle_cmsg(the_game,cm);    break;  case CMsgHandScore:    /* if that was the winner, we should start scoring our hand */    if ( ( game_handle_cmsg(the_game,cm) 	   == the_game->players[the_game->player]->id)	 && the_game->active )      do_something();    break;    /* after a Settlement or Washout message, do something: start next hand */  case CMsgWashOut:  case CMsgSettlement:    game_handle_cmsg(the_game,cm);    if ( the_game->active ) do_something();    break;    /* likewise after a washout */    /* after a MahJong message, we should do something: namely       start making our scoring sets. */  case CMsgPlayerRobsKong:  case CMsgPlayerMahJongs:    game_handle_cmsg(the_game,cm);    if ( the_game->active ) do_something();    break;    /* in the case of a PlayerDeclaresSpecials message, we need to       do something if it is now our turn; but this isn't given       by the affected id.       However, if the state is Discarding, and no tiles have       so far been discarded, we shouldn't do something       now, since we are about to be asked to pause.    */  case CMsgPlayerDeclaresSpecial:    game_handle_cmsg(the_game,cm);    if ( the_game->player == our_seat && the_game->active	 && ! ( the_game->state == Discarding && the_game->serial == 0 ))      do_something();    break;    /* in these cases, we need to do something if the message       is addressed to us. */  case CMsgPlayerDraws:  case CMsgPlayerDrawsLoose:  case CMsgPlayerPungs:  case CMsgPlayerKongs:  case CMsgPlayerChows:  case CMsgPlayerFormsClosedPung:  case CMsgPlayerFormsClosedChow:  case CMsgPlayerPairs:  case CMsgPlayerFormsClosedPair:  case CMsgPlayerSpecialSet:  case CMsgPlayerFormsClosedSpecialSet:  case CMsgSwapTile:    if ( game_handle_cmsg(the_game,cm) == our_id && the_game->active)      do_something();    break;    /* in this case, we need to do something else if it's not our turn! */  case CMsgPlayerDiscards:    if ( game_handle_cmsg(the_game,cm) != our_id && the_game->active)      check_discard(our_player,&curstrat);    break;    /* if this is us, we need to do something, and if it's        somebody else, we might be able to rob the kong */  case CMsgPlayerDeclaresClosedKong:  case CMsgPlayerAddsToPung:    if ( game_handle_cmsg(the_game,cm) == our_id && the_game->active)      do_something();    else if ( the_game->active )       check_discard(our_player,&curstrat); /* actually this checks the kong */    break;    /* In this case, it depends on the state of the game */  case CMsgStartPlay:    /* We need to do something if the id is us, or 0. */    { int id;    id = game_handle_cmsg(the_game,cm);    if ( id == our_id || id == 0 )       do_something();    }    break;    /* similarly */  case CMsgPlayerReady:    game_handle_cmsg(the_game,cm);    if ( ! the_game->paused ) do_something();    break;  case CMsgPause:    game_handle_cmsg(the_game,cm);    do_something();    break;  case CMsgPlayerOptionSet:    /* we don't recognize any options, so ignore it */    break;

⌨️ 快捷键说明

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