1 /* $Header: /home/jcb/MahJong/newmj/RCS/greedy.c,v 12.2 2014/01/03 14:18:15 jcb Exp $
2  * greedy.c
3  * This is a computer player. Currently offensive only.
4  * Options not documented.
5  */
6 /****************** COPYRIGHT STATEMENT **********************
7  * This file is Copyright (c) 2000 by J. C. Bradfield.       *
8  * Distribution and use is governed by the LICENCE file that *
9  * accompanies this file.                                    *
10  * The moral rights of the author are asserted.              *
11  *                                                           *
12  ***************** DISCLAIMER OF WARRANTY ********************
13  * This code is not warranted fit for any purpose. See the   *
14  * LICENCE file for further information.                     *
15  *                                                           *
16  *************************************************************/
17 
18 static const char rcs_id[] = "$Header: /home/jcb/MahJong/newmj/RCS/greedy.c,v 12.2 2014/01/03 14:18:15 jcb Exp $";
19 
20 static int debugeval = 0;
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include "client.h"
25 #include "sysdep.h"
26 
27 #include "version.h"
28 
29 static double magic[28+13] =
30   {
31     12, 2, 1, 0.15, 1, 4, 4.97465626805558, 4, 1, 0.00638363133042069,
32     0, 1, 0.025, 0.4, 0.34, 0.4, 0.033333333, 0.3,
33     2, 25, 2, 25, 90.2519293502827, 3, 0.99, 1, -0.0011160627477312, 0.25,
34 
35     6.0, 2.0, 25.0, 1.0, 12.0, 0.5, 3.0, 5.0, 0.5, 0.5, 0.5, 0.5,
36     0.5 };
37 
38 static double *magic2 = &magic[28];
39 
40 
41 
42 /* is this tile a doubling tile (or scoring pair) */
43 #define is_doubler(t) (is_dragon(t) || (is_wind(t) && \
44  (suit_of(t) == our_player->wind || suit_of(t) == the_game->round)))
45 
46 Game *the_game;
47 int our_id = 0;
48 PlayerP our_player;
49 seats our_seat;
50 
51 static char *password = NULL;
52 
53 static FILE *debugf;
54 
55 /* New style strategy */
56 typedef struct {
57   double chowness; /* how much do we like/dislike chows?
58 		      From -1.0 (no chows) to +1.0 (no pungs) */
59   double hiddenness; /* how much do we want to keep things concealed?
60 			From 0.0 (don't care) to 1.0 (absolutely no claims) */
61   double majorness; /* are we trying to get all majors?
62 		       From 0.0 (don't care) to 1.0 (discard all minors) */
63   double suitness; /* are we trying to collect one suit? From 0.0 to 1.0 */
64   TileSuit suit;   /* if so, which? */
65 } strategy;
66 
67 /* values to try out */
68 typedef enum { chowness, hiddenness, majorness, suitness } stratparamtype;
69 struct { int ncomps; double values[5]; }
70  stratparams[suitness+1] =
71  { { 3, { 0.0, -0.9, 0.5 } } , /* chowness */
72    { 2, { 0.0, 0.8 } } , /* hiddenness */
73    { 1, { 0.0 } } , /* majorness */
74    { 2, { 0.0, 0.5 } } /* suitness */
75  } ;
76 
77 /* routine to parse a comma separated list of floats into
78    the given strat param. Return num of comps, or -1 on error */
parsefloatlist(const char * fl,stratparamtype spt)79 static int parsefloatlist(const char *fl, stratparamtype spt) {
80   char *start, *end;
81   int i;
82   if ( ! fl ) { warn("null arg to parsefloatlist"); return -1; }
83   start = (char *)fl;
84   i = 0;
85   while ( i < 5 ) {
86     /* it is a feature that this will return zero on an empty
87        string, since we shd have at least one value */
88     stratparams[spt].values[i] = strtod(start,&end);
89     i++;
90     start = end;
91     if ( ! *start ) break;
92     if ( *start == ',' ) start++;
93   }
94   if ( *start ) warn("too many components, ignoring excess");
95   stratparams[spt].ncomps = i;
96   return i;
97 }
98 
99 
100 
101 static strategy curstrat;
102 /* These are names for computed strategy values. See the awful mess
103    below... */
104 enum {pungbase,pairbase,chowbase,seqbase,sglbase,
105       partpung,partchow,exposedpungpenalty,exposedchowpenalty,
106       suitfactor, mjbonus, kongbonus,weight};
107 
108 /* the value of a new strategy must exceed the current
109    by this amount for it to be chosen */
110 static double hysteresis = 4.0;
111 
112 
113 /* Used to note availability of tiles */
114 static int tilesleft[MaxTile];
115 /* track discards of player to right */
116 static int rightdiscs[MaxTile]; /* disc_ser of last of each tile discarded */
117 static int strategy_chosen;
118 static int despatch_line(char *line);
119 static void do_something(void);
120 static void check_discard(PlayerP p,strategy *strat,int closed_kong);
121 static Tile decide_discard(PlayerP p, double *score, strategy *newstrat);
122 static void update_tilesleft(CMsgUnion *m);
123 static void maybe_switch_strategy(strategy *strat);
124 static double eval(Tile *tp, strategy *strat, double *stratpoints,int reclevel, int *ninc, int *npr, double *breadth);
125 static double evalhand(PlayerP p, strategy *strat);
126 static int chances_to_win(PlayerP p);
127 /* copy old tile array into new */
128 #define tcopy(new,old) memcpy((void *)new,(void *)old,(MAX_CONCEALED+1)*sizeof(Tile))
129 /* Convenience function */
130 #define send_packet(m) client_send_packet(the_game,(PMsgMsg *)m)
131 
usage(char * pname,char * msg)132 static void usage(char *pname,char *msg) {
133   fprintf(stderr,"%s: %s\nUsage: %s [ --id N ] [ --name NAME ] [ --password PASSWORD ] [ --server ADDR ]\n\
134   [ strategy options ]\n",
135 	  pname,msg,pname);
136   exit(1);
137 }
138 
main(int argc,char * argv[])139 int main(int argc, char *argv[]) {
140   char buf[1000];
141   char *l;
142   int i;
143   char *evalh = NULL ; /* just evaluate hand with default strategy
144 			  and all debugging, and exit */
145   char *address = ":5000";
146   char *name = NULL;
147 
148   debugf = stderr;
149 
150   /* options. I should use getopt ... */
151   for (i=1;i<argc;i++) {
152     if ( strcmp(argv[i],"--id") == 0 ) {
153       if ( ++i == argc ) usage(argv[0],"missing argument to --id");
154       our_id = atoi(argv[i]);
155     } else if ( strcmp(argv[i],"--server") == 0 ) {
156       if ( ++i == argc ) usage(argv[0],"missing argument to --server");
157       address = argv[i];
158     } else if ( strcmp(argv[i],"--address") == 0 ) {
159       if ( ++i == argc ) usage(argv[0],"missing argument to --address");
160       address = argv[i];
161     } else if ( strcmp(argv[i],"--name") == 0 ) {
162       if ( ++i == argc ) usage(argv[0],"missing argument to --name");
163       name = argv[i];
164     } else if ( strcmp(argv[i],"--password") == 0 ) {
165       if ( ++i == argc ) usage(argv[0],"missing argument to --password");
166       password = argv[i];
167     } else if ( strcmp(argv[i],"--debug") == 0 ) {
168       if ( ++i == argc ) usage(argv[0],"missing argument to --debug");
169       debugeval = atoi(argv[i]);
170     } else if ( strcmp(argv[i],"--eval") == 0 ) {
171       if ( ++i == argc ) usage(argv[0],"missing argument to --eval");
172       evalh = argv[i];
173       debugeval = 99;
174     } else if ( strcmp(argv[i],"--hysteresis") == 0 ) {
175       if ( ++i == argc ) usage(argv[0],"missing argument to --hysteresis");
176       hysteresis = atof(argv[i]);
177     } else if ( strcmp(argv[i],"--chowness") == 0 ) {
178       if ( ++i == argc ) usage(argv[0],"missing argument to --chowness");
179       parsefloatlist(argv[i],chowness);
180     } else if ( strcmp(argv[i],"--hiddenness") == 0 ) {
181       if ( ++i == argc ) usage(argv[0],"missing argument to --hiddenness");
182       parsefloatlist(argv[i],hiddenness);
183     } else if ( strcmp(argv[i],"--majorness") == 0 ) {
184       if ( ++i == argc ) usage(argv[0],"missing argument to --majorness");
185       parsefloatlist(argv[i],majorness);
186     } else if ( strcmp(argv[i],"--suitness") == 0 ) {
187       if ( ++i == argc ) usage(argv[0],"missing argument to --suitness");
188       parsefloatlist(argv[i],suitness);
189     } else if ( strcmp(argv[i],"--magic") == 0 ) {
190       FILE *f;
191       unsigned int j;
192       if ( ++i == argc ) usage(argv[0],"missing argument to --magic");
193       f = fopen(argv[i],"r");
194       if ( f == NULL ) {
195 	perror("can't open param file");
196 	exit(1);
197       }
198       for ( j = 0 ; j < sizeof(magic)/sizeof(double) ; j++ ) {
199 	if ( fscanf(f,"%lg",&magic[j]) != 1 ) {
200 	  fprintf(stderr,"%s","error in param file\n");
201 	  exit(1);
202 	}
203       }
204     } else if ( strcmp(argv[i],"--magic2") == 0 ) {
205       FILE *f;
206       int j;
207       if ( ++i == argc ) usage(argv[0],"missing argument to --magic2");
208       f = fopen(argv[i],"r");
209       if ( f == NULL ) {
210 	perror("can't open param file");
211 	exit(1);
212       }
213       for ( j = 0 ; j < 13 ; j++ ) {
214 	if ( fscanf(f,"%lg",&magic2[j]) != 1 ) {
215 	  fprintf(stderr,"%s","error in param file\n");
216 	  exit(1);
217 	}
218       }
219     } else {
220       fprintf(stderr,"unknown option or argument: %s\n",argv[i]);
221       usage(argv[0],"unknown option or argument");
222     }
223   }
224 
225   srand(time(NULL));
226 
227   if ( evalh ) {
228     Player pp;
229     Game g;
230 
231     g.round = EastWind;
232     the_game = &g;
233     pp.wind = EastWind;
234     initialize_player(&pp);
235     set_player_tiles(&pp,evalh);
236     our_player = &pp;
237     evalhand(&pp,&curstrat);
238     exit(0);
239   }
240 
241   the_game = client_init(address);
242   if ( ! the_game ) exit(1);
243 
244   sprintf(buf,"Robot(%d)",getpid());
245 
246   client_connect(the_game,our_id,name ? name : buf);
247 
248   while ( 1 ) {
249    l = get_line(the_game->fd);
250     if ( ! l ) {
251       exit(1);
252     }
253     despatch_line(l);
254   }
255 }
256 
257 /* despatch_line: this is the mega-switch which deals with
258    the input from the controller */
despatch_line(char * line)259 static int despatch_line(char *line) {
260   CMsgMsg *cm;
261 
262   if ( line == NULL ) {
263 
264     warn("receive error on controller connexion\n");
265     exit(1);
266   }
267 
268   cm = decode_cmsg(line);
269   if ( cm == NULL ) {
270     warn("Protocol error on controller connexion; ignoring\n");
271     return 0;
272   }
273 
274   update_tilesleft((CMsgUnion *)cm);
275 
276   switch ( cm->type ) {
277   case CMsgError:
278     break; /* damn all we can do */
279   case CMsgGameOver:
280     exit(0);
281   case CMsgReconnect:
282     /* we should never receive this */
283     warn("Received Reconnect command\n");
284     exit(1);
285   case CMsgInfoTiles:
286     /* We ignore these. */
287     break;
288   case CMsgCanMahJong:
289     /* Currently we ignore these, as we don't issue queries */
290     break;
291   case CMsgConnectReply:
292     game_handle_cmsg(the_game,cm);
293     our_id = the_game->players[0]->id;
294     our_player = the_game->players[0];
295     break;
296   case CMsgAuthReqd:
297     {
298       CMsgAuthReqdMsg *carm = (CMsgAuthReqdMsg *)cm;
299       PMsgAuthInfoMsg paim;
300       paim.type = PMsgAuthInfo;
301       if ( strncmp(carm->authtype,"basic",16) != 0 ) {
302 	warn("Asked for unknown authorization type %.16s",carm->authtype);
303 	exit(1);
304       }
305       strcpy(paim.authtype,"basic");
306       if ( password == NULL ) {
307 	warn("Asked for password, don't have it");
308 	exit(1);
309       }
310       paim.authdata = password;
311       send_packet(&paim);
312     }
313     break;
314     /* In these cases, our seat might have changed, so we need to calculate it */
315   case CMsgGame:
316     /* In this case, we need to ask for the game options */
317     {
318       PMsgListGameOptionsMsg plgom;
319       plgom.type = PMsgListGameOptions;
320       plgom.include_disabled = 0;
321       send_packet(&plgom);
322     }
323     /* and then ... */
324   case CMsgNewRound:
325   case CMsgNewHand:
326     game_handle_cmsg(the_game,cm);
327     our_seat = game_id_to_seat(the_game,our_id);
328     if ( debugeval ) fprintf(debugf,"New hand\n");
329     /* reset strategy to default */
330     curstrat.chowness = stratparams[chowness].values[0];
331     curstrat.hiddenness = stratparams[hiddenness].values[0];
332     curstrat.majorness = stratparams[majorness].values[0];
333     curstrat.suitness = stratparams[suitness].values[0];
334     curstrat.suit = 0;
335     break;
336     /* in all these cases, game_handle_cmsg does all the work we want */
337   case CMsgPlayer:
338   case CMsgStopPlay:
339   case CMsgClaimDenied:
340   case CMsgPlayerDoesntClaim:
341   case CMsgPlayerClaimsPung:
342   case CMsgPlayerClaimsKong:
343   case CMsgPlayerClaimsChow:
344   case CMsgPlayerClaimsMahJong:
345   case CMsgPlayerShowsTiles:
346   case CMsgDangerousDiscard:
347   case CMsgGameOption:
348   case CMsgChangeManager:
349   case CMsgWall:
350   case CMsgComment:
351   case CMsgStateSaved:
352   case CMsgMessage:
353     game_handle_cmsg(the_game,cm);
354     break;
355   case CMsgHandScore:
356     /* if that was the winner, we should start scoring our hand */
357     if ( ( game_handle_cmsg(the_game,cm)
358 	   == the_game->players[the_game->player]->id)
359 	 && the_game->active )
360       do_something();
361     break;
362     /* after a Settlement or Washout message, do something: start next hand */
363   case CMsgWashOut:
364   case CMsgSettlement:
365     game_handle_cmsg(the_game,cm);
366     if ( the_game->active ) do_something();
367     break;
368     /* likewise after a washout */
369     /* after a MahJong message, we should do something: namely
370        start making our scoring sets. */
371   case CMsgPlayerRobsKong:
372   case CMsgPlayerMahJongs:
373     game_handle_cmsg(the_game,cm);
374     if ( the_game->active ) do_something();
375     break;
376     /* in the case of a PlayerDeclaresSpecials message, we need to
377        do something if it is now our turn; but this isn't given
378        by the affected id.
379        However, if the state is Discarding, and no tiles have
380        so far been discarded, we shouldn't do something
381        now, since we are about to be asked to pause.
382     */
383   case CMsgPlayerDeclaresSpecial:
384     game_handle_cmsg(the_game,cm);
385     if ( the_game->player == our_seat && the_game->active
386 	 && ! ( the_game->state == Discarding && the_game->serial == 0 ))
387       do_something();
388     break;
389     /* in these cases, we need to do something if the message
390        is addressed to us. */
391   case CMsgPlayerDraws:
392   case CMsgPlayerDrawsLoose:
393   case CMsgPlayerPungs:
394   case CMsgPlayerKongs:
395   case CMsgPlayerChows:
396   case CMsgPlayerFormsClosedPung:
397   case CMsgPlayerFormsClosedChow:
398   case CMsgPlayerPairs:
399   case CMsgPlayerFormsClosedPair:
400   case CMsgPlayerSpecialSet:
401   case CMsgPlayerFormsClosedSpecialSet:
402   case CMsgSwapTile:
403     if ( game_handle_cmsg(the_game,cm) == our_id && the_game->active)
404       do_something();
405     break;
406     /* in this case, we need to do something else if it's not our turn! */
407   case CMsgPlayerDiscards:
408     if ( game_handle_cmsg(the_game,cm) != our_id && the_game->active)
409       check_discard(our_player,&curstrat,0);
410     break;
411     /* if this is us, we need to do something, and if it's
412        somebody else, we might be able to rob the kong */
413   case CMsgPlayerDeclaresClosedKong:
414     if ( game_handle_cmsg(the_game,cm) == our_id && the_game->active)
415       do_something();
416     else if ( the_game->active )
417       check_discard(our_player,&curstrat,1); /* actually this checks the kong */
418     break;
419   case CMsgPlayerAddsToPung:
420     if ( game_handle_cmsg(the_game,cm) == our_id && the_game->active)
421       do_something();
422     else if ( the_game->active )
423       check_discard(our_player,&curstrat,0); /* actually this checks the kong */
424     break;
425     /* In this case, it depends on the state of the game */
426   case CMsgStartPlay:
427     /* We need to do something if the id is us, or 0. */
428     { int id;
429     id = game_handle_cmsg(the_game,cm);
430     if ( id == our_id || id == 0 )
431       do_something();
432     }
433     break;
434     /* similarly */
435   case CMsgPlayerReady:
436     game_handle_cmsg(the_game,cm);
437     if ( ! the_game->paused ) do_something();
438     break;
439   case CMsgPause:
440     game_handle_cmsg(the_game,cm);
441     do_something();
442     break;
443   case CMsgPlayerOptionSet:
444     /* we don't recognize any options, so ignore it */
445     break;
446   case CMsgRedirect:
447     warn("Redirect command not currently supported");
448     exit(1);
449   }
450   return 1;
451 }
452 
453 /* do something when it's our turn.
454 */
do_something(void)455 static void do_something(void) {
456   int i;
457   MJSpecialHandFlags mjspecflags;
458 
459   mjspecflags = 0;
460   if ( game_get_option_value(the_game,GOSevenPairs,NULL).optbool )
461     mjspecflags |= MJSevenPairs;
462 
463   /* if the game is paused, and we haven't said we're ready, say so */
464   if ( the_game->paused ) {
465     if ( !the_game->ready[our_seat] ) {
466       PMsgReadyMsg pm;
467       pm.type = PMsgReady;
468       send_packet(&pm);
469     }
470     return;
471   }
472 
473   /* if the game state is handcomplete, do nothing */
474   if ( the_game->state == HandComplete ) return;
475 
476   /* If the game state is discarded, then it must mean this has
477      been called in response to a StartPlay message after resuming
478      an old hand. So actually we want to check the discard, unless
479      of course we are the discarder, or we have already claimed. */
480   if ( the_game->state == Discarded ) {
481     if ( the_game->player != our_seat
482 	 && the_game->claims[our_seat] == UnknownClaim )
483       check_discard(our_player,&curstrat,0);
484     return;
485   }
486 
487   /* If the game state is Dealing, then we should not do anything.
488    */
489   if ( the_game->state == Dealing ) return;
490 
491   /* if we're called in declaring specials or discarding, but it's
492      not our turn, do nothing */
493   if ( (the_game->state == DeclaringSpecials
494 	|| the_game->state == Discarding)
495        && the_game->player != our_seat ) return;
496 
497   /* if we're waiting to draw another tile, do nothing */
498   if ( the_game->needs != FromNone ) return;
499 
500   /* if we have a special, declare it. N.B. we'll
501      be called again as a result of this, so only look for first.
502   */
503   for ( i=0; i < our_player->num_concealed
504 	  && ! is_special(our_player->concealed[i]) ; i++);
505   if ( i < our_player->num_concealed ) {
506     PMsgDeclareSpecialMsg m;
507     m.type = PMsgDeclareSpecial;
508     m.tile = our_player->concealed[i];
509     send_packet(&m);
510     return;
511   }
512   /* OK, no specials */
513   if ( the_game->state == DeclaringSpecials ) {
514     PMsgDeclareSpecialMsg m;
515     m.type = PMsgDeclareSpecial;
516     m.tile = HiddenTile;
517     send_packet(&m);
518     /* and at this point, we should decide our strategy */
519     maybe_switch_strategy(&curstrat);
520     return;
521   }
522   /* if the game is in the mahjonging state, and our hand is not declared,
523      then we should declare a set. */
524   if ( the_game->state == MahJonging ) {
525     TileSet *tsp;
526     PMsgUnion m;
527 
528     if ( pflag(our_player,HandDeclared) ) return;
529     /* as courtesy, if we're not the winner, we shouldn't score until
530        the winner has */
531     if ( our_seat != the_game->player
532 	 && ! pflag(the_game->players[the_game->player],HandDeclared) ) return;
533 
534     /* get the list of possible decls */
535     tsp = client_find_sets(our_player,
536 			   (the_game->player == our_seat
537 			    && the_game->mjpending)
538 			   ? the_game->tile : HiddenTile,
539 			   the_game->player == our_seat,
540 			   (PlayerP *)0,mjspecflags);
541     if ( !tsp && our_player->num_concealed > 0 ) {
542       m.type = PMsgShowTiles;
543       send_packet(&m);
544       return;
545     }
546     /* just do the first one */
547     switch ( tsp->type ) {
548     case Kong:
549       /* we can't declare a kong now, so declare the pung instead */
550     case Pung:
551       m.type = PMsgPung;
552       m.pung.discard = 0;
553       break;
554     case Chow:
555       m.type = PMsgChow;
556       m.chow.discard = 0;
557       m.chow.cpos = the_game->tile - tsp->tile;
558       break;
559     case Pair:
560       m.type = PMsgPair;
561       break;
562     case ClosedPung:
563       m.type = PMsgFormClosedPung;
564       m.formclosedpung.tile = tsp->tile;
565       break;
566     case ClosedChow:
567       m.type = PMsgFormClosedChow;
568       m.formclosedchow.tile = tsp->tile;
569       break;
570     case ClosedPair:
571       m.type = PMsgFormClosedPair;
572       m.formclosedpair.tile = tsp->tile;
573       break;
574     case Empty: /* can't happen, just to suppress warning */
575     case ClosedKong: /* ditto */
576       ;
577     }
578     send_packet(&m);
579     return;
580   }
581 
582   /* if we can declare MahJong, do it */
583   if ( player_can_mah_jong(our_player,HiddenTile,mjspecflags) ) {
584     PMsgMahJongMsg m;
585     m.type = PMsgMahJong;
586     m.discard = 0;
587     send_packet(&m);
588     return;
589   } else if ( the_game->whence != FromDiscard ) {
590     /* check for concealed kongs and melded kongs. Just declare them. */
591     int i;
592     double val;
593     Player pc;
594     val = evalhand(our_player,&curstrat);
595     /* a side effect of the above call is that our concealed tiles
596        are sorted (in reverse order), so we can avoid duplicating effort */
597     for (i=0;i<our_player->num_concealed;i++) {
598       /* don't look at same tile twice */
599       if ( i && our_player->concealed[i] == our_player->concealed[i-1] ) continue;
600       if ( player_can_declare_closed_kong(our_player,our_player->concealed[i]) ) {
601 	PMsgDeclareClosedKongMsg m;
602 	copy_player(&pc,our_player);
603 	player_declares_closed_kong(&pc,our_player->concealed[i]);
604 	if ( evalhand(&pc,&curstrat) > val ) {
605 	  m.type = PMsgDeclareClosedKong;
606 	  m.tile = our_player->concealed[i];
607 	  send_packet(&m);
608 	  return;
609 	}
610       }
611     }
612     /* Now check for pungs we can meld to */
613     for (i=0;i<MAX_TILESETS;i++) {
614       if ( our_player->tilesets[i].type == Pung
615 	   && player_can_add_to_pung(our_player,our_player->tilesets[i].tile) ) {
616 	PMsgAddToPungMsg m;
617 	copy_player(&pc,our_player);
618 	player_adds_to_pung(&pc,our_player->tilesets[i].tile);
619 	if ( evalhand(&pc,&curstrat) > val ) {
620 	  m.type = PMsgAddToPung;
621 	  m.tile = our_player->tilesets[i].tile;
622 	  send_packet(&m);
623 	  return;
624 	}
625       }
626     }
627   }
628   /* if we get here, we have to discard */
629   {
630     PMsgDiscardMsg m;
631     Tile t;
632 
633     /* strategy switching only after drawing tile from wall */
634     if ( the_game->whence != FromDiscard || !strategy_chosen) {
635       maybe_switch_strategy(&curstrat);
636     }
637 
638     t = decide_discard(our_player,NULL,&curstrat);
639 
640     m.type = PMsgDiscard;
641     m.tile = t;
642     m.calling = 0; /* we don't bother looking for original call */
643     send_packet(&m);
644     return;
645   }
646 }
647 
648 /* Check if we want the discard, and claim it.
649    Arg is strategy.
650    Also called to check whether a kong can be robbed -
651    the last arg says if being called on a closed kong */
check_discard(PlayerP p,strategy * strat,int closedkong)652 static void check_discard(PlayerP p, strategy *strat,int closedkong) {
653   PMsgUnion m;
654   double bestval,val;
655   int canmj;
656   char buf[100];
657   MJSpecialHandFlags mjspecflags;
658 
659   mjspecflags = 0;
660   if ( game_get_option_value(the_game,GOSevenPairs,NULL).optbool )
661     mjspecflags |= MJSevenPairs;
662 
663   if ( the_game->state == Discarding
664        || the_game->state == DeclaringSpecials ) {
665     /* this means we're being called to check whether a kong
666        can be robbed. Since robbing a kong gets us an extra double,
667        this is probably always worth doing, unless we're trying for
668        some limit hand */
669     if ( player_can_mah_jong(p,the_game->tile,mjspecflags)
670       && (!closedkong || player_can_thirteen_wonders(p,the_game->tile)) ) {
671       m.type = PMsgMahJong;
672       m.mahjong.discard = the_game->serial;
673     } else {
674       m.type = PMsgNoClaim;
675       m.noclaim.discard = the_game->serial;
676     }
677     send_packet(&m);
678     return;
679   }
680 
681   if ( debugeval ) {
682     player_print_tiles(buf,p,0);
683     fprintf(debugf,"Hand: %s  ; discard %s\n",buf,tile_code(the_game->tile));
684   }
685   bestval = evalhand(p,strat);
686   if ( debugeval ) {
687     fprintf(debugf,"Hand value before claim %.3f\n",bestval);
688   }
689 
690   canmj = player_can_mah_jong(p,the_game->tile,mjspecflags);
691   m.type = PMsgNoClaim;
692   m.noclaim.discard = the_game->serial;
693   if ( player_can_kong(p,the_game->tile) ) {
694       Player pc;
695 
696       copy_player(&pc,p);
697       player_kongs(&pc,the_game->tile);
698       val = evalhand(&pc,strat);
699       /* we won't discard a tile here */
700       if ( debugeval ) {
701 	fprintf(debugf,"Hand after kong  %.3f\n",val);
702       }
703       if ( val > bestval ) {
704 	m.type = PMsgKong;
705 	m.kong.discard = the_game->serial;
706 	bestval = val;
707       }
708       else
709 	if ( debugeval ) {
710 	  fprintf(debugf,"Chose not to kong\n");
711 	}
712   }
713   if ( player_can_pung(p,the_game->tile) ) {
714     Player pc;
715 
716     copy_player(&pc,p);
717     player_pungs(&pc,the_game->tile);
718     decide_discard(&pc,&val,&curstrat);
719     if ( debugeval ) {
720       fprintf(debugf,"Hand after pung  %.3f\n",val);
721     }
722     if ( val > bestval ) {
723       m.type = PMsgPung;
724       m.pung.discard = the_game->serial;
725       bestval = val;
726     }
727     else
728       if ( debugeval ) {
729 	fprintf(debugf,"Chose not to pung\n");
730       }
731     }
732   if ( (canmj || our_seat == (the_game->player+1)%NUM_SEATS)
733        && is_suit(the_game->tile) ) {
734     ChowPosition cpos = (unsigned) -1;
735     Player pc;
736     int chowposs = 0;
737     Tile t = the_game->tile;
738     copy_player(&pc,p);
739     if ( player_chows(&pc,t,Lower) ) {
740       decide_discard(&pc,&val,&curstrat);
741       if ( debugeval ) {
742 	fprintf(debugf,"Hand after lower chow: %.3f\n",val);
743       }
744       chowposs = 1;
745       if ( val > bestval ) {
746 	bestval = val;
747 	cpos = Lower;
748       }
749       copy_player(&pc,p);
750     }
751     if ( player_chows(&pc,t,Middle) ) {
752       decide_discard(&pc,&val,&curstrat);
753       if ( debugeval ) {
754 	fprintf(debugf,"Hand after middle chow: %.3f\n",val);
755       }
756       chowposs = 1;
757       if ( val > bestval ) {
758 	bestval = val;
759 	cpos = Middle;
760       }
761       copy_player(&pc,p);
762     }
763     if ( player_chows(&pc,t,Upper) ) {
764       chowposs = 1;
765       decide_discard(&pc,&val,&curstrat);
766       if ( debugeval ) {
767 	fprintf(debugf,"Hand after upper chow: %.3f\n",val);
768       }
769       if ( val > bestval ) {
770 	bestval = val;
771 	cpos = Upper;
772       }
773       copy_player(&pc,p);
774     }
775     if ( cpos != (unsigned)-1 ) {
776       m.type = PMsgChow;
777       m.chow.discard = the_game->serial;
778       m.chow.cpos = cpos;
779     }
780     else
781       if ( debugeval ) {
782 	if ( chowposs ) fprintf(debugf,"chose not to chow\n");
783       }
784   }
785   /* mah jong */
786   if ( canmj ) {
787     m.type = PMsgMahJong;
788     m.mahjong.discard = the_game->serial;
789 
790 #if 1
791     /* if we're following a concealed strategy, and we still have
792        four chances (ex?cluding this one) of going out, then
793        don't claim */
794     /* instead of four chances, make it depend on number of tiles left */
795     /* test: if hidden >1, then never claim */
796     if ( (strat->hiddenness > 1.0) || (strat->hiddenness*chances_to_win(p)
797 	 * (the_game->wall.live_end-the_game->wall.live_used)
798 	 / (the_game->wall.dead_end-the_game->wall.live_used)
799 	 >= 1.5) ) {
800       m.type = PMsgNoClaim;
801       m.noclaim.discard = the_game->serial;
802     }
803 #endif
804     if ( m.type != PMsgNoClaim ) {
805       if ( debugeval && strat->hiddenness > 0.0 ) fprintf(debugf,"claiming mahjong on hidden strategy\n");
806       m.type = PMsgMahJong;
807       m.mahjong.discard = the_game->serial;
808     } else {
809       if ( debugeval ) {
810 	fprintf(debugf,"CHOSE NOT TO MAHJONG\n");
811       }
812     }
813   }
814   if ( debugeval ) {
815     fprintf(debugf,"Result: %s",encode_pmsg((PMsgMsg *)&m));
816   }
817   send_packet(&m);
818   return;
819 }
820 
821 
822 /* Here is a data structure to track the number of (assumed)
823    available tiles elsewhere. The update fn should be called on every CMsg. */
824 
update_tilesleft(CMsgUnion * m)825 static void update_tilesleft(CMsgUnion *m) {
826   int i;
827   /* note that we don't need to check whether the tile is blank,
828      since the HiddenTile entry of tilesleft has no meaning.
829   */
830   switch ( m->type ) {
831   case CMsgNewHand:
832     for (i=0; i < MaxTile; i++) {
833       tilesleft[i] = 4;
834       rightdiscs[i] = 0;
835     }
836     return;
837   case CMsgPlayerDeclaresSpecial:
838     return;
839   case CMsgPlayerDraws:
840     tilesleft[m->playerdraws.tile]--;
841     return;
842   case CMsgPlayerDrawsLoose:
843     tilesleft[m->playerdrawsloose.tile]--;
844     return;
845   case CMsgPlayerDiscards:
846     /* if this is us, we've already counted it */
847     if ( m->playerdiscards.id != our_id )
848       tilesleft[m->playerdiscards.tile]--;
849     if ( game_id_to_seat(the_game,m->playerdiscards.id)
850 	 == (our_seat+1)%4 )
851       rightdiscs[m->playerdiscards.tile] = m->playerdiscards.discard;
852     return;
853   case CMsgPlayerPungs:
854     /* if somebody else pungs, then two more tiles become dead
855        (the discard was already noted).
856        If we pung, nothing new is known */
857     if ( m->playerpungs.id != our_id )
858       tilesleft[m->playerpungs.tile] -= 2;
859     return;
860   case CMsgPlayerKongs:
861     /* if somebody else kongs, then three more tiles become dead
862        (the discard was already noted). */
863     if ( m->playerkongs.id != our_id )
864       tilesleft[m->playerkongs.tile] -= 3;
865     return;
866   case CMsgPlayerDeclaresClosedKong:
867     if ( m->playerdeclaresclosedkong.id != our_id )
868       tilesleft[m->playerdeclaresclosedkong.tile] -= 4;
869     return;
870   case CMsgPlayerAddsToPung:
871     if ( m->playeraddstopung.id != our_id )
872       tilesleft[m->playeraddstopung.tile]--;
873     return;
874   case CMsgPlayerChows:
875     if ( m->playerchows.id != our_id ) {
876       Tile t = m->playerchows.tile;
877       ChowPosition c = m->playerchows.cpos;
878       tilesleft[(c==Lower)?t+1:(c==Middle)?t-1:t-2]--;
879       tilesleft[(c==Lower)?t+2:(c==Middle)?t+1:t-1]--;
880     }
881     return;
882   case CMsgSwapTile:
883     tilesleft[m->swaptile.oldtile]++;
884     tilesleft[m->swaptile.newtile]--;
885     return;
886   default:
887     return;
888   }
889 }
890 
891 
892 /* This sorts the tiles (as below) into reverse order.
893    Why reverse order? So that HiddenTile terminates the hand.
894 */
tsort(Tile * tp)895 static void tsort(Tile *tp) {
896   int i,m;
897   Tile t;
898   /* bubblesort */
899   m = 1;
900   while ( m ) {
901     m = 0;
902     for (i=0; i<MAX_CONCEALED+1-1;i++)
903       if ( tp[i] < tp[i+1] ) {
904 	t = tp[i];
905 	tp[i] = tp[i+1];
906 	tp[i+1] = t;
907 	m = 1;
908       }
909   }
910 }
911 
912 
913 /* This function attempts to evaluate a partial hand.
914    The input is a (pointer to an) array of tiles
915    (length MAX_CONCEALED+1; some will be blank).
916    The value is a floating point number, calculated thus:
917    for the first tile in the set, form all possible sets
918    and partial sets (incl. singletons) with that tile;
919    then recurse on the remainder. The value is then the
920    max over the partial sets of the inherent value of the
921    set (explained below) and the recursive value of the remaining hand.
922    This would have the slightly awkward consequence that pairs get counted
923    twice in pungs, since given 222... we see 22 2 and also 2 22.
924    Hence, if we form a pung, we don't form a pair also.
925    (Nothing special is done about kongs; it should be.)
926    **** The input is sorted in place. ****
927 */
928 
929 /* debugging format:
930    SSTT:mmmm+ (recursive)
931    tttt(nnnn)
932    where SS is a set code (Pu,Pr,Ch,In,Ou,Si),
933    TT is the tile code, mmmm is the set value,
934    tttt is the total, nnnn is the residual
935    Hence the recursive call should indent all lines except the first
936    by reclevel*11 characters, and the base case call should emit
937    a newline.
938 */
939 /* other parameters:
940    strat: current strategy
941    reclevel: recursion level. Should start at 0.
942    ninc: number of incomplete sets (including pairs) in
943      the chain so far.
944    npr: number of pairs in the chain so far.
945    breadth is something to try to count the number of ways a hand
946    can be evaluated. Every time we hit bottom, we'll increment
947    breadth by 1/reclevel.
948 */
949 
eval(Tile * tp,strategy * strat,double * stratpoints,int reclevel,int * ninc,int * npr,double * breadth)950 static double eval(Tile *tp,strategy *strat,double *stratpoints,
951 		   int reclevel,
952 		   int *ninc,
953 		   int *npr,
954 		   double *breadth) {
955   Tile copy[MAX_CONCEALED+1],copy2[MAX_CONCEALED+1];
956   int i;
957   double mval = 0, pval = 0, val = 0,
958     pvalr = 0, mvalr = 0, valr = 0;
959   int ppr, mpr; int spr;
960   char prefix[200];
961   static char totbuf[200];
962   char tb[20];
963   int notfirst=0;
964 
965   tsort(tp);
966 
967   if ( reclevel == -1 ) {
968     /*evaluate each suit in turn*/
969     mval = 0.0;
970     tcopy(copy,tp);
971     while ( suit_of(copy[0]) ) {
972       tcopy(copy2,copy);
973       for ( i = 0; suit_of(copy[i]) == suit_of(copy[0]); i++ );
974       for ( ; i < MAX_CONCEALED+1 ; i++ ) copy[i] = HiddenTile;
975       val = eval(copy,strat,stratpoints,0,ninc,npr,breadth);
976       mval += val ;
977       if ( debugeval ) fprintf(debugf,"Evaling suit %d returned v=%.2f, b=%.2f\n",
978 			      suit_of(copy[0]),val,*breadth);
979       tcopy(copy,copy2);
980       for ( i= 0; suit_of(copy[i]) == suit_of(copy2[0]) ; i++ )
981 	copy[i] = HiddenTile;
982       tsort(copy);
983     }
984     if ( debugeval ) fprintf(debugf,"Level 0 returned %.2f\n",mval);
985     return mval;
986   }
987 
988   if ( debugeval ) {
989     /* The total buffer. A call at recursion level n writes the total into bytes
990        11(n-1) to 11n-1  of the buffer (right justified in the first 4 chars;
991        spaces in the rest.
992        A base case terminates the total buffer with null.
993        When a second set is printed, or when we terminate at level zero,
994        then the total buffer is printed.
995     */
996 
997     for (i=0;i<reclevel*11;i++) prefix[i]=' ';
998     prefix[i]=0;
999   }
1000 
1001   if ( tp[0] == HiddenTile ) {
1002     if ( debugeval > 1 ) {
1003       fprintf(debugf,"\n");
1004       if (reclevel) sprintf(&totbuf[11*(reclevel-1)+4],"\n");
1005     }
1006     /* if there is one "incomplete" set and one pair, we have a complete
1007        hand */
1008 #if 0
1009     if ( ninc == 1 && npr == 1 ) val = stratpoints[mjbonus];
1010     else val = 0.0;
1011 #else
1012     val = 0.0;
1013 #endif
1014     if ( debugeval > 1 ) {
1015       sprintf(tb,"%4.1f",val);
1016       strncpy(&totbuf[11*reclevel],tb,4);
1017     }
1018     return val;
1019   }
1020 
1021   /* does it pung? */
1022   ppr = 0;
1023   if ( tp[1] == tp[0] ) {
1024     if ( tp[2] == tp[0] ) {
1025       val = 0.0;
1026       /* add the value of this set.
1027       */
1028       val += stratpoints[pungbase];
1029       /* if we're trying for a no score hand, scoring pairs are bad */
1030       if ( is_doubler(tp[0]) ) val += (-strat->chowness)  * magic2[0];
1031       if ( is_major(tp[0]) ) {
1032 	val += magic2[1];
1033       } else {
1034 	val -= magic2[2]*strat->majorness;
1035       }
1036       if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit )
1037 	val *= stratpoints[suitfactor];
1038       if ( debugeval > 1 ) {
1039 	fprintf(debugf,"%sPu%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);
1040       }
1041       /* remove the tiles and recurse */
1042       tcopy(copy,tp);
1043       copy[0] = copy[1] = copy[2] = HiddenTile;
1044       valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&ppr,breadth);
1045       if ( debugeval > 1 ) {
1046 	sprintf(tb,"%4.1f",val);
1047 	strncpy(&totbuf[11*reclevel],tb,4);
1048       }
1049       val += valr;
1050       if ( val > pval ) { pval = val; pvalr = valr ; }
1051     } else {
1052       val = 0.0;
1053       /* A pair is worth something for itself, plus something
1054 	 for its chances of becoming a pung.
1055 	 A doubler pair is worth an extra 2 points.
1056 	 A major pair is worth an extra point.
1057 	 Beware the risk of arranging effect that a chow and
1058 	 a pair is worth much more than a pung and an inner sequence,
1059 	 so that we'd break a pung rather than a chow.
1060       */
1061       ppr++;
1062       val += stratpoints[partpung]*stratpoints[pungbase] * tilesleft[tp[0]];
1063       /* doublers are bad for noscore */
1064       if ( is_doubler(tp[0]) ) val += 2 - (strat->chowness)*4.0;
1065       if ( is_major(tp[0]) ) {
1066 	val += magic2[3];
1067       } else {
1068 	val -= magic2[4]*strat->majorness;
1069       }
1070       if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit )
1071 	val *= stratpoints[suitfactor];
1072       if ( debugeval > 1 ) {
1073 	fprintf(debugf,"%sPr%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);
1074       }
1075       /* remove the tiles and recurse */
1076       tcopy(copy,tp);
1077       copy[0] = copy[1] = HiddenTile;
1078       (*ninc)++;
1079       valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&ppr,breadth);
1080       val += valr;
1081       if ( debugeval > 1 ) {
1082 	sprintf(tb,"%4.1f",val);
1083 	strncpy(&totbuf[11*reclevel],tb,4);
1084       }
1085       if ( val > pval ) { pval = val; pvalr = valr; }
1086     }
1087   }
1088   /* OK, now deal with chows. */
1089   mpr = 0;
1090   if ( is_suit(tp[0]) ) {
1091     Tile t1,t2; int i1,i2; /* other tiles, and their indices */
1092     /* NB tiles are in reverse order!!!!! */
1093     t1 = ((value_of(tp[0]) > 1) ? tp[0]-1 : 0);
1094     t2 = ((value_of(tp[0]) > 2) ? tp[0]-2 : 0);
1095     for (i1=0;t1 && tp[i1] && tp[i1]!=t1;i1++);
1096     if ( ! tp[i1] ) i1=0;
1097     for (i2=0;t2 && tp[i2] && tp[i2]!=t2;i2++);
1098     if ( ! tp[i2] ) i2=0;
1099 
1100     /* if we have a chow */
1101     if ( i1 && i2 ) {
1102       val = 0.0;
1103       /* A chow is deemed to be worth 12 points also.
1104 	 (Quick and dirty ... hike pungbonus to avoid chows.)
1105       */
1106      val += stratpoints[chowbase];
1107       if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit )
1108 	val *= stratpoints[suitfactor];
1109      if ( debugeval > 1 ) {
1110        if ( notfirst ) fprintf(debugf,"%s%s",prefix,&totbuf[11*reclevel]);
1111        fprintf(debugf,"%sCh%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);
1112      }
1113       /* remove the tiles and recurse */
1114       tcopy(copy,tp);
1115       copy[0] = copy[i1] = copy[i2] = HiddenTile;
1116       valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&mpr,breadth);
1117       val += valr;
1118       if ( debugeval > 1 ) {
1119 	sprintf(tb,"%4.1f",val);
1120 	strncpy(&totbuf[11*reclevel],tb,4);
1121       }
1122       if ( val > mval ) { mval = val; mvalr = valr; }
1123     }
1124     /* If we have an inner sequence... note that it's intentional
1125        that we do this as well, since maybe if we split the chow,
1126        we'll find a pung. But we'
1127     */
1128     if ( i1 ) {
1129       val = 0.0;
1130       /* An inner sequence is worth the number of chances of completion,
1131 	 allowing for the fact that on average, the tiles in right
1132 	 and opposite and half the tiles in the wall will not be available
1133 	 for completing a chow.
1134 	 NOTE: this needs to change when we're nearly at MahJong.
1135       */
1136       val += stratpoints[seqbase];
1137       if ( value_of(tp[0]) < 9 ) {
1138 	val += stratpoints[partchow]*stratpoints[chowbase] * tilesleft[tp[0]+1];
1139       }
1140       if ( value_of(t1) > 1 ) {
1141 	val += stratpoints[partchow]*stratpoints[chowbase] * tilesleft[t1-1];
1142       }
1143       if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit )
1144 	val *= stratpoints[suitfactor];
1145       if ( debugeval > 1 ) {
1146 	if ( notfirst ) fprintf(debugf,"%s%s",prefix,&totbuf[11*reclevel]);
1147 	fprintf(debugf,"%sIn%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);
1148       }
1149       /* remove the tiles and recurse */
1150       tcopy(copy,tp);
1151       copy[0] = copy[i1] = HiddenTile;
1152       valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&mpr,breadth);
1153       val += valr;
1154       if ( debugeval > 1 ) {
1155 	sprintf(tb,"%4.1f",val);
1156 	strncpy(&totbuf[11*reclevel],tb,4);
1157       }
1158       if ( val > mval ) { mval = val; mvalr = valr; }
1159     }
1160     /* If we have a split sequence ... Here we don't do this if there's
1161        been a chow. Hmm, why not? I thought I had a reason. Fill it in
1162        sometime. */
1163     else if ( i2 ) {
1164       val = 0.0;
1165       /* Likewise */
1166       val += stratpoints[seqbase];
1167       val += stratpoints[partchow]*stratpoints[chowbase] * tilesleft[t1];
1168       if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit )
1169 	val *= stratpoints[suitfactor];
1170       if ( debugeval > 1 ) {
1171 	if ( notfirst ) fprintf(debugf,"%s%s",prefix,&totbuf[11*reclevel]);
1172 	fprintf(debugf,"%sOu%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);
1173       }
1174       /* remove the tiles and recurse */
1175       tcopy(copy,tp);
1176       copy[0] = copy[i2] = HiddenTile;
1177       valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&mpr,breadth);
1178       val += valr;
1179       if ( debugeval > 1 ) {
1180 	sprintf(tb,"%4.1f",val);
1181 	strncpy(&totbuf[11*reclevel],tb,4);
1182       }
1183       if ( val > mval ) { mval = val; mvalr = valr; }
1184     }
1185   }
1186   /* Finally, the score for a singleton.
1187   */
1188   /* let's also add .25 times the number of neighbouring tiles */
1189   spr = 0;
1190   val = 0.0;
1191   val += stratpoints[sglbase]
1192     * (tilesleft[tp[0]]
1193        + ( is_suit(tp[0])
1194 	  ? (magic2[5]*strat->chowness*(tilesleft[tp[0]-1]+ tilesleft[tp[0]+1])) : 0))
1195     * (magic2[6]-strat->chowness);
1196   if ( is_doubler(tp[0]) ) {
1197     if (tilesleft[tp[0]] == 0) val -= magic2[7]; /* completely useless */
1198     else {
1199       if ( (magic2[8]-strat->chowness) > 0 )
1200 	val += (tilesleft[tp[0]])*stratpoints[sglbase]*(magic2[9]-strat->chowness);
1201       else
1202 	val += (3-tilesleft[tp[0]])*stratpoints[sglbase]*(magic2[10]-strat->chowness);
1203     }
1204   }
1205   if ( is_suit(tp[0]) && suit_of(tp[0]) != strat->suit ) {
1206     /* val could be negative, in which case we don't want to shrink it.
1207        So just substract a constant */
1208     val -= magic2[11]*strat->suitness*stratpoints[sglbase];
1209   }
1210   if ( ! is_major(tp[0]) ) {
1211     val -= magic2[12]*strat->majorness*stratpoints[sglbase];
1212   }
1213   if ( debugeval > 1 ) {
1214     if ( notfirst ) fprintf(debugf,"%s%s",prefix,&totbuf[11*reclevel]);
1215     fprintf(debugf,"%sSi%s:%4.1f+ ",notfirst++?prefix:"",tile_code(tp[0]),val);
1216   }
1217   tcopy(copy,tp);
1218   copy[0] = HiddenTile;
1219   valr = eval(copy,strat,stratpoints,reclevel+1,ninc,&spr,breadth);
1220   val += valr;
1221   if ( debugeval > 1 ) {
1222     sprintf(tb,"%4.1f",val);
1223     strncpy(&totbuf[11*reclevel],tb,4);
1224   }
1225   /* at this point, we have pair/seq/single based scores. */
1226 
1227   if ( mval > pval ) {
1228     if ( val > mval ) {
1229       if ( spr ) (*npr)++;
1230       mval = val;
1231     } else {
1232       if ( mpr ) (*npr)++;
1233     }
1234   } else {
1235     if ( val > pval ) {
1236       mval = val;
1237       if ( spr ) (*npr)++;
1238     } else {
1239       mval = pval;
1240       if ( ppr ) (*npr)++;
1241     }
1242   }
1243   if ( debugeval > 1 ) {
1244     if ( reclevel ) {
1245       sprintf(tb,"(%4.1f) ",mval);
1246       strncpy(&totbuf[11*(reclevel-1)+4],tb,7);
1247     }
1248     else fputs(totbuf,debugf);
1249   }
1250   return mval;
1251 }
1252 
1253 
1254 /* This function uses the above to evaluate a player's hand, including
1255    the completed sets. */
evalhand(PlayerP p,strategy * strat)1256 static double evalhand(PlayerP p,strategy *strat) {
1257   Tile tcopy[MAX_CONCEALED+1];
1258   double val,breadth;
1259   int i, npr, ninc;
1260   double stratpoints[weight+1];
1261 
1262   if ( debugeval ) {
1263     char buf[100];
1264     fprintf(debugf,"eval with strat params c=%.1f, h=%.1f, m=%.1f, s=%.1f (%d)\n",
1265 	   strat->chowness,strat->hiddenness,strat->majorness,
1266 	   strat->suitness,strat->suit);
1267     player_print_tiles(buf,p,0);
1268     fprintf(debugf,"Hand: %s\n",buf);
1269   }
1270   /* calculate old style strategy values from new ones */
1271   stratpoints[pungbase] =
1272     magic[0] - ( strat->chowness > 0 ? strat->chowness * magic[0]
1273 	     : strat->chowness * magic[1] );
1274   stratpoints[pungbase] *= (magic[2] + magic[3] * strat->hiddenness);
1275   stratpoints[pairbase] = magic[4]*(magic[5] + (magic[6]*fabs(strat->chowness)));
1276   stratpoints[chowbase] =
1277     magic[0] + ( strat->chowness > 0 ? strat->chowness * magic[7]
1278 	     : strat->chowness * magic[0] );
1279   stratpoints[chowbase] *= (magic[8] + magic[9] * strat->hiddenness)
1280     * (1.0 - strat->majorness);
1281   stratpoints[seqbase] = magic[10]*(magic[11] + ( strat->chowness < 0 ? strat->chowness : 0))
1282     * (1.0 - strat->majorness);
1283   stratpoints[sglbase] = magic[12];
1284   stratpoints[partpung] = magic[13]*(magic[14])*(1-magic[15]*strat->hiddenness);
1285   stratpoints[partchow] = magic[16]*(1-magic[17]*strat->hiddenness) * (1.0 - strat->majorness);
1286   stratpoints[exposedpungpenalty] = magic[18] + strat->hiddenness * stratpoints[pungbase]
1287     + ( (strat->chowness > 0) ? magic[19] * strat->chowness : 0.0 );
1288   stratpoints[exposedchowpenalty] = magic[20] + strat->hiddenness * stratpoints[chowbase]
1289     + ( (strat->chowness < 0) ? -1*magic[21] * strat->chowness : 0.0 )
1290     + magic[21] * strat->majorness;
1291   stratpoints[mjbonus] = magic[22];
1292   stratpoints[kongbonus] = magic[23];
1293   stratpoints[suitfactor] =
1294     ((strat->suitness >= 1.0) ? 0.01 : (1.0 - magic[24]*strat->suitness));
1295   stratpoints[weight] = magic[25] +
1296     (strat->suitness >= 1.0 ? magic[26]*(strat->suitness-1.0) : magic[26]*strat->suitness)
1297     + magic[27]*strat->majorness;
1298 
1299   for (i=0; i<p->num_concealed; i++)
1300     tcopy[i] = p->concealed[i];
1301   for ( ; i < MAX_CONCEALED+1; i++)
1302     tcopy[i] = HiddenTile;
1303 
1304   val = 0.0;
1305 
1306   ninc = npr = 0; /* number of "incomplete"/pairs in hand */
1307 
1308   /* note that if we see any closed pungs in here, they are
1309      actually hacks representing hypothetical open sets */
1310 
1311   for (i=0; i<5; i++) {
1312     double sval = 0.0;
1313     switch (p->tilesets[i].type) {
1314     case Chow:
1315     case ClosedChow:
1316       sval -= stratpoints[exposedchowpenalty];
1317       sval += stratpoints[chowbase];
1318       break;
1319     case ClosedKong:
1320       sval += stratpoints[exposedpungpenalty]; /* cancel the penalty later */
1321     case Kong:
1322       sval += stratpoints[kongbonus];
1323     case Pung:
1324     case ClosedPung:
1325       sval -= stratpoints[exposedpungpenalty];
1326       sval += stratpoints[pungbase];
1327       /* these shadow evalhand above */
1328       if ( is_doubler(p->tilesets[i].tile) ) sval += (-strat->chowness)  * 6.0;
1329       if ( is_major(p->tilesets[i].tile) ) {
1330 	sval += 2.0 ; /* small bonus for luck */
1331       } else {
1332 	sval -= 25.0*strat->majorness;
1333       }
1334       break;
1335     case Pair:
1336     case ClosedPair:
1337       ninc = npr = 1; /* for correct evaluation of pairs */
1338       sval += stratpoints[pairbase];
1339       break;
1340     default:
1341       ;
1342     }
1343     if ( p->tilesets[i].type != Empty
1344 	 && is_suit(p->tilesets[i].tile)
1345 	 && suit_of(p->tilesets[i].tile) != strat->suit )
1346       sval -= 10.0*strat->suitness;
1347     if ( debugeval > 1 ) {
1348       fprintf(debugf,"Set %s: %.1f\n",player_print_TileSetType(p->tilesets[i].type),
1349 	     sval);
1350     }
1351     val += sval;
1352   }
1353   breadth = 0.0;
1354   val += eval(tcopy,strat,stratpoints,-1,&ninc,&npr,&breadth);
1355   /* add the pairbase if we have at least one pair */
1356   if ( npr > 0 ) {
1357     if ( debugeval > 1 ) fprintf(debugf,"+pairbase %.1f\n",stratpoints[pairbase]);
1358     val += stratpoints[pairbase];
1359   }
1360   val *= stratpoints[weight];
1361 #if 0 /* randomization seems to be a lose */
1362   /* now add a small random offset */
1363   r = (2.0*rand())/RAND_MAX - 1.0;
1364   r = 4*r*r;
1365   return val+r;
1366 #else
1367   if ( debugeval ) fprintf(debugf,"Value %.2f\n",val);
1368   return val;
1369 #endif
1370 }
1371 
1372 /* compute the number of ways a calling hand can go out */
chances_to_win(PlayerP p)1373 static int chances_to_win(PlayerP p) {
1374   Tile t;
1375   int n;
1376   MJSpecialHandFlags mjspecflags;
1377 
1378   mjspecflags = 0;
1379   if ( game_get_option_value(the_game,GOSevenPairs,NULL).optbool )
1380     mjspecflags |= MJSevenPairs;
1381 
1382   t = HiddenTile;
1383   n = 0;
1384   while ( (t = tile_iterate(t,0)) != HiddenTile ) {
1385     if ( tilesleft[t] && player_can_mah_jong(p,t,mjspecflags) )
1386       n += tilesleft[t];
1387   }
1388   return n;
1389 }
1390 
1391 /* compute tile to discard. Return value is tile.
1392    Second arg returns score of resulting hand.
1393    Third arg returns the new strategy.
1394 */
decide_discard(PlayerP p,double * score,strategy * strat)1395 static Tile decide_discard(PlayerP p, double *score, strategy *strat) {
1396   /* how do we choose a tile to discard?
1397      remove the tile, and evaluate the remaining hand.
1398      Discard the tile giving the greatest residual value.
1399   */
1400   int i,best;
1401   double values[MAX_CONCEALED+1]; Tile tilesa[MAX_CONCEALED+1],tiles[MAX_CONCEALED+1] UNUSED;
1402   char buf[80];
1403   const Tile *t = p->concealed;
1404 
1405 
1406   for (i=0;i<MAX_CONCEALED+1;i++) values[i]=0;
1407   for (i=0;i<p->num_concealed;i++) tilesa[i] = t[i];
1408   for (;i<MAX_CONCEALED+1;i++) tilesa[i] = HiddenTile;
1409 
1410   if ( debugeval ) {
1411     player_print_tiles(buf,p,0);
1412     fprintf(debugf,"Hand: %s\n",buf);
1413   }
1414   best = 0;
1415   tsort(tilesa); /* no point in looking at same tile twice */
1416   for (i=0;i<p->num_concealed;i++) {
1417     Player cp;
1418     if ( i && tilesa[i] == tilesa[i-1] ) continue;
1419     if ( debugeval ) {
1420       fprintf(debugf,"Trying %s: \n",tile_code(tilesa[i]));
1421     }
1422     copy_player(&cp,p);
1423     player_discards(&cp,tilesa[i]);
1424     values[i] = evalhand(&cp,strat);
1425     /* add a bonus for tiles recently discarded by the player
1426        to the right */
1427     if ( rightdiscs[tilesa[i]] )
1428       values[i] += 0.5; /* /(the_game->serial-rightdiscs[tilesa[i]]) */;
1429     if ( is_suit(tilesa[i])
1430 	 && ((value_of(tilesa[i]) < 7
1431 	      && rightdiscs[tilesa[i]+3])
1432 	     || (value_of(tilesa[i]) > 3
1433 		 && rightdiscs[tilesa[i]-3])) )
1434       values[i] += 0.4; /* the 1-4-7 argument */
1435     /* Best tile to discard leaves highest residual score */
1436     if ( values[i] > values[best] ) best = i;
1437     if ( debugeval ) {
1438 	fprintf(debugf,"Tile %s has value %.1f\n",tile_code(tilesa[i]),values[i]);
1439     }
1440   }
1441   if ( debugeval ) {
1442     fprintf(debugf,"Discarding %s\n",tile_code(tilesa[best]));
1443   }
1444   if ( score ) *score = values[best];
1445   return tilesa[best];
1446 }
1447 
1448 /* Maybe switch strategy: takes a strat pointer as argument,
1449    and updates it in place. */
maybe_switch_strategy(strategy * strat)1450 static void maybe_switch_strategy(strategy *strat) {
1451   strategy tmpstrat;
1452   int i,j;
1453   double val,oval, bestval;
1454   strategy beststrat;
1455   int dofast;
1456   PlayerP p = our_player;
1457 
1458   oval = evalhand(p,strat);
1459 
1460   bestval = -1000.0;
1461   tmpstrat.chowness = stratparams[chowness].values[0];
1462   tmpstrat.hiddenness = stratparams[hiddenness].values[0];
1463   tmpstrat.majorness = stratparams[majorness].values[0];
1464   /* it makes no sense to try to evaluate pung/chowness with
1465      a non-zero suitness, cos we don't know which suit, and
1466      evaluating with suit=0 is equiv to all honours! */
1467   /* tmpstrat.suitness = stratparams[suitness].values[0]; */
1468   tmpstrat.suitness = 0.0;
1469   tmpstrat.suit = 0;
1470   beststrat.chowness = tmpstrat.chowness;
1471   for ( i=0 ; i < stratparams[chowness].ncomps ; i++ ) {
1472     tmpstrat.chowness = stratparams[chowness].values[i];
1473     val = evalhand(p,&tmpstrat);
1474     if ( val > bestval ) {
1475       bestval = val ;
1476       beststrat.chowness = tmpstrat.chowness;
1477     }
1478   }
1479   tmpstrat.chowness = beststrat.chowness;
1480   beststrat.hiddenness = tmpstrat.hiddenness;
1481   /* from i = 1, since we had [0] just above */
1482   for ( i = 1 ; i < stratparams[hiddenness].ncomps ; i++ ) {
1483     tmpstrat.hiddenness = stratparams[hiddenness].values[i];
1484     val = evalhand(p,&tmpstrat);
1485     if ( val > bestval ) {
1486       bestval = val ;
1487       beststrat.hiddenness = tmpstrat.hiddenness;
1488     }
1489   }
1490   /* and for suit */
1491   tmpstrat.hiddenness = beststrat.hiddenness;
1492   /* now we need to reset the best val, since only now
1493      are we considering the values the user had */
1494   bestval = -1000;
1495   for ( i = 0; i < stratparams[suitness].ncomps; i++ ) {
1496     tmpstrat.suitness = stratparams[suitness].values[i];
1497     /* j = 0 corresponds to all honours, which we shd get
1498        if we can ?? */
1499     for ( j = 0 ; j <= ((tmpstrat.suitness == 0.0)? 0 : 3) ; j++ ) {
1500       tmpstrat.suit = j;
1501       val = evalhand(p,&tmpstrat);
1502       if ( val > bestval ) {
1503 	bestval = val ;
1504 	beststrat = tmpstrat;
1505       }
1506     }
1507   }
1508   /* we'll now try for all majors... */
1509   /* however, there's no point in doing this unless we already
1510      think that a pung-based strategy is best */
1511   if ( beststrat.chowness < 0.0 ) {
1512     tmpstrat = beststrat;
1513     for ( i = 1; i < stratparams[majorness].ncomps; i++ ) {
1514       tmpstrat.majorness = stratparams[majorness].values[i];
1515       val = evalhand(p,&tmpstrat);
1516       if ( val > bestval ) {
1517 	bestval = val ;
1518 	beststrat = tmpstrat;
1519       }
1520     }
1521   }
1522   /* if some other player has four sets declared, then switch to
1523      Fast */
1524   dofast = 0;
1525 #if 0
1526   for ( i = 0 ; i < NUM_SEATS ; i++ ) {
1527     PlayerP p1 = the_game->players[i];
1528       if ( p1 == p ) continue;
1529       if ( p1->num_concealed <= 1 ) dofast = 1;
1530   }
1531 #endif
1532   if ( dofast ) {
1533     /* strat = Fast; */
1534     if ( debugeval ) { fprintf(debugf,"Using fast\n"); }
1535   } else {
1536     if ( bestval >= oval + hysteresis ) {
1537       *strat = beststrat;
1538       if ( debugeval ) {
1539 	static char buf[128];
1540 	fprintf(debugf,"Switching to strat c=%.1f h=%.1f s=%.1f (%d) m=%.1f\n",
1541 	       strat->chowness,strat->hiddenness,
1542 	       strat->suitness,strat->suit,strat->majorness);
1543 	  player_print_tiles(buf,p,0);
1544 	  fprintf(debugf," with hand %s\n",buf);
1545       }
1546     }
1547   }
1548 }
1549