deal319/0000755000175200017520000000000011341325570010271 5ustar cbecbedeal319/ansidecl.h0000644000175200017520000000604511062564550012234 0ustar cbecbe/* Copyright (C) 1991 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the GNU C Library; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ANSI and traditional C compatibility macros ANSI C is assumed if __STDC__ is #defined. Macro ANSI C definition Traditional C definition ----- ---- - ---------- ----------- - ---------- PTR `void *' `char *' LONG_DOUBLE `long double' `double' CONST `const' `' VOLATILE `volatile' `' SIGNED `signed' `' PTRCONST `void *const' `char *' DEFUN(name, arglist, args) Defines function NAME. ARGLIST lists the arguments, separated by commas and enclosed in parentheses. ARGLIST becomes the argument list in traditional C. ARGS list the arguments with their types. It becomes a prototype in ANSI C, and the type declarations in traditional C. Arguments should be separated with `AND'. For functions with a variable number of arguments, the last thing listed should be `DOTS'. DEFUN_VOID(name) Defines a function NAME, which takes no arguments. EXFUN(name, prototype) Is used in an external function declaration. In ANSI C it is `NAMEPROTOTYPE' (so PROTOTYPE should be enclosed in parentheses). In traditional C it is `NAME()'. For a function that takes no arguments, PROTOTYPE should be `(NOARGS)'. For example: extern int EXFUN(printf, (CONST char *format DOTS)); int DEFUN(fprintf, (stream, format), FILE *stream AND CONST char *format DOTS) { ... } void DEFUN_VOID(abort) { ... } */ #ifndef _ANSIDECL_H #define _ANSIDECL_H 1 /* Every source file includes this file, so they will all get the switch for lint. */ /* LINTLIBRARY */ #ifdef __STDC__ #define PTR void * #define PTRCONST void *CONST #define LONG_DOUBLE long double #define AND , #define NOARGS void #define CONST const #define VOLATILE volatile #define SIGNED signed #define DOTS , ... #define EXFUN(name, proto) name proto #define DEFUN(name, arglist, args) name(args) #define DEFUN_VOID(name) name(NOARGS) #else /* Not ANSI C. */ #define PTR char * #define PTRCONST PTR #define LONG_DOUBLE double #define AND ; #define NOARGS #define CONST #define VOLATILE #define SIGNED #define DOTS #define EXFUN(name, proto) name() #define DEFUN(name, arglist, args) name arglist args; #define DEFUN_VOID(name) name() #endif /* ANSI C. */ #endif /* ansidecl.h */ deal319/dealtypes.c0000644000175200017520000003036611074376057012450 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This file defines new Tcl types, to avoid the constant relookup * of certain common words and strings (coverting AKJ2 to its * binary representation, for example, or suit or hand names to their * internal numeric values.) * * int getSuitNumFromObj(Tcl_Interp *interp, Tcl_Obj *suit) * int getHandNumFromObj(Tcl_Interp *interp, Tcl_Obj *hand) * int getHoldingNumFromObj(Tcl_Interp *interp, Tcl_Obj *holding) * int getCardNumFromObj(Tcl_Interp *interp, Tcl_Obj *card) * * Tcl_Obj* Tcl_NewHoldingObj(int holding); * * The underlying objects are *converted* to these new types, * which keeps them from being looked up, again and again. * * See * * http://www.tcl.tk/man/tcl8.6/TclLib/ObjectType.htm * * for more information about object types in Tcl. */ #include "dealtypes.h" #include "ctype.h" #include "string.h" Tcl_ObjType CardType, HoldingType; static Tcl_Obj* lengthObjs[14]; void initializeLengths() { int i; static int initialized=0; if (!initialized) { for (i=0; i<=13; i++) { Tcl_IncrRefCount(lengthObjs[i]=Tcl_NewIntObj(i)); } initialized=1; } } Tcl_Obj *getLengthObj(int i) { return lengthObjs[i]; } static void dupDealRepProc(Tcl_Obj *source, Tcl_Obj *dup) { dup->internalRep.longValue=source->internalRep.longValue; } extern char cards[]; extern char suits[]; static void updateCardStringRep(Tcl_Obj *card) { int cardnum=card->internalRep.longValue; int suit=cardnum&3; int denom=cardnum>>2; char *string=Tcl_Alloc(3); string[0]=cards[denom]; string[1]=suits[suit]; string[2]=0; card->bytes=string; card->length=2; } static int convertToCardRep(Tcl_Interp *interp,Tcl_Obj *card) { char *string=Tcl_GetString(card); card->typePtr=&CardType; card->internalRep.longValue=card_num(string); return TCL_OK; } void initializeCardType() { CardType.freeIntRepProc=NULL; CardType.name="Card"; CardType.dupIntRepProc=dupDealRepProc; CardType.freeIntRepProc=NULL; CardType.updateStringProc=updateCardStringRep; CardType.setFromAnyProc=convertToCardRep; Tcl_RegisterObjType(&CardType); } static int validHoldingNum(int num) { int spots; if (num<0) { return 0; } spots=(num>>13); if (spots<0||spots>13) { return 0; } if (spots>0) { /* Make sure spots are right */ int codedspots=(1<typePtr=&HoldingType; result->internalRep.longValue=holding; Tcl_InvalidateStringRep(result); return result; } /* * Exact holdings are encoded as 13 bits, so AJ932 is, * in binary, * 1001010000011 * AKQJT98765432 * * Abstract holdings like AJ8xxx are recorded in the * lower 13 bits as AJ8432, but with the top bits * representing the number of x's: * * x's|AKQJT98765432 * 11|1001001000111 * * The '11' means there are 3 x's. * * Note, this means that AKJ4xxx is meaningless - the xxx's * cannot all be smaller than the 4. The procedure returns * an error in this case. * * Functions which take exact holdings can also take * holdings with x's by simply examining the lower 13 bits: * holding&8191 * So, for example, when evaluating: * * hcp eval AKxxxxxxxxxx * * the x's are assumed to be the smallest * possible, in which case, we are really * evaluating: * * hcp eval AKJT98765432 * * which turns out to be 8. * */ static int convertToHoldingRep(Tcl_Interp *interp,Tcl_Obj *holding) { char *string=Tcl_GetString(holding); char *cardCursor=cards; int hnum=0,spots=0; int cardnum=0; if (*string == '-' && string[1]==0) { holding->internalRep.longValue = 0; holding->typePtr = &HoldingType; return TCL_OK; } while (*cardCursor && *string) { if (*cardCursor==toupper(*string)) { hnum |= (1<<(12-cardnum)); string++; } cardCursor++; cardnum++; } while (*string && (*string=='x' || *string=='X')) { if (hnum & (1<internalRep.longValue=hnum; holding->typePtr=&HoldingType; return TCL_OK; } static char *holdingStrings[8192]; char *getStringForHoldingNum(int hnum,int *lenPtr) { int hlength; int spots; char *source,*result; spots=hnum>>13; hnum = ((hnum>>spots)<internalRep.longValue; holding->bytes=getStringForHoldingNum(hnum,&hlength); holding->length=hlength; } void initializeHoldingType() { int i; for (i=0; i<8192; i++) { holdingStrings[i]=NULL; } HoldingType.freeIntRepProc=NULL; HoldingType.name="Holding"; HoldingType.dupIntRepProc=dupDealRepProc; HoldingType.freeIntRepProc=NULL; HoldingType.updateStringProc=updateHoldingStringRep; HoldingType.setFromAnyProc=convertToHoldingRep; Tcl_RegisterObjType(&HoldingType); } static int spadeId=KEYWORD_INVALID_ID; /* static int aceId=KEYWORD_INVALID_ID; */ static int northId=KEYWORD_INVALID_ID; /** * Procedure for walking through all holdings */ static int Deal_foreachHolding(TCLOBJ_PARAMS) TCLOBJ_DECL { int result,i; if (objc!=3) { Tcl_WrongNumArgs(interp,1,objv," { ... code ... }"); return TCL_ERROR; } for (i=0; i<=8191; i++) { Tcl_Obj *holding=Tcl_NewHoldingObj(i); Tcl_ObjSetVar2(interp,objv[1],NULL,holding,TCL_PARSE_PART1); result=Tcl_EvalObj(interp,objv[2]); if (result==TCL_BREAK) { break; } if (result==TCL_CONTINUE) { continue; } if (result!=TCL_OK) { return result; } } return TCL_OK; } static Tcl_Obj *AllSuits[4],*SuitList,*AllHands[4],*HandsList; static void initializeAllSuits() { int i; #ifdef DEAL_MEMORY fprintf(stderr,"getAllSuitObjs called, allocating suit objects\n"); #endif for (i=0; i<4; i++) { Tcl_IncrRefCount(AllSuits[i]=Keyword_NewObj(spadeId+i)); Tcl_IncrRefCount(AllHands[i]=Keyword_NewObj(northId+i)); } Tcl_IncrRefCount(SuitList=Tcl_NewListObj(4,AllSuits)); Tcl_IncrRefCount(HandsList=Tcl_NewListObj(4,AllHands)); } static int tcl_type_assert(TCLOBJ_PARAMS) TCLOBJ_DECL { int base=(int)cd; int value; if (objc!=2) { Tcl_WrongNumArgs(interp,1,objv,""); return TCL_ERROR; } value=Keyword_getIdFromObj(interp,objv[1]); if (valuebase+3) { Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": failed. '", Tcl_GetString(objv[1]), "' does not match type.", NULL); return TCL_ERROR; } return TCL_OK; } void initializeDealTypes(Tcl_Interp *interp) { static int initialized=0; Tcl_CreateObjCommand(interp,"foreachHolding",Deal_foreachHolding,NULL,NULL); if (!initialized) { Keyword_Init(interp); initializeCardType(); initializeHoldingType(); spadeId=Keyword_addKey("spades"); Keyword_addKey("hearts"); Keyword_addKey("diamonds"); Keyword_addKey("clubs"); Keyword_addKey("notrump"); northId=Keyword_addKey("north"); Keyword_addKey("east"); Keyword_addKey("south"); Keyword_addKey("west"); Keyword_alias("South","south",0); Keyword_alias("North","north",0); Keyword_alias("East","east",0); Keyword_alias("West","west",0); Tcl_CreateObjCommand(interp,"assertHandname", tcl_type_assert,(ClientData)northId,NULL); Tcl_CreateObjCommand(interp,"assertSuitname", tcl_type_assert,(ClientData)spadeId,NULL); initializeAllSuits(); initialized=1; } } int getDenomNumFromObj(Tcl_Interp *interp, Tcl_Obj *denom) { int denomNum; if (denom->typePtr!=&KeywordType) { int res=Tcl_ConvertToType(interp,denom,&KeywordType); if (res!=TCL_OK) { return NOSUIT; } } denomNum=(int)denom->internalRep.longValue-spadeId; if (denomNum>=0 && denomNum<=4) { return denomNum; } return -1; } int getSuitNumFromObj(Tcl_Interp *interp, Tcl_Obj *suit) { int suitNum; if (suit->typePtr!=&KeywordType) { int res=Tcl_ConvertToType(interp,suit,&KeywordType); if (res!=TCL_OK) { return NOSUIT; } } suitNum=(int)suit->internalRep.longValue-spadeId; if (suitNum>=0 && suitNum<=3) { return suitNum; } return NOSUIT; } int getHandNumFromObj(Tcl_Interp *interp, Tcl_Obj *hand) { int handNum; if (hand->typePtr!=&KeywordType) { int res=Tcl_ConvertToType(interp,hand,&KeywordType); if (res!=TCL_OK) { Tcl_AddErrorInfo(interp,"Couldnt covert object to KeywordType\n"); return NOSEAT; } } handNum=(int)hand->internalRep.longValue-northId; if (handNum>=0 && handNum<=3) { return handNum; } return NOSEAT; } /* Tcl_Obj* getHandKeywordObj(Tcl_Interp *interp,int num) { static Tcl_Obj *hands[4]={0,0,0,0}; static int initialized=0; if (num<0|| num>3 || northId==KEYWORD_INVALID_ID) { return NULL; } if (!initialized) { int i; for (i=0; i<4; i++) { Tcl_IncrRefCount(hands[i]=Keyword_NewObj(i+northId)); } initialized=1; } return hands[num]; } */ int getHoldingNumFromObj(Tcl_Interp *interp, Tcl_Obj *holding) { if (holding->typePtr!=&HoldingType) { int res=Tcl_ConvertToType(interp,holding,&HoldingType); if (res!=TCL_OK) { Tcl_AppendResult(interp, "Could not convert ", Tcl_GetString(holding), "to a suit holding", NULL); return -1; } } return (int)holding->internalRep.longValue; } int getCardNumFromObj(Tcl_Interp *interp, Tcl_Obj *card) { if (card->typePtr!=&CardType) { int res=Tcl_ConvertToType(interp,card,&CardType); if (res!=TCL_OK) { return NOCARD; } } return card->internalRep.longValue; } int getHandHoldingsFromObjv(Tcl_Interp *interp,Tcl_Obj * CONST *objv,int *retHoldings) { int cards=0,suit; for (suit=0; suit<4; suit++) { Tcl_Obj *hObj=objv[suit]; retHoldings[suit]=getHoldingNumFromObj(interp,hObj); if (retHoldings[suit]<0) { Tcl_AddErrorInfo(interp,Tcl_GetString(hObj)); Tcl_AddErrorInfo(interp," is an invalid holding\n"); return TCL_ERROR; } cards += counttable[8191&retHoldings[suit]]; } if (cards!=13) { Tcl_SetResult(interp,"hand does not have 13 cards.\n",TCL_STATIC); return TCL_ERROR; } return TCL_OK; } int getHandHoldingsFromObj(Tcl_Interp *interp, Tcl_Obj *obj, int *retHoldings) { int retval,length; Tcl_Obj **objv; retval=Tcl_ListObjGetElements(interp,obj,&length,&objv); if (retval!=TCL_OK || length!=4) { Tcl_SetResult(interp, "Hand argument was not a list of length 4", TCL_STATIC); return TCL_ERROR; } return getHandHoldingsFromObjv(interp,objv,retHoldings); } Tcl_Obj * CONST *getAllSuitObjs() { return AllSuits; } Tcl_Obj *getSuitList() { return SuitList; } Tcl_Obj *getSuitKeywordObj(Tcl_Interp *interp,int num) { if (num<0||num>3) { return 0; } return AllSuits[num]; } Tcl_Obj *getHandKeywordObj(Tcl_Interp *interp,int num) { if (num<0||num>3) { return 0; } return AllHands[num]; } deal319/tcl_dds.c0000644000175200017520000002366711062564550012072 0ustar cbecbe#include "deal.h" #include "tcl_incl.h" #include "dealtypes.h" #include "ddsInterface.h" #ifdef BENCH int totalNodes = 0; #endif static int LastTrump = -1; static int CountCalls = 0; static int parse_diagram(Tcl_Interp *interp,Tcl_Obj *diagram, struct deal *aDeal, int *handLength) { int retval,length; int suitHoldings[4]; int countHand[4]; Tcl_Obj **hands; int hand,suit; for (suit=0; suit<4; suit++) { suitHoldings[suit]=0; for (hand=0; hand<4; hand++) { aDeal->remaining.cards[hand][suit]=0; } } retval = Tcl_ListObjGetElements(interp,diagram,&length,&hands); if (retval !=TCL_OK) { return TCL_ERROR; } if (length!=4) { return TCL_ERROR; } for (hand=0; hand<4; hand++) { int suitCount; Tcl_Obj **suits; countHand[hand] = 0; retval = Tcl_ListObjGetElements(interp,hands[hand],&suitCount, &suits); if (retval != TCL_OK) { return TCL_ERROR; } if (suitCount>4) { return TCL_ERROR; } for (suit=0; suitremaining.cards[hand][suit] = holding; suitLength = counttable[holding]; countHand[hand] += suitLength; if (suitHoldings[suit] & holding) { /* Not disjoint */ return TCL_ERROR; } suitHoldings[suit] |= (holding); } } for (hand=1; hand<4; hand++) { if (countHand[hand] != countHand[0]) { /* Hands not all same size */ return TCL_ERROR; } } *handLength = countHand[0]; return TCL_OK; } static int tcl_double_dummy_reset(TCLOBJ_PARAMS) TCLOBJ_DECL { LastTrump = -1; return TCL_OK; } static int tcl_dds(TCLOBJ_PARAMS) TCLOBJ_DECL { static int doInit=1, DiagramFlagID=-1, GoalFlagID=-1, NoReuseFlagID=-1, ReuseFlagID=-1, LeaderFlagID=-1, TrickFlagID=-1; int goal=-1; int playerGoal = -1; int hand, suit,result; int mode=-1; int declarer = 2; struct deal d; int status; int handLength; int cardsPlayedToTrick=0; int totalTricksPlayed=0; int played[4]; Tcl_Obj *diagram = NULL; struct futureTricks futp; if (doInit) { ReuseFlagID=Keyword_addKey("-reuse"); NoReuseFlagID=Keyword_addKey("-noreuse"); DiagramFlagID=Keyword_addKey("-diagram"); GoalFlagID=Keyword_addKey("-goal"); LeaderFlagID=Keyword_addKey("-leader"); TrickFlagID=Keyword_addKey("-trick"); doInit=0; } memset(&(d.currentTrickSuit), 0, 3*sizeof(int)); memset(&(d.currentTrickRank), 0, 3*sizeof(int)); d.trump=4; /* notrump */ d.first=-1; /* unknown */ for (suit=0; suit<4; suit++) { played[suit] = 0; } while (objc > 1) { int id = Keyword_getIdFromObj(interp,objv[1]); objv++; objc--; if (id == ReuseFlagID) { mode=2; continue; } if (id == NoReuseFlagID) { mode=1; continue; } if (id == DiagramFlagID || id == GoalFlagID || id == LeaderFlagID || id == TrickFlagID) { Tcl_Obj *arg = objv[1]; if (objc>1) { objc--; objv++; } else { return TCL_ERROR; } if (id == DiagramFlagID) { if (diagram!=NULL) { return TCL_ERROR; } diagram = arg; } else if (id == GoalFlagID ) { if (TCL_ERROR == Tcl_GetIntFromObj(interp,arg,&goal) || (goal!=-1 && (goal<1 && goal>13))) { Tcl_AppendResult(interp,"Invalid tricks goal: ",Tcl_GetString(arg),NULL); return TCL_ERROR; } } else if (id == LeaderFlagID) { d.first = getHandNumFromObj(interp,arg); if (d.first == NOSEAT) { Tcl_AppendResult(interp,"invalid seat name passed to -leader: ",Tcl_GetString(arg),NULL); return TCL_ERROR; } } else if (id == TrickFlagID) { Tcl_Obj **cards; int playNo,rank; if (cardsPlayedToTrick!=0) { Tcl_AppendResult(interp,"No additional tricks after an incomplete trick",NULL); } if (TCL_ERROR == Tcl_ListObjGetElements(interp,arg,&cardsPlayedToTrick,&cards) || cardsPlayedToTrick>4) { Tcl_AppendResult(interp,"Invalid -trick argument: ",Tcl_GetString(arg),NULL); return TCL_ERROR; } for (playNo=0; playNo 2) { d.trump = getDenomNumFromObj(interp,objv[2]); if (d.trump==-1) { Tcl_AppendResult(interp,"Invalid denomination: ", Tcl_GetString(objv[2]), NULL); return TCL_ERROR; } } if (objc > 1) { declarer = getHandNumFromObj(interp,objv[1]); if (declarer == NOSEAT) { Tcl_AppendResult(interp,"invalid declarer name passed: ",Tcl_GetString(objv[1]),NULL); return TCL_ERROR; } } if (d.first==-1) { d.first = (declarer+1)%4; } if (diagram != NULL) { int retval = parse_diagram(interp,diagram, &d,&handLength); if (retval != TCL_OK) { return TCL_ERROR; } } else { finish_deal(); handLength = 13; for (hand=0; hand<4; hand++) { /* Double dummy solver has north hand zero */ int ddsHand = hand; for (suit=0; suit<4; suit++) { d.remaining.cards[ddsHand][suit] = globalDeal.hand[hand].suit[suit]; } } } for (hand=0; hand<4; hand++) { for (suit=0; suit<4; suit++) { d.remaining.cards[hand][suit] &= (~played[suit]); } } handLength = handLength - totalTricksPlayed; if (goal>0) { if ((d.first + cardsPlayedToTrick + declarer)&1) { playerGoal = (handLength + 1)-goal; /* Goal passed to DDS */ } else { playerGoal = goal; /* Goal passed to DDS */ } } if (CountCalls == 0) { mode = 0; } else if ( mode == -1 ) { if (d.trump != LastTrump || diagram != NULL) { mode = 1; } else { mode = 2; } } /* fprintf(stderr,"mode = %d\n",mode); */ status = SolveBoard(d,playerGoal,1,mode,&futp); LastTrump = d.trump; CountCalls++; if (status != 1) { Tcl_SetObjResult(interp,Tcl_NewIntObj(status)); Tcl_AppendResult(interp,": dds failed due to error status from double dummy solver",NULL); return TCL_ERROR; } #ifdef BENCH totalNodes += futp.totalNodes; printf("nodes=%d totalNodes=%d\n",futp.totalNodes,totalNodes); #endif if (futp.score[0]==-2) { /* Defender takes all the tricks */ result = 0; } else if (futp.score[0]==-1) { if (goal>0) { result = 1; } else { result = handLength; } } else { if ((d.first + cardsPlayedToTrick + declarer)&1) { result = handLength-futp.score[0]; } else { result = futp.score[0]; } if (goal>0) { result = (result>=goal); } } Tcl_SetObjResult(interp,Tcl_NewIntObj(result)); return TCL_OK; } /* This code directly borrows from Alex Martelli's Python interface to dds. */ static int tcl_double_dummy_solve(TCLOBJ_PARAMS) TCLOBJ_DECL { int goal=-1; int leaderGoal = -1; int hand, suit,result; int mode; struct deal d; int status; struct futureTricks futp; memset(&(d.currentTrickSuit), 0, 3*sizeof(int)); memset(&(d.currentTrickRank), 0, 3*sizeof(int)); d.trump=4; /* notrump */ d.first=WEST; /* west */ finish_deal(); if (objc > 2) { d.trump = getDenomNumFromObj(interp,objv[2]); if (d.trump==-1) { Tcl_AppendResult(interp,"Invalid denomination: ", Tcl_GetString(objv[2]), NULL); return TCL_ERROR; } } if (objc > 1) { int declarer = getHandNumFromObj(interp,objv[1]); if (declarer == NOSEAT) { Tcl_AppendResult(interp,"invalid seat name passed: ",Tcl_GetString(objv[1]),NULL); return TCL_ERROR; } d.first = (declarer+1)%4; } if (objc > 3) { if (TCL_ERROR == Tcl_GetIntFromObj(interp,objv[3],&goal) || (goal!=-1 && (goal<1 && goal>13))) { Tcl_AppendResult(interp,"Invalid tricks goal: ",Tcl_GetString(objv[3]),NULL); return TCL_ERROR; } } if (goal>0) { leaderGoal = 14-goal; /* Goal passed to DDS */ } for (hand=0; hand<4; hand++) { /* Double dummy solver has north hand zero */ int ddsHand = hand; for (suit=0; suit<4; suit++) { d.remaining.cards[ddsHand][suit] = globalDeal.hand[hand].suit[suit]; } } if (d.trump != LastTrump) { if (CountCalls == 0) { mode = 0; } else { mode = 1; } } else { mode = 2; } /* fprintf(stderr,"mode = %d\n",mode); */ status = SolveBoard(d,leaderGoal,1,mode,&futp); LastTrump = d.trump; CountCalls++; if (status != 1) { Tcl_SetObjResult(interp,Tcl_NewIntObj(status)); Tcl_AppendResult(interp,"dds failed due to error status from double dummy solver",NULL); return TCL_ERROR; } #ifdef BENCH totalNodes += futp.totalNodes; printf("nodes=%d totalNodes=%d\n",futp.totalNodes,totalNodes); #endif if (futp.score[0]==-2) { /* Defender takes all the tricks */ result = 0; } else if (futp.score[0]==-1) { if (goal>0) { result = 1; } else { result = 13; } } else { result = 13-futp.score[0]; if (goal>0) { result = (result>=goal); } } Tcl_SetObjResult(interp,Tcl_NewIntObj(result)); return TCL_OK; } int DDS_Init(interp) Tcl_Interp *interp; { DDSInitStart(); Tcl_CreateObjCommand(interp,"tricks",tcl_double_dummy_solve,NULL,NULL); Tcl_CreateObjCommand(interp,"dds",tcl_dds,NULL,NULL); Tcl_CreateObjCommand(interp,"dds_reset",tcl_double_dummy_reset,NULL,NULL); return TCL_OK; } deal319/LICENSE0000644000175200017520000000207111062564550011301 0ustar cbecbeCopyright (C) 1996-2001, Thomas Andrews. Deal is released under the GNU General Public License. See the file, GPL, for the complete text of the license. The DDS code is under a different license and copyright. The file random.c has a seperate copyright: /* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ deal319/dist.c0000644000175200017520000004614511062564550011415 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This set of routines implements the 'shapeclass' and * 'shapefunc' methods. */ #include #include "deal.h" #include "dist.h" #include "dealtypes.h" #include HandDist dist_table[DIST_COUNT]; static Tcl_Obj *shapeObjs[DIST_COUNT]; static Tcl_Obj *shapeParams=NULL; /* Will contain constant list "s h d c" */ static Tcl_Obj* lengthObjs[14]; static void InitializeLengths() { int i; for (i=0; i<=13; i++) { Tcl_IncrRefCount(lengthObjs[i]=Tcl_NewIntObj(i)); } } /* * The set of distributions for a hand are in 1-1 correspondence * with the set of of 3-subsets of the numbers {0,1,...,15}; if * our distribution is S-H-D-C, then we choose as our 3-subset * S,S+H+1,S+H+D+2. * * I have chosen to use the "squashed order" for the 3-subsets * as the basis for numbering the distributions because it is * easy to compute the index of the 3-subset from it's elements. * * For information about the squashed order, see: * Anderson, "Combinatorics of Finite Sets", pp 112-119. * * I'm sure there is an easier way, but my brain is too tired, and this * should work well enough. */ /* * This method, while sound, isn't as quick as just using * pointers to pointers. I've left it in as a reminder * static int distTableIndex(s,h,d) int s,h,d; { * * * int f1=s, f2=s+h+1, f3=s+h+d+2; * (f3 choose 3) + (f2 choose 2) + (f1 choose 1) * return f3*(f3-1)*(f3-2)/6+f2*(f2-1)/2+f1; * I've pretabulated the (x choose 2) and (x choose 3) functions for even easier lookup; this function is suitable for inlining. static choose2tab[]={0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91}; static choose3tab[]={0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286, 364, 455}; return choose3tab[s+h+d]+choose2tab[s+h]+s; } */ void computeDistTable() { int s,h,d; int entry=0; Tcl_Obj *lengths[4]; Tcl_Obj *shapeObj; for (s=0;s<=13; s++) { lengths[0]=lengthObjs[s]; for (h=0; h<=13-s; h++) { lengths[1]=lengthObjs[h]; for (d=0; d<=13-s-h; d++) { int c=13-s-h-d; lengths[2]=lengthObjs[d]; lengths[3]=lengthObjs[c]; dist_table[entry][SPADES]=s; dist_table[entry][HEARTS]=h; dist_table[entry][DIAMONDS]=d; dist_table[entry][CLUBS]=13-s-h-d; shapeObj=Tcl_NewListObj(4,lengths); Tcl_IncrRefCount(shapeObjs[entry]=shapeObj); entry++; } } } } void printDistTable() { int i; for (i=0; iarray2[i]; if (obj != (Tcl_Obj*) NULL) { Tcl_DecrRefCount(obj); } } Tcl_Free(data); } DistFunc newDistFunc(n) int n; { int s,h,d; int index1=0,index2=0; DistFunc func=(DistFunc)Tcl_Alloc(n*sizeof(struct distfunc)); for (s=0; s<=13; s++) { func->array[s] = index1+(func->array1); for (h=0; h<=13-s; h++,index1++) { func->array1[index1]= index2 + (func->array2); for (d=0; d<=13-s-h; d++, index2++) { func->array2[index2] = 0; } } } return func; } DistSet newDistSet(n) int n; { int s,h,d; int index1=0,index2=0; DistSet set=(DistSet)Tcl_Alloc(n*sizeof(struct distset)); for (s=0; s<=13; s++) { set->array[s] = index1+(set->array1); for (h=0; h<=13-s; h++,index1++) { set->array1[index1]= index2 + (set->array2); for (d=0; d<=13-s-h; d++, index2++) { set->array2[index2] = NULL; } } } set->shapesList=NULL; return set; } void deleteDistSet(ClientData cd) { DistSet set=(DistSet)cd; int i; for (i=0; iarray2[i]!=NULL) { Tcl_DecrRefCount(set->array2[i]); } } Tcl_Free((char*)set); } int tcl_shapefunc_eval ( TCLOBJ_PARAMS ) TCLOBJ_DECL { static int handSubCmd=-1,compileSubCmd=-1, evalSubCmd=-1, shapeSubCmd, subCmdInit=1; int hand; char *result,*rptr; int i; int s,h,d,c; DistFunc set=(DistFunc) cd; if (subCmdInit) { handSubCmd=Keyword_addKey("hand"); compileSubCmd=Keyword_addKey("compile"); evalSubCmd=Keyword_addKey("eval"); shapeSubCmd=Keyword_addKey("shape"); subCmdInit=0; } if (objc==1) { Tcl_WrongNumArgs(interp,1,objv,"handname"); Tcl_AppendResult(interp,"\tor\n",0); Tcl_WrongNumArgs(interp,1,objv,"hand "); Tcl_AppendResult(interp,"\tor\n",0); Tcl_WrongNumArgs(interp,1,objv,"hand eval "); Tcl_AppendResult(interp,"\tor\n",0); Tcl_WrongNumArgs(interp,1,objv,"hand shape { }"); return TCL_ERROR; } if (NOSEAT==(hand=getHandNumFromObj(interp,objv[1]))) { int subCmd=Keyword_getIdFromObj(interp,objv[1]); if (subCmd==compileSubCmd) { int len; char *command=Tcl_GetString(objv[0]); result=(char *)Tcl_Alloc(8*DIST_COUNT+strlen(command)+50); sprintf(result,"shapeclass.binary %s {\n",command); rptr=result+strlen(result); for (i=1;i<=DIST_COUNT; i++) { if (i%8==1) { *(rptr++)='\t'; } sprintf(rptr,"%s",Tcl_GetStringFromObj(DFVal(set,i-1),&len)); rptr += len; if (i%8==0) { *(rptr++)='\n'; } else { *(rptr++)=' '; } } strcpy(rptr,"\n}\n"); Tcl_SetResult(interp,result,TCL_DYNAMIC); return TCL_OK; } if (subCmd==handSubCmd) { int retval,suit,holding[4],lengths[4]; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,""); return TCL_ERROR; } retval=getHandHoldingsFromObj(interp,objv[2],holding); if (retval!=TCL_OK) { Tcl_SetResult(interp,"Argument was not a list of four holdings", TCL_STATIC); return TCL_ERROR; } for (suit=0; suit<4; suit++) { lengths[suit]=(counttable[holding[suit]&8191]); } s=lengths[0]; h=lengths[1]; d=lengths[2]; c=lengths[3]; } else if (subCmd==evalSubCmd) { if (objc!=6) { Tcl_WrongNumArgs(interp,2,objv,"slen hlen dlen clen"); return TCL_ERROR; } Tcl_GetIntFromObj(interp,objv[2],&s); Tcl_GetIntFromObj(interp,objv[3],&h); Tcl_GetIntFromObj(interp,objv[4],&d); Tcl_GetIntFromObj(interp,objv[5],&c); } else if (subCmd==shapeSubCmd) { int retval; Tcl_Obj **objv2=NULL; int objc2=0; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,"{slen hlen dlen clen}"); return TCL_ERROR; } retval=Tcl_ListObjGetElements(interp,objv[2],&objc2,&objv2); if (retval==TCL_ERROR || objc2!=4) { Tcl_SetResult(interp,"Shape must be a list of four suit lengths", TCL_STATIC); return TCL_ERROR; } Tcl_GetIntFromObj(interp,objv2[0],&s); Tcl_GetIntFromObj(interp,objv2[1],&h); Tcl_GetIntFromObj(interp,objv2[2],&d); Tcl_GetIntFromObj(interp,objv2[3],&c); } else { char *command=Tcl_GetString(objv[0]); Tcl_AppendResult(interp,Tcl_GetString(objv[1]), " is not a legitimate subcommand for the shapefunc ", command, NULL); return TCL_ERROR; } } else { if (objc!=2) { Tcl_WrongNumArgs(interp,2,objv,0); return TCL_ERROR; } FINISH(hand); s=count_suit(hand,SPADES); h=count_suit(hand,HEARTS); d=count_suit(hand,DIAMONDS); c=count_suit(hand,CLUBS); } if (s+h+d+c!=13) { Tcl_SetResult(interp,"Suit lengths did not add to 13",TCL_STATIC); return TCL_ERROR; } Tcl_SetObjResult(interp,set->array[s][h][d]); return TCL_OK; } int tcl_shapeclass_eval ( TCLOBJ_PARAMS ) TCLOBJ_DECL { static int subCmdInit=1, compileSubCmd=-1, handSubCmd=-1, evalSubCmd=-1, listSubCmd=-1, shapeSubCmd=-1; int hand; char *result,*rptr; int i; int s,h,d,c; DistSet set=(DistSet) cd; if (subCmdInit) { handSubCmd=Keyword_addKey("hand"); compileSubCmd=Keyword_addKey("compile"); evalSubCmd=Keyword_addKey("eval"); listSubCmd=Keyword_addKey("list"); shapeSubCmd=Keyword_addKey("shape"); subCmdInit=0; } if (objc==1) { Tcl_WrongNumArgs(interp,1,objv,"list"); Tcl_AppendResult(interp,"\tor\n",0); Tcl_WrongNumArgs(interp,1,objv,""); Tcl_AppendResult(interp,"\tor\n",0); Tcl_WrongNumArgs(interp,1,objv,"hand "); Tcl_AppendResult(interp,"\tor\n",0); Tcl_WrongNumArgs(interp,1,objv,"hand eval "); Tcl_AppendResult(interp,"\tor\n",0); return TCL_ERROR; } if (NOSEAT==(hand=getHandNumFromObj(interp,objv[1]))) { int subCmdId=Keyword_getIdFromObj(interp,objv[1]); if (subCmdId==listSubCmd) { if (objc!=2) { Tcl_WrongNumArgs(interp,2,objv,0); return TCL_ERROR; } if (set->shapesList==NULL) { Tcl_Obj *explicit[DIST_COUNT],*current; int ret,value,count=0; for (i=0; ishapesList=Tcl_NewListObj(count,explicit)); } Tcl_SetObjResult(interp,set->shapesList); return TCL_OK; } if (subCmdId==compileSubCmd) { char *name=Tcl_GetString(objv[0]); result=(char *)Tcl_Alloc(1+DIST_COUNT+strlen(name)+1024); sprintf(result,"shapeclass.binary %s {\n",name); rptr=result+strlen(result); for (i=1;i<=DIST_COUNT; i++) { Tcl_Obj *obj=DSElt(set,i-1); int isElt; int ret=Tcl_GetBooleanFromObj(interp,obj,&isElt); if (ret!=TCL_OK) { Tcl_Free(result); return ret; } if (i%32==1) { *(rptr++)='\t'; } *(rptr++)=(isElt ? '1' : '0'); if (i%32==0) { *(rptr++)='\n'; } else { if (i%8==0) { *(rptr++)=' '; } } } strcpy(rptr,"\n}\n"); Tcl_SetResult(interp,result,TCL_DYNAMIC); return TCL_OK; } if (subCmdId==handSubCmd) { int retval,suit,hnum[4],lengths[4]; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,""); return TCL_ERROR; } retval=getHandHoldingsFromObj(interp,objv[2],hnum); if (retval!=TCL_OK) { Tcl_AddErrorInfo(interp,"Argument was not a valid hand"); return TCL_ERROR; } for (suit=0; suit<4; suit++) { lengths[suit]=counttable[hnum[suit]&8191]; } s=lengths[0]; h=lengths[1]; d=lengths[2]; c=lengths[3]; } else if (subCmdId==evalSubCmd) { if (objc!=6) { Tcl_WrongNumArgs(interp,2,objv," "); return TCL_ERROR; } Tcl_GetIntFromObj(interp,objv[2],&s); Tcl_GetIntFromObj(interp,objv[3],&h); Tcl_GetIntFromObj(interp,objv[4],&d); Tcl_GetIntFromObj(interp,objv[5],&c); } else if (subCmdId==shapeSubCmd) { int retval; Tcl_Obj **objv2=NULL; int objc2=0; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,"{ }"); return TCL_ERROR; } retval=Tcl_ListObjGetElements(interp,objv[2],&objc2,&objv2); if (retval==TCL_ERROR || objc2!=4) { Tcl_SetResult(interp,"Error trying to parse shape ",TCL_STATIC); Tcl_AppendResult(interp,Tcl_GetString(objv[2]),NULL); return TCL_ERROR; } Tcl_GetIntFromObj(interp,objv2[0],&s); Tcl_GetIntFromObj(interp,objv2[1],&h); Tcl_GetIntFromObj(interp,objv2[2],&d); Tcl_GetIntFromObj(interp,objv2[3],&c); } else { char *command=Tcl_GetString(objv[0]); Tcl_AppendResult(interp,Tcl_GetString(objv[1]), " is not a legitimate subcommand for the shapeclass ", command, NULL); return TCL_ERROR; } } else { FINISH(hand); s=count_suit(hand,SPADES); h=count_suit(hand,HEARTS); d=count_suit(hand,DIAMONDS); c=count_suit(hand,CLUBS); } if (s+h+d+c!=13) { Tcl_SetResult(interp,"Shape did not have 13 cards.",TCL_STATIC); return TCL_ERROR; } Tcl_SetObjResult(interp,set->array[s][h][d]); return TCL_OK; } static int ShapeProcDefine(interp,name,procBody) Tcl_Interp *interp; Tcl_Obj *name; Tcl_Obj *procBody; { static Tcl_Obj *procCmd=NULL; Tcl_Obj *code[4]; if (procCmd==NULL) { Tcl_IncrRefCount(procCmd=Tcl_NewStringObj("proc",4)); } code[0]=procCmd; code[1]=name; code[2]=shapeParams; code[3]=procBody; return Tcl_EvalObjv(interp,4,code,TCL_EVAL_GLOBAL); } DistFunc shapefunc_compile(interp,name,procBody) Tcl_Interp *interp; Tcl_Obj *name; Tcl_Obj *procBody; { int result; DistFunc func; char *nameStr; int spades,hearts,diamonds,clubs; Tcl_Obj *array[5],*value; func=newDistFunc(1); if (func==0) { return 0; } result=ShapeProcDefine(interp,name,procBody); nameStr=Tcl_GetString(name); if (result==TCL_ERROR) { deleteDistFunc(func); Tcl_AppendResult(interp,"\nCould not compile function ",nameStr,"\n",NULL); return 0; } array[0]=name; for (spades=0; spades<=13; spades++) { array[1]=lengthObjs[spades]; for (hearts=0; hearts<=13-spades; hearts++) { array[2]=lengthObjs[hearts]; for (diamonds=0; diamonds<=13-spades-hearts; diamonds++) { array[3]=lengthObjs[diamonds]; clubs=13-spades-hearts-diamonds; array[4]=lengthObjs[clubs]; result=Tcl_EvalObjv(interp,5,array,TCL_EVAL_GLOBAL); if (result==TCL_ERROR) { deleteDistFunc(func); Tcl_AppendResult(interp,"\nCould not compile function ",nameStr,"\n", NULL); return 0; } value=Tcl_GetObjResult(interp); func->array[spades][hearts][diamonds]=value; Tcl_IncrRefCount(value); } } } Tcl_ResetResult(interp); /* Clear interp results... */ return func; } DistSet shapeclass_compile(interp,name,procBody) Tcl_Interp *interp; Tcl_Obj *name; Tcl_Obj *procBody; { int result; DistSet set; int spades,hearts,diamonds,clubs; Tcl_Obj *callCmd[5],*value; char *nameStr; set=newDistSet(1); result=ShapeProcDefine(interp,name,procBody); nameStr=Tcl_GetString(name); if (result==TCL_ERROR) { deleteDistSet((ClientData)set); Tcl_AppendResult(interp,"\nCould not compile function ", nameStr, NULL); return 0; } callCmd[0]=name; for (spades=0; spades<=13; spades++) { callCmd[1]=lengthObjs[spades]; for (hearts=0; hearts<=13-spades; hearts++) { callCmd[2]=lengthObjs[hearts]; for (diamonds=0; diamonds<=13-spades-hearts; diamonds++) { callCmd[3]=lengthObjs[diamonds]; clubs=13-spades-hearts-diamonds; callCmd[4]=lengthObjs[clubs]; result=Tcl_EvalObjv(interp,5,callCmd,TCL_EVAL_GLOBAL); if (result==TCL_ERROR) { deleteDistSet((ClientData)set); Tcl_AppendResult(interp,"\nCould not compile function ", nameStr, NULL); return 0; } value=Tcl_GetObjResult(interp); set->array[spades][hearts][diamonds]=value; Tcl_IncrRefCount(value); } } } Tcl_ResetResult(interp); return set; } int tcl_shapefunc_lazy ( TCLOBJ_PARAMS ) TCLOBJ_DECL { Tcl_Obj *procBody=(Tcl_Obj *)cd; char *name=Tcl_GetString(objv[0]); DistFunc func=shapefunc_compile(interp,objv[0],procBody); if (func==(DistFunc)NULL) { Tcl_AppendResult(interp,"Error compiling\n",NULL); return TCL_ERROR; } Tcl_CreateObjCommand(interp,name,tcl_shapefunc_eval,(ClientData)func, deleteDistFunc); return tcl_shapefunc_eval((ClientData) func,interp,objc,objv); } DistSet shapeclass_lazy_compile (interp,nameObj,procBody) Tcl_Interp *interp; Tcl_Obj *nameObj; Tcl_Obj *procBody; { DistSet set=shapeclass_compile(interp,nameObj,procBody); char *name; if (set==(DistSet)NULL) { return 0; } name=Tcl_GetString(nameObj); Tcl_CreateObjCommand(interp,name,tcl_shapeclass_eval,(ClientData)set, deleteDistSet); return set; } int tcl_shapeclass_lazy ( TCLOBJ_PARAMS ) TCLOBJ_DECL { Tcl_Obj *procBody=(Tcl_Obj *)cd; DistSet set=shapeclass_lazy_compile(interp,objv[0],procBody); if (set==(DistSet)0) { Tcl_AddErrorInfo(interp,"Error compiling shape class "); Tcl_AddErrorInfo(interp,Tcl_GetString(objv[0])); return TCL_ERROR; } return tcl_shapeclass_eval((ClientData) set,interp,objc,objv); } int tcl_shapeexpr_define ( TCLOBJ_PARAMS ) TCLOBJ_DECL { static Tcl_Obj *exprCmd=NULL; int isClass=(int)cd; Tcl_Obj *cmdElts[2]; Tcl_Obj *command; char *name; if (exprCmd==NULL) { Tcl_IncrRefCount(exprCmd=Tcl_NewStringObj("expr",4)); } if (objc!=3) { Tcl_WrongNumArgs(interp,1,objv," "); return TCL_ERROR; } name=Tcl_GetString(objv[1]); cmdElts[0]=exprCmd; cmdElts[1]=objv[2]; Tcl_IncrRefCount(command=Tcl_NewListObj(2,cmdElts)); if (isClass) { Tcl_CreateObjCommand(interp,name,tcl_shapeclass_lazy,(ClientData)command,&Tcl_ObjDelete); } else { Tcl_CreateObjCommand(interp,name,tcl_shapefunc_lazy,(ClientData)command,&Tcl_ObjDelete); } return TCL_OK; } int tcl_shapefunc_define ( TCLOBJ_PARAMS ) TCLOBJ_DECL { char *name; if (objc!=3) { Tcl_WrongNumArgs(interp,1,objv," "); return TCL_ERROR; } name=Tcl_GetString(objv[1]); Tcl_IncrRefCount(objv[2]); Tcl_CreateObjCommand(interp,name,tcl_shapefunc_lazy,(ClientData)objv[2],Tcl_ObjDelete); return TCL_OK; } int tcl_shapeclass_define ( TCLOBJ_PARAMS ) TCLOBJ_DECL { char *name; if (objc!=3) { Tcl_WrongNumArgs(interp,1,objv," "); return TCL_ERROR; } name=Tcl_GetString(objv[1]); Tcl_IncrRefCount(objv[2]); Tcl_CreateObjCommand(interp,name,tcl_shapeclass_lazy,(ClientData)objv[2],Tcl_ObjDelete); return TCL_OK; } int tcl_shapeclass_define_binary ( TCL_PARAMS ) TCL_DECL { DistSet set; CONST84 char *s; int i; if (argc!=3) { return TCL_ERROR; } set=newDistSet(1); for (i=0; iarray2[i]=Tcl_NewBooleanObj(0)); } for (i=0,s=argv[2]; (*s) && (i=2, and 0 for rank<2. */ return (1<>2; } template inline INT smallestBitInInteger(INT value) { return value & (-value); } inline holding_t smallestRankInSuit(holding_t h) { return smallestBitInInteger(h); } inline int InvBitMapRank(holding_t bitMap) { switch (bitMap) { case 0x1000: return 14; case 0x0800: return 13; case 0x0400: return 12; case 0x0200: return 11; case 0x0100: return 10; case 0x0080: return 9; case 0x0040: return 8; case 0x0020: return 7; case 0x0010: return 6; case 0x0008: return 5; case 0x0004: return 4; case 0x0002: return 3; case 0x0001: return 2; default: return 0; } } inline int InvWinMask(int mask) { switch (mask) { case 0x01000000: return 1; case 0x00400000: return 2; case 0x00100000: return 3; case 0x00040000: return 4; case 0x00010000: return 5; case 0x00004000: return 6; case 0x00001000: return 7; case 0x00000400: return 8; case 0x00000100: return 9; case 0x00000040: return 10; case 0x00000010: return 11; case 0x00000004: return 12; case 0x00000001: return 13; default: return 0; } } #endif deal319/GPL0000644000175200017520000004313111062564550010643 0ustar cbecbe GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. deal319/getopt.h0000644000175200017520000001445711062564550011762 0ustar cbecbe/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ deal319/vector.h0000644000175200017520000000262611062564550011755 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ typedef struct lazy_vector_data { int num; int value[13]; } *LazyVectorData; LazyVectorData newLazyVector PROTO( () ); typedef int *VectorTable; #define VectorTableLookup(table,holding) \ table[1+((8191&holding)>>(table[0]))] int vectorCount PROTO( (VectorTable,int,int) ); /* * * Gross - should define this as a static function and * hope the compiler inlines the code. * */ #define SetVectorData(vector,i,val) \ {\ int ___i=i,___val=(val); LazyVectorData ___vec=(vector);\ if (___i>=0 && ___i<=13) {\ ___vec->value[___i]=(___val);\ if (___i>___vec->num && (___val!=0)) { ___vec->num=___i; }\ }\ } deal319/holdings.h0000644000175200017520000000151611062564550012257 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "deck.h" extern int IDealHolding_Init _ANSI_ARGS_((Tcl_Interp *)); deal319/deal.c0000644000175200017520000003032511102073544011341 0ustar cbecbe/* * deal.c - Mostly Tcl-free code for dealing. This is the "heart" * of Deal. * * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "deal.h" char *suitname[]={"spades","hearts","diamonds","clubs"}; char *handname[]={"north","east","south","west"}; RawDeal globalDeal; RawDist globalDist; struct deck_stacker stacker; struct deck complete_deal; /* These are here for backward compatibility reasons */ int *distributions[]={ globalDist.hand[0].suit, globalDist.hand[1].suit, globalDist.hand[2].suit, globalDist.hand[3].suit }; int *holdings[]={ globalDeal.hand[0].suit, globalDeal.hand[1].suit, globalDeal.hand[2].suit, globalDeal.hand[3].suit }; char suits[]="SHCD"; char cards[]="AKQJT98765432"; int verbose=0; #define fast_mod(n,d) ((n)%(d)) int reset_deck() { int i; stacker.dealt=0; for (i=0; i<52; i++) { stacker.card[i] = NOCARD; stacker.whom[i]=NOSEAT; stacker.where[i]=-1; } for (i=0; i<4; i++) { stacker.handcount[i]=0; } #ifdef DEBUG fprintf(stderr,"Reset deck\n"); #endif return TCL_OK; } void get_distribution_hand(hand) int hand; { int suit; for (suit=0; suit<4; suit++) { globalDist.hand[hand].suit[suit]=(int) counttable[globalDeal.hand[hand].suit[suit]]; } } int count_deals=0; void old_reset_deal(dealp) struct deck *dealp; { int card, hand; dealp->dealt=0; for (card=0; card<52; card++) { dealp->card[card]=card; dealp->whom[card]=NOSEAT; dealp->where[card]=card; } for (hand=0; hand<4; hand++) { dealp->handcount[hand]=0; dealp->finished[hand]=0; } } void reset_deal(dealp) struct deck *dealp; { int hand,suit; static struct deck initializeOnce; static int needsInit=1; if (needsInit) { old_reset_deal(&initializeOnce); needsInit=0; } memcpy(dealp,&initializeOnce,sizeof(struct deck)); for (hand=0; hand<4; hand++) { for (suit=0; suit<4; suit++) { globalDeal.hand[hand].suit[suit]=0; } } } #ifdef DEBUG static void assert_deck(dealp) struct deck *dealp; { int loc,card; for (loc=0; loc<52; loc++) { card=dealp->card[loc]; if (dealp->where[card]!=loc) { #ifdef __CENTERLINE__ centerline_stop(); #else abort(); #endif } } } #endif /* This amounts to a swap command, with lots of record keeping added to keep "where" and "card" as inverses */ void deal_put(dealp,card,whom) struct deck *dealp; int card,whom; { int where=dealp->where[card]; /* Where the card is, currently */ int loc=dealp->dealt; /* Where it will be placed */ int othercard=dealp->card[loc]; /* The card currently in this place */ /* Swapping "loc" with "where" in the array */ dealp->card[where]=othercard; dealp->card[loc]=card; dealp->where[othercard]=where; dealp->where[card]=loc; dealp->handcount[whom]++; dealp->whom[loc]=whom; /* Give the card to whom */ globalDeal.hand[whom].suit[SUIT(card)] |= (1 << (12- (RANK(card)))); dealp->dealt++; #ifdef DEBUG assert_deck(dealp); #endif } void place_fixed_cards(dealp) struct deck *dealp; { int i=0; while (i=3) { return TCL_ERROR; } hand++; suit=SPADES; cardsHand=0; break; case '\n': if (cardsHand!=13 || cardsDeck!=52) { return TCL_ERROR; } start_deal(); return TCL_OK; default: if (cardsHand>=13 || NORANK==(card=card_name_table[c])) { return TCL_ERROR; } cardsHand++; cardsDeck++; put_card(hand,CARD(card,suit)); break; } } if (cardsDeck!=0) { return TCL_ERROR;} return TCL_RETURN; } char *format_deal_compact () { char s[4][26]; char *result=(char *)Tcl_Alloc(52*2); char *s1[4]; int hand,suit,denom; for (hand=0; hand<4; hand++) s1[hand]=s[hand]; for (suit=0; suit<4; suit++) { for (denom=0; denom <13; denom++) { int card=CARD(denom,suit); int where=complete_deal.where[card]; if (!(denom)) { for (hand=0; hand<4; hand++) { *(s1[hand]++)=' '; } } *(s1[complete_deal.whom[where]]++)=cards[denom]; } } for (hand=0; hand<4; hand++) { *(s1[hand])=0; } sprintf(result,"%s|%s|%s|%s\n",1+s[0],1+s[1],1+s[2],1+s[3]); return result; } char *format_deal_verbose() { static char suit_chars[]="SHDC"; char a[4][4][14]; char *p[4][4]; char *result,*rp; int suit,hand,card,where; for(hand=0; hand<4; hand++) for(suit=0; suit<4; suit++) p[hand][suit]=&a[hand][suit][0]; for (suit=0; suit<4; suit++) for (card=0; card <52; card += 4) { where=complete_deal.where[card+suit]; *(p[complete_deal.whom[where]][suit]++)=cards[card>>2]; } for(hand=0; hand<4; hand++) for(suit=0; suit<4; suit++) if (p[hand][suit] == &a[hand][suit][0]) { strcpy(p[hand][suit],"---"); } else { *(p[hand][suit])=0; } rp=result=(char *)Tcl_Alloc(2048); for (suit=0; suit<4; suit++) { sprintf(rp," %c : %s\n",suit_chars[suit],a[NORTH][suit]); rp=rp+strlen(rp); } for (suit=0; suit<4; suit++) { sprintf(rp," %c : %-13s %c : %-13s\n",suit_chars[suit],a[WEST][suit], suit_chars[suit],a[EAST][suit]); rp=rp+strlen(rp); } for (suit=0; suit<4; suit++) { sprintf(rp," %c : %s\n",suit_chars[suit],a[SOUTH][suit]); rp=rp+strlen(rp); } sprintf(rp,"---------------------------\n"); return result; } int hand_name_table[256]; int suit_name_table[256]; int card_name_table[256]; void init_name_tables() { int i; for (i=0; i<256; i++) { hand_name_table[i]=NOSEAT; suit_name_table[i]=NOSUIT; card_name_table[i]=NORANK; } hand_name_table['N']=hand_name_table['n']=NORTH; hand_name_table['E']=hand_name_table['e']=EAST; hand_name_table['S']=hand_name_table['s']=SOUTH; hand_name_table['W']=hand_name_table['w']=WEST; suit_name_table['S']=suit_name_table['s']=SPADES; suit_name_table['H']=suit_name_table['h']=HEARTS; suit_name_table['D']=suit_name_table['d']=DIAMONDS; suit_name_table['C']=suit_name_table['c']=CLUBS; for (i=0; i<13; i++) { card_name_table[(int)cards[i]]=i; card_name_table[(int)tolower(cards[i])]=i; } } int count_controls(holding,dummy) int holding; void *dummy; { /* * * Since holdings contains a 13-bit * representation of the holdings in the suit, * controls can be computed by taking holdings[hand][suit] >> 11 * */ return ((8191&holding)>>11); } int count_hcp(h,dummy) int h; void *dummy; { static int hcptable[]={ 0 /*no honors*/ ,1 /*J*/ ,2 /*Q*/ ,3 /*QJ*/, 3 /*K*/ ,4 /*KJ*/ ,5 /*KQ*/ ,6 /*KQJ*/, 4 /*A*/ ,5 /*AJ*/ ,6 /*AQ*/ ,7 /*AQJ*/, 7 /*AK*/,8 /*AKJ*/,9 /*AKQ*/,10 /*AKQJ*/, }; return hcptable[(8191&h)>>9]; } int count_losers(holding,dummy) int holding; void * dummy; /* For additive function implementation */ { /* Really counts half-losers */ int base=counttable[holding&8191]; int losers=0; if (base==0) { return 0; } if (!HoldingHas(holding,ACE)) { losers +=2; } if (base>=2) { if (!HoldingHas(holding,KING)) { losers +=2; } } if (base>=3) { if (!HoldingHas(holding,QUEEN)) { losers +=2; } else { if (losers==4) { if(!HoldingHas(holding,JACK) && !HoldingHas(holding,TEN)) { losers++; } } } } return losers; } int put_card(hand,card) int hand,card; { int loc=stacker.dealt; if (stacker.handcount[hand]==13) { return TCL_ERROR; } if (stacker.where[card]!=-1) { /* Don't complain if stacking card to same hand */ if (stacker.whom[stacker.where[card]]==hand) { return TCL_OK; } else { return TCL_ERROR; } } else { stacker.where[card]=loc; } stacker.handcount[hand]++; stacker.whom[loc]=hand; stacker.card[loc]=card; stacker.dealt++; return TCL_OK; } void get_stacked_cards(int hand,int holdings[]) { int index, suit,denom, card; for (suit=0; suit<4; suit++) { holdings[suit]=0; } for (index=0; index=0; card--) { if (holding&1) { if (TCL_ERROR==put_card(hand,CARD(card,suit))) { return TCL_ERROR; } } holding >>= 1; } return TCL_OK; } int put_holdings(int hand,int *holdings) { int suit; for (suit=0; suit<4; suit++) { if (TCL_ERROR==put_holding(hand,suit,holdings[suit])) { return TCL_ERROR; } /* fprintf(stderr,"Adding holding %d to hand %d\n",h,hand); */ } return TCL_OK; } int put_hand(int hand,char *hstring) { int suit=SPADES; char s[4][13],*sptr; sscanf(hstring,"%s %s %s %s",s[SPADES],s[HEARTS],s[DIAMONDS],s[CLUBS]); for(suit=SPADES; suit<=CLUBS; suit++) { if (*s[suit]=='-') { continue; } sptr=s[suit]; while (*sptr) { if (TCL_ERROR==put_card(hand,CARD(card_name_table[(int)*sptr],suit))) { return TCL_ERROR; } sptr++; } } return TCL_OK; } int card_num (string) char *string; { return CARD(card_name_table[(int)string[0]],suit_name_table[(int)string[1]]); } void rotate_deal(rotation) int rotation; { int loc,card; int whom[52]; rotation = 4 - (rotation & 3); /* same as %4, only always positive */ finish_deal(); for(card=0; card<52; card++) { loc=complete_deal.where[card]; whom[card]=(complete_deal.whom[loc]+rotation) % 4; } reset_deal(&complete_deal); for(card=0; card<52; card++) { deal_put(&complete_deal,card,whom[card]); } finish_deal(); } deal319/maindeal.c0000644000175200017520000000157511062564550012222 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ extern int old_main(int, char**); int main(argc,argv) int argc; char *argv[]; { return old_main(argc,argv); } deal319/Makefile0000644000175200017520000001360611341056635011742 0ustar cbecbe# # # This file is copyrighted under the GNU Public License. # See http://www.gnu.org/copyleft/gpl.html for further # details. # # Makefile for "deal", a bridge hand generator. # TCL_DIR=/usr include Make.mac-osx #include Make.ubuntu CC=gcc # Since strdup is not implemented on some Ultrix systems # (and is not required by ANSI C) you might want to # uncomment the following line: # # EXTRAS_OBJS= util.o # EXTRA_OBJS= # On system which don't have "random" and "srandom", # you might have to use the horrible "rand" for random # number generation # #EXTRA_CFLAGS = -Drandom=rand -Dsrandom=srand # #EXTRA_CFLAGS = #EXTRA_CFLAGS = -DUSE_RAND48 COMPILE.c= $(CC) $(CFLAGS) -c CFLAGS= $(DEBUG_FLAGS) -I$(TCL_INCL) $(EXTRA_CFLAGS) OBJS=random.o additive.o hand.o deal.o formats.o tcl_deal.o maindeal.o \ stat.o counttable.o vector.o dist.o stringbox.o dealtypes.o \ keywords.o holdings.o tcl_dds.o dds.o ddsLookup.o \ $(EXTRA_OBJS) SRCS=additive.c hand.c deal.c formats.c tcl_deal.c dist.c vector.c stat.c counttable.c stringbox.c dealtypes.c holdings.c keywords.c maindeal.c random.c dds.cpp ddsLookup.cpp getopt.c SRCKIT=additive.c hand.c deal.c formats.c tcl_deal.c dist.c vector.c stat.c makecounttable.c stringbox.c dealtypes.c holdings.c keywords.c maindeal.c random.c tcl_dds.c dds.cpp ddsLookup.cpp HFILES=deck.h deal.h tcl_incl.h vector.h stat.h tcl_dist.h dist.h formats.h additive.h stringbox.h dealtypes.h holdings.h keywords.h ansidecl.h dds.h ddsInline.h ddsInterface.h Holding.h getopt.h ddsLookup.h EXAMPLES= ex/*.tcl TESTS=tests HTML=html BUILDFILES=Makefile Make.dep Make.mac-osx Make.ubuntu OTHERFILES=CHANGES LICENSE GPL input format lib deal.tcl SOURCEKIT=$(SRCKIT) $(HFILES) $(EXAMPLES) $(BUILDFILES) $(OTHERFILES) $(EXTRAS) $(TESTS) $(HTML) BINKIT=$(EXAMPLES) $(OTHERFILES) $(TESTS) $(HTML) UUKIT=$(EXAMPLES) $(OTHERFILES) deal BINARY=./deal deal: $(OBJS) g++ $(CFLAGS) $(OBJS) -o deal $(LDFLAGS) universal: $(MAKE) clean $(MAKE) MAC_ARCH="$(MAC_ARCH_UNIVERSAL)" deal.cgi: make clean make CFLAGS="$(CFLAGS) -DCGI" vector.so: vector.c $(CC) -c $(CFLAGS) -PIC vector.c ld vector.o -o vector.so dist.so: dist.c $(CC) -c $(CFLAGS) -PIC dist.c ld dist.o -o dist.so stringbox.so: stringbox.c $(CC) -c $(CFLAGS) -PIC stringbox.c ld stringbox.o -o stringbox.so $(SRCS): deal.h counttable.c: makecounttable ./makecounttable > counttable.c KITNAME=deal DEAL_VERSION=319 OLD_VERSION=318 RELEASE=$(KITNAME)$(DEAL_VERSION) SRCDIR=$(RELEASE) BINDIR=$(RELEASE)-bin SRCZIP=$(SRCDIR).zip EXEZIP=$(SRCDIR)win.zip DOCZIP=$(SRCDIR)doc.zip SRCTAR=$(SRCDIR).tar SRCGZIP=$(SRCTAR).gz BINZIP=$(KITNAME)exe.zip DMG=$(BINDIR).dmg DIFFZIP=deal$(DEAL_VERSION)diff.zip OLDZIP=../deal/deal$(OLD_VERSION).zip OLDDIR=$(KITNAME)$(OLD_VERSION) DOCDEST=html DOCTYPE=release SMALLTESTCOUNT=10 allzip: zip dmg CHANGES: docs/html/CHANGES.txt cp docs/html/CHANGES.txt CHANGES zip: $(SRCZIP) dmg: $(DMG) xzip: $(EXEZIP) dzip: $(DOCZIP) documentation: rm -rf $(DOCDEST) mkdir $(DOCDEST) cp -r docs/graphics $(DOCDEST)/graphics cp -r docs/html/*.css docs/html/ex $(DOCDEST) cd docs/html; for file in *.html *.js; do \ php process.php $(DOCTYPE) $$file > ../../$(DOCDEST)/$$file ; done sitedoc: $(MAKE) DOCDEST=site DOCTYPE=site documentation newsite: $(MAKE) clean $(MAKE) universal $(MAKE) dmg cp $(DMG) site $(MAKE) zip cp $(SRCZIP) site $(MAKE) xzip cp $(EXEZIP) site $(BINDIR): $(BINKIT) sitedoc documentation rm -rf $(BINDIR) mkdir $(BINDIR) /bin/ls -1d $(BINKIT) | xargs tar cf - | (cd $(BINDIR) ; tar xf -) find $(BINDIR) -name .svn -print | xargs /bin/rm -rf $(SRCDIR): $(SOURCEKIT) docs/html docs/graphics documentation mv Make.dep Make.dep.saved touch Make.dep rm -rf $(SRCDIR) mkdir $(SRCDIR) /bin/ls -1d $(SOURCEKIT) | xargs tar cf - | (cd $(SRCDIR) ; tar xf -) mv Make.dep.saved Make.dep $(SRCZIP): $(SRCDIR) zip -r $(SRCZIP) $(SRCDIR) -x \*~ -x *CVS/\* *.svn/\* $(EXEZIP): $(SRCDIR) rm -f $(EXEZIP) $(SRCDIR)/deal test -f deal.exe test -f tcl85.dll cp deal.exe $(SRCDIR) cp tcl85.dll $(SRCDIR) zip -r $(EXEZIP) $(SRCDIR)/ex $(SRCDIR)/input $(SRCDIR)/format $(SRCDIR)/docs $(SRCDIR)/CHANGES $(SRCDIR)/LICENSE $(SRCDIR)/GPL $(SRCDIR)/lib $(SRCDIR)/deal.tcl $(SRCDIR)/deal.exe $(SRCDIR)/tcl85.dll $(SRCDIR)/tests $(SRCDIR)/html -x \*~ -x *CVS/\* *.svn/\* $(DMG): $(BINDIR) deal cp deal $(BINDIR)/deal /bin/rm -rf dmg $(DMG) mkdir dmg cp -r $(BINDIR) dmg/$(SRCDIR) hdiutil create -srcfolder dmg -volname "Deal $(DEAL_VERSION)" $(DMG) $(DOCZIP): $(SRCDIR) rm -f $(DOCZIP) zip -r $(DOCZIP) $(SRCDIR)/CHANGES $(SRCDIR)/LICENSE $(SRCDIR)/GPL $(SRCDIR)/docs -x \*~ -x *CVS/\* *.svn/\* gzip: $(SRCTAR).gz $(SRCTAR).gz: $(SRCDIR) rm -f $(SRCTAR).gz tar cf $(SRCTAR) $(SRCDIR) gzip $(SRCTAR) $(BINZIP): deal strip deal ls -1 $(UUKIT) | grep -v /RCS | xargs zip $(BINZIP) #zip $(BINZIP) $(UUKIT) diffzip: $(DIFFZIP) $(DIFFZIP): $(SRCZIP) rm -rf tempdir $(DIFFZIP) mkdir tempdir cd tempdir ; unzip ../$(SRCZIP) ; unzip ../$(OLDZIP) cd tempdir ; diff -r $(OLDDIR) $(SRCDIR) > ../diff.out || echo Done zip $(DIFFZIP) diff.out tar: mv Make.dep Make.dep.saved touch Make.dep tar cvf deal.tar $(SOURCEKIT) mv Make.dep.saved Make.dep test: ./deal $(BINARY) -I "line tests/input/sample.line" -i format/ddline 100 > test.out if cmp test.out tests/output/sample.ddline ; then echo PASS; else echo FAIL ; fi smalltest: ./deal $(BINARY) -I "line tests/input/sample.line" -i format/ddline $(SMALLTESTCOUNT) > test.out head -$(SMALLTESTCOUNT) tests/output/sample.ddline > correct.out diff test.out correct.out if cmp test.out correct.out ; then echo PASS; else echo FAIL ; fi great88: ./deal $(BINARY) -x tests/great88 | fgrep FAIL || echo "PASSED" html: documentation ftp: $(SRCZIP) cp $(SRCZIP) $(FTP) depends: $(CC) $(CFLAGS) -M *.c *.cpp >Make.dep clean: rm -rf deal $(OBJS) $(SRCDIR) $(SRCZIP) $(SRCGZIP) $(DOCZIP) $(DMG) $(EXEZIP) $(BINDIR) counttable.c makecounttable makecounttable.o html site include Make.dep deal319/formats.h0000644000175200017520000000165511062564550012127 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "deal.h" Tcl_Obj *tcl_format_hand PROTO((int */*holdingArray*/,Tcl_Obj * /*voidstring*/)); Tcl_Obj *tcl_format_suit PROTO((int holding,Tcl_Obj * /*voidstring*/)); deal319/ddsLookup.h0000644000175200017520000000325011063020176012401 0ustar cbecbe#include "ddsInline.h" #ifndef __DDS_LOOKUP_H__ #define __DDS_LOOKUP_H__ /* * This header defines some inline functions which do global lookups for DDS * These functions are: * * CountOnes(holding_t) - counts the cards in a holding * * getHighestRank(holding_t) - returns the rank (2-14) of the highest * card in the holding * * getTopCards(holding_t h,int n) - returns a holding consisting of the top n cards * in holding h * * Your application must call initializeDDSLookup() to use these lookup tables */ /* struct topCardsType { holding_t topCards[14]; }; */ /* In dds code, counttable is local, but since I've already got a counttable in Deal, I reference that table instead */ extern "C" unsigned short int counttable[]; extern int highestRankLookup[8192]; extern holding_t topCardsLookup[14][8192]; inline unsigned short int CountOnes(holding_t holding) { return counttable[holding]; } inline int getHighestRank(holding_t holding) { return highestRankLookup[holding]; } inline holding_t getTopCards(holding_t holding, int count) { return topCardsLookup[count][holding]; } inline void initializeDDSLookup() { int n,rank; holding_t holding; highestRankLookup[0] = 0; for (n=0; n<14; n++) { topCardsLookup[n][0] = 0; } for (rank=2; rank<=14; rank++) { holding_t highestBitRank = BitRank(rank); for (holding=highestBitRank; holding<2*highestBitRank; holding++) { highestRankLookup[holding] = rank; holding_t rest = holding & (~highestBitRank); topCardsLookup[0][holding] = 0; for (n=1; n<14; n++) { topCardsLookup[n][holding] = highestBitRank | topCardsLookup[n-1][rest]; } } } } #endif deal319/Holding.h0000644000175200017520000000133311062564550012031 0ustar cbecbe#ifndef __DDS_HOLDING_H__ #define __DDS_HOLDING_H__ #include "ddsInterface.h" /* * This is just a utility class so you can say: * cout << Holding(h) << endl; * when h is of type holding_t. */ struct Holding { holding_t _h; inline Holding(holding_t h) : _h(h) { } inline operator holding_t() const { return _h; } }; inline ostream& operator <<(ostream &out,const Holding &holding) { static const char *cards="AKQJT98765432"; int index=0; holding_t h = holding._h; if (h&8191) { for (holding_t card=1<<12; card; card >>= 1, index++) { if (h & card) { out << cards[index]; } } } else { out << "void"; } out << " (" << holding._h << ")"; return out; } #endif deal319/random.c0000644000175200017520000003067111341063504011720 0ustar cbecbe/* This code has been introduced by Bruce Moore */ /* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * This is derived from the Berkeley source: * @(#)random.c 5.5 (Berkeley) 7/6/88 * It was reworked for the GNU C Library by Roland McGrath. */ #include "ansidecl.h" #include #include #include #include long int DEFUN_VOID(__random); /* An improved random number generation package. In addition to the standard rand()/srand() like interface, this package also has a special state info interface. The initstate() routine is called with a seed, an array of bytes, and a count of how many bytes are being passed in; this array is then initialized to contain information for random number generation with that much state information. Good sizes for the amount of state information are 32, 64, 128, and 256 bytes. The state can be switched by calling the setstate() function with the same array as was initiallized with initstate(). By default, the package runs with 128 bytes of state information and generates far better random numbers than a linear congruential generator. If the amount of state information is less than 32 bytes, a simple linear congruential R.N.G. is used. Internally, the state information is treated as an array of longs; the zeroeth element of the array is the type of R.N.G. being used (small integer); the remainder of the array is the state information for the R.N.G. Thus, 32 bytes of state information will give 7 longs worth of state information, which will allow a degree seven polynomial. (Note: The zeroeth word of state information also has some other information stored in it; see setstate for details). The random number generation technique is a linear feedback shift register approach, employing trinomials (since there are fewer terms to sum up that way). In this approach, the least significant bit of all the numbers in the state table will act as a linear feedback shift register, and will have period 2^deg - 1 (where deg is the degree of the polynomial being used, assuming that the polynomial is irreducible and primitive). The higher order bits will have longer periods, since their values are also influenced by pseudo-random carries out of the lower bits. The total period of the generator is approximately deg*(2**deg - 1); thus doubling the amount of state information has a vast influence on the period of the generator. Note: The deg*(2**deg - 1) is an approximation only good for large deg, when the period of the shift register is the dominant factor. With deg equal to seven, the period is actually much longer than the 7*(2**7 - 1) predicted by this formula. */ /* For each of the currently supported random number generators, we have a break value on the amount of state information (you need at least thi bytes of state info to support this random number generator), a degree for the polynomial (actually a trinomial) that the R.N.G. is based on, and separation between the two lower order coefficients of the trinomial. */ /* Linear congruential. */ #define TYPE_0 0 #define BREAK_0 8 #define DEG_0 0 #define SEP_0 0 /* x**7 + x**3 + 1. */ #define TYPE_1 1 #define BREAK_1 32 #define DEG_1 7 #define SEP_1 3 /* x**15 + x + 1. */ #define TYPE_2 2 #define BREAK_2 64 #define DEG_2 15 #define SEP_2 1 /* x**31 + x**3 + 1. */ #define TYPE_3 3 #define BREAK_3 128 #define DEG_3 31 #define SEP_3 3 /* x**63 + x + 1. */ #define TYPE_4 4 #define BREAK_4 256 #define DEG_4 63 #define SEP_4 1 /* Array versions of the above information to make code run faster. Relies on fact that TYPE_i == i. */ #define MAX_TYPES 5 /* Max number of types above. */ static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; /* Initially, everything is set up as if from: initstate(1, randtbl, 128); Note that this initialization takes advantage of the fact that srandom advances the front and rear pointers 10*rand_deg times, and hence the rear pointer which starts at 0 will also end up at zero; thus the zeroeth element of the state information, which contains info about the current position of the rear pointer is just (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ static long int randtbl[DEG_3 + 1] = { TYPE_3, -851904987, -43806228, -2029755270, 1390239686, -1912102820, -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, -1714531963, 1800685987, -2015299881, 654595283, -1149023258, -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, -607508183, -205999574, -1696891592, 1492211999, -1528267240, -952028296, -189082757, 362343714, 1424981831, 2039449641, }; /* FPTR and RPTR are two pointers into the state info, a front and a rear pointer. These two pointers are always rand_sep places aparts, as they cycle through the state information. (Yes, this does mean we could get away with just one pointer, but the code for random is more efficient this way). The pointers are left positioned as they would be from the call: initstate(1, randtbl, 128); (The position of the rear pointer, rptr, is really 0 (as explained above in the initialization of randtbl) because the state table pointer is set to point to randtbl[1] (as explained below).) */ static long int *fptr = &randtbl[SEP_3 + 1]; static long int *rptr = &randtbl[1]; /* The following things are the pointer to the state information table, the type of the current generator, the degree of the current polynomial being used, and the separation between the two pointers. Note that for efficiency of random, we remember the first location of the state information, not the zeroeth. Hence it is valid to access state[-1], which is used to store the type of the R.N.G. Also, we remember the last location, since this is more efficient than indexing every time to find the address of the last element to see if the front and rear pointers have wrapped. */ static long int *state = &randtbl[1]; static int rand_type = TYPE_3; static int rand_deg = DEG_3; static int rand_sep = SEP_3; static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; /* Initialize the random number generator based on the given seed. If the type is the trivial no-state-information type, just remember the seed. Otherwise, initializes state[] based on the given "seed" via a linear congruential generator. Then, the pointers are set to known locations that are exactly rand_sep places apart. Lastly, it cycles the state information a given number of times to get rid of any initial dependencies introduced by the L.C.R.N.G. Note that the initialization of randtbl[] for default usage relies on values produced by this routine. */ void DEFUN(__srandom, (x), unsigned int x) { state[0] = x; if (rand_type != TYPE_0) { register long int i; for (i = 1; i < rand_deg; ++i) state[i] = (1103515145 * state[i - 1]) + 12345; fptr = &state[rand_sep]; rptr = &state[0]; for (i = 0; i < 10 * rand_deg; ++i) (void) __random(); } } /* Initialize the state information in the given array of N bytes for future random number generation. Based on the number of bytes we are given, and the break values for the different R.N.G.'s, we choose the best (largest) one we can and set things up for it. srandom is then called to initialize the state information. Note that on return from srandom, we set state[-1] to be the type multiplexed with the current value of the rear pointer; this is so successive calls to initstate won't lose this information and will be able to restart with setstate. Note: The first thing we do is save the current state, if any, just like setstate so that it doesn't matter when initstate is called. Returns a pointer to the old state. */ PTR DEFUN(__initstate, (seed, arg_state, n), unsigned int seed AND PTR arg_state AND size_t n) { PTR ostate = (PTR) &state[-1]; if (rand_type == TYPE_0) state[-1] = rand_type; else state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; if (n < BREAK_1) { if (n < BREAK_0) { errno = EINVAL; return NULL; } rand_type = TYPE_0; rand_deg = DEG_0; rand_sep = SEP_0; } else if (n < BREAK_2) { rand_type = TYPE_1; rand_deg = DEG_1; rand_sep = SEP_1; } else if (n < BREAK_3) { rand_type = TYPE_2; rand_deg = DEG_2; rand_sep = SEP_2; } else if (n < BREAK_4) { rand_type = TYPE_3; rand_deg = DEG_3; rand_sep = SEP_3; } else { rand_type = TYPE_4; rand_deg = DEG_4; rand_sep = SEP_4; } state = &((long int *) arg_state)[1]; /* First location. */ /* Must set END_PTR before srandom. */ end_ptr = &state[rand_deg]; __srandom(seed); if (rand_type == TYPE_0) state[-1] = rand_type; else state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; return ostate; } /* Restore the state from the given state array. Note: It is important that we also remember the locations of the pointers in the current state information, and restore the locations of the pointers from the old state information. This is done by multiplexing the pointer location into the zeroeth word of the state information. Note that due to the order in which things are done, it is OK to call setstate with the same state as the current state Returns a pointer to the old state information. */ PTR DEFUN(__setstate, (arg_state), PTR arg_state) { register long int *new_state = (long int *) arg_state; register int type = new_state[0] % MAX_TYPES; register int rear = new_state[0] / MAX_TYPES; PTR ostate = (PTR) &state[-1]; if (rand_type == TYPE_0) state[-1] = rand_type; else state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; switch (type) { case TYPE_0: case TYPE_1: case TYPE_2: case TYPE_3: case TYPE_4: rand_type = type; rand_deg = degrees[type]; rand_sep = seps[type]; break; default: /* State info munged. */ errno = EINVAL; return NULL; } state = &new_state[1]; if (rand_type != TYPE_0) { rptr = &state[rear]; fptr = &state[(rear + rand_sep) % rand_deg]; } /* Set end_ptr too. */ end_ptr = &state[rand_deg]; return ostate; } /* If we are using the trivial TYPE_0 R.N.G., just do the old linear congruential bit. Otherwise, we do our fancy trinomial stuff, which is the same in all ther other cases due to all the global variables that have been set up. The basic operation is to add the number at the rear pointer into the one at the front pointer. Then both pointers are advanced to the next location cyclically in the table. The value returned is the sum generated, reduced to 31 bits by throwing away the "least random" low bit. Note: The code takes advantage of the fact that both the front and rear pointers can't wrap on the same call by not testing the rear pointer if the front one has wrapped. Returns a 31-bit random number. */ long int DEFUN_VOID(__random) /* long int random(void) */ /* Use this one if your system complains about the DEFUN_VOID statement */ { if (rand_type == TYPE_0) { state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; return state[0]; } else { long int i; *fptr += *rptr; /* Chucking least random bit. */ i = (*fptr >> 1) & LONG_MAX; ++fptr; if (fptr >= end_ptr) { fptr = state; ++rptr; } else { ++rptr; if (rptr >= end_ptr) rptr = state; } return i; } } deal319/hand.c0000644000175200017520000003310011062564550011347 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Commands defined in this file: * * whogets - returns the name of the holder of a specific card * * north,east,south,west,hand - rather complicated; see below * * hcp, controls, losers * * spades,hearts,diamonds,clubs - returns suit counts * * */ #include #include #include #include #include #include "deal.h" #include "dealtypes.h" #include "additive.h" #include "formats.h" #include "tcl_incl.h" #include #if (TCL_MINOR_VERSION==0) int My_EvalObjv(Tcl_Interp *interp,int objc,Tcl_Obj **objv,int dummy) { Tcl_Obj *list=Tcl_NewListObj(objc,objv); if (list==NULL) { return TCL_ERROR; } return Tcl_GlobalEvalObj(interp,list); } #endif int tcl_deal_to_whom (TCLOBJ_PARAMS) TCLOBJ_DECL { int card; if (objc!=2) { Tcl_WrongNumArgs(interp,1,objv,""); return TCL_ERROR; } card=card_num(Tcl_GetString(objv[1])); if (card>=52||card<0) { Tcl_AppendResult(interp,Tcl_GetString(objv[0]), ": ", Tcl_GetString(objv[1])," is not a valid card name",NULL); return TCL_ERROR; } Tcl_SetObjResult(interp,getHandKeywordObj(interp,to_whom(card))); return TCL_OK; } int tcl_other_hand(TCLOBJ_PARAMS) TCLOBJ_DECL { Tcl_Obj *result; int hand; int rotation=(int)cd; /* 1 = LHO, 2 = partner, 3 = RHO */ if (objc!=2) { Tcl_WrongNumArgs(interp,1,objv,""); return TCL_ERROR; } hand=getHandNumFromObj(interp,objv[1]); if (hand<0||hand>3) { Tcl_AppendResult(interp,Tcl_GetString(objv[0]), ": Expected handname as first argument; got '", Tcl_GetString(objv[1]),"'",NULL); return TCL_ERROR; } hand = (hand+rotation)%4; result=getHandKeywordObj(interp,hand); if (result==NULL) { /*NOTREACHED*/ /* This should almost never happen -getHandKeywordObj doesn't create a new object, and the hand is assured to be an appropriate hand number */ return TCL_ERROR; } Tcl_SetObjResult(interp,result); return TCL_OK; } int tcl_count_suit (TCLOBJ_PARAMS) TCLOBJ_DECL { static int doInit=1, HandCmdID=-1; static char *usage=" | hand "; int suit,hand,length; int hArray[4],*hptr; if (doInit) { HandCmdID=Keyword_addKey("hand"); doInit=0; } if (objc<2) { Tcl_WrongNumArgs(interp,1,objv,usage); return TCL_ERROR; } hand=getHandNumFromObj(interp,objv[1]); if (NOSEAT==hand) { if (objc!=3) { Tcl_WrongNumArgs(interp,1,objv,usage); return TCL_ERROR; } if (HandCmdID!=Keyword_getIdFromObj(interp,objv[1])) { Tcl_AppendResult(interp, "Illegal hand name, \"",Tcl_GetString(objv[1]), "\", used with \"", Tcl_GetString(objv[0]),"\" command",(char *)NULL); return TCL_ERROR; } if (TCL_OK!=getHandHoldingsFromObj(interp,objv[2],hArray)) { Tcl_AppendResult(interp, "Badly specified hand, \"",Tcl_GetString(objv[2]), "\", used with \"", Tcl_GetString(objv[0]),"\" command",(char *)NULL); return TCL_ERROR; } hptr=hArray; } else { if (objc!=2) { Tcl_WrongNumArgs(interp,1,objv,usage); return TCL_ERROR; } FINISH(hand); hptr=holdings[hand]; } suit=(int)cd; length=counttable[8191&hptr[suit]]; Tcl_SetObjResult(interp,getLengthObj(length)); return TCL_OK; } Tcl_Obj *tcl_hand_holdings(Tcl_Interp *interp,int *hArray) { Tcl_Obj *holdingObjs[4]; Tcl_Obj *list; int suit; for (suit=0; suit<4; suit++) { holdingObjs[suit]=Tcl_NewHoldingObj(hArray[suit]); } list=Tcl_NewListObj(4,holdingObjs); return list; } /* * tcl_hand_cmd implements the commands "north","east", * "south", and "west". * * Placing cards: * north is AKQ JT98 765 432 * south is {432 765 JT98 AKQ} * west gets AD * * Formatting output: * % north * AKQ JT98 765 432 * % south clubs * AKQ * * Getting the shape or pattern: * % north shape * 3 4 3 3 * % north pattern * 4 3 3 3 */ static int tcl_hand_cmd( TCLOBJ_PARAMS ) TCLOBJ_DECL { static int uninitialized=1, IsID=-1, GetsID=-1, PatternID=-1, ShapeID=-1, HasID=-1, HandID=-1, VoidFlagID=-1; int hand=(int)cd; int suit; Tcl_Obj *voidObj=0; int argID; int retval; Tcl_Obj * CONST *objv0=objv; /* saved due to potential increment of objv */ int usageStart=1; /* set to 2 if this is of type hand ... */ Tcl_Obj *handObj=NULL; static Tcl_Obj *stackHandCmd=NULL,*stackCardsCmd=NULL; int hnums[4]; int *holdingsPtr; if (uninitialized) { /* Initialize once */ IsID=Keyword_addKey("is"); GetsID=Keyword_addKey("gets"); PatternID=Keyword_addKey("pattern"); ShapeID=Keyword_addKey("shape"); HasID=Keyword_addKey("has"); HandID=Keyword_addKey("hand"); VoidFlagID=Keyword_addKey("-void"); uninitialized=0; Tcl_IncrRefCount(stackHandCmd=Tcl_NewStringObj("::stack_hand",12)); Tcl_IncrRefCount(stackCardsCmd=Tcl_NewStringObj("::stack_cards",13)); } if (NOSEAT==hand) { if (objc>=2) { handObj=objv[1]; usageStart+=2; objv++; objc--; } else { char *name=Tcl_GetString(*objv0); Tcl_AppendResult(interp,name[0]," is not a legitimate hand name",NULL); return TCL_ERROR; } } if (objc>1) { argID=Keyword_getIdFromObj(interp,objv[1]); if (argID==VoidFlagID) { voidObj=objv[2]; objv+=2; objc-=2; argID=Keyword_getIdFromObj(interp,objv[1]); } } if (objc<=1) { if (handObj==NULL) { FINISH(hand); holdingsPtr=globalDeal.hand[hand].suit; } else { retval=getHandHoldingsFromObj(interp,handObj,hnums); if (retval!=TCL_OK) { Tcl_AddErrorInfo(interp,"Error extracting holding from hand object"); return retval; } holdingsPtr=hnums; } if (voidObj!=NULL) { Tcl_SetObjResult(interp,tcl_format_hand(holdingsPtr,voidObj)); } else { Tcl_SetObjResult(interp,tcl_hand_holdings(interp,holdingsPtr)); } return TCL_OK; } /* argID=Keyword_getIdFromObj(interp,objv[1]); */ if (argID==KEYWORD_INVALID_ID) { Tcl_AppendResult(interp, Tcl_GetString(*objv0), ": invalid subcommand ", Tcl_GetString(objv[1]), NULL); return TCL_ERROR; } if (argID==IsID) { Tcl_Obj **command; int i; if (handObj!=NULL) { Tcl_AddErrorInfo(interp, "hand subcommand 'is' cannot be used with hand command"); return TCL_ERROR; } command=(Tcl_Obj**)Tcl_Alloc(objc*sizeof(Tcl_Obj*)); command[0]=stackHandCmd; command[1]=objv[0]; for (i=2; i2) { card=getCardNumFromObj(interp,objv[--objc]); if (card>=52||card<0) { Tcl_AppendResult(interp,Tcl_GetString(objv[objc])," is not a valid card name",NULL); return TCL_ERROR; } holdings[SUIT(card)] |= (1<<(12-RANK(card))); } for (suit=0; suit<4; suit++) { if (holdings[suit]!=0) { stackcmd[2]=suits[suit]; Tcl_IncrRefCount(stackcmd[3]=Tcl_NewHoldingObj(holdings[suit])); if (TCL_OK!=Tcl_EvalObjv(interp,4,stackcmd,TCL_EVAL_GLOBAL)) { Tcl_AppendResult(interp,"Forcing cards with 'gets' failed.",NULL); return TCL_ERROR; } Tcl_DecrRefCount(stackcmd[3]); } } return TCL_OK; } if (handObj==NULL) { FINISH(hand); holdingsPtr=globalDeal.hand[hand].suit; } else { retval=getHandHoldingsFromObj(interp,handObj,hnums); if (retval!=TCL_OK) { return retval; } holdingsPtr=hnums; } usageStart += 1; if (argID==PatternID || argID==ShapeID) { int i,j,temp,d[4]; Tcl_Obj *s=Tcl_NewListObj(0,NULL); if (objc>2) { Tcl_WrongNumArgs(interp,usageStart,objv0,0); return TCL_ERROR; } for (i=0; i<4 ; i++) { d[i]=counttable[8191&holdingsPtr[i]]; } if (argID==PatternID) { /* do bubble sort to return pattern */ for (j=3; j>=1; j--) for (i=0; i [] ..."); return TCL_ERROR; } while(objc>2) { card=getCardNumFromObj(interp,objv[--objc]); if (card>=52 || card<0) { Tcl_AppendResult(interp,Tcl_GetString(objv[objc])," is not a valid card name",NULL); return TCL_ERROR; } if (HASCARD2(holdingsPtr,card)) { count++; } } Tcl_SetObjResult(interp,Tcl_NewIntObj(count)); return TCL_OK; } if (NOSUIT!=(suit=getSuitNumFromObj(interp,objv[1]))) { if (objc!=2) { Tcl_WrongNumArgs(interp,usageStart,objv0,0); return TCL_ERROR; } Tcl_SetObjResult(interp,tcl_format_suit(holdingsPtr[suit],voidObj)); return TCL_OK; } else { Tcl_AppendResult(interp,Tcl_GetString(objv[1]), " is not a legitimate suit name\n", Tcl_GetString(objv[0]), "[]",NULL); return TCL_ERROR; } return TCL_ERROR; } int tcl_stack_cards(TCLOBJ_PARAMS) TCLOBJ_DECL { int hand; int index; int tclRet; if (objc<4||(objc%2)) { Tcl_WrongNumArgs(interp,1,objv,"handname suitname holding [suitname holding ...]"); return TCL_ERROR; } if (NOSEAT==(hand=getHandNumFromObj(interp,objv[1]))) { Tcl_AddErrorInfo(interp,"error: first argument must be a hand name"); return TCL_ERROR; } for (index=2; index }"); Tcl_AppendResult(interp," or ",NULL); Tcl_WrongNumArgs(interp,1,objv," "); return TCL_ERROR; } if (NOSEAT==(hand=getHandNumFromObj(interp,objv[1]))) { Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": first argument must be a hand name", TCL_STATIC); return TCL_ERROR; } if (objc==3) { tclret=getHandHoldingsFromObj(interp,objv[2],hnums); } else { tclret=getHandHoldingsFromObjv(interp,objv+2,hnums); } if (tclret!=TCL_OK) { Tcl_SetResult(interp,"Hand stacking error",TCL_STATIC); return TCL_ERROR; } return put_holdings(hand,hnums); } int HandCmd_Init(Tcl_Interp *interp) { int hand,suit; initializeLengths(); initializeDealTypes(interp); for (suit=SPADES; suit<=CLUBS; suit++) { /* Put suit name in client data as well as command name to allow use of "rename" by user */ Tcl_CreateObjCommand(interp,suitname[suit], tcl_count_suit, (ClientData)suit, NULL); } for (hand=NORTH; hand<=WEST; hand++) { /* Put hand number in client data to allow use of "rename" by user */ Tcl_CreateObjCommand(interp,handname[hand],tcl_hand_cmd,(ClientData)hand,NULL); } Tcl_CreateObjCommand(interp,"hand",tcl_hand_cmd,(ClientData)NOSEAT,NULL); Tcl_CreateObjCommand(interp,"whogets",tcl_deal_to_whom,NULL,NULL); tcl_create_additive(interp,"controls", count_controls, NULL, NULL); tcl_create_additive(interp,"hcp", count_hcp, NULL, NULL); tcl_create_additive(interp,"losers", count_losers, NULL, NULL); Tcl_CreateObjCommand(interp,"lho",tcl_other_hand,(ClientData)1,NULL); Tcl_CreateObjCommand(interp,"partner",tcl_other_hand,(ClientData)2,NULL); Tcl_CreateObjCommand(interp,"rho",tcl_other_hand,(ClientData)3,NULL); /* * These are not meant to be overridden */ Tcl_CreateObjCommand(interp,"deck_stack_hand",tcl_stack_hand,NULL,NULL); Tcl_CreateObjCommand(interp,"deck_stack_cards",tcl_stack_cards,NULL,NULL); /* These two aliases are meant to be overridden */ Tcl_CreateObjCommand(interp,"stack_hand",tcl_stack_hand,NULL,NULL); Tcl_CreateObjCommand(interp,"stack_cards",tcl_stack_cards,NULL,NULL); return TCL_OK; } deal319/additive.c0000644000175200017520000001422411224443223012225 0ustar cbecbe/* * additive.c - Quick way to define integer additive holding procedures * This is old code, somewhat superceded by "holdingProc" * procedures * * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This file encapsulates a specific class of bridge functions, namely, * "additive" functions. An additive function is one that * is computed suit-by-suit, with the total equalling the sum * of the values for each suit. * * Examples include: * * hcp - high card points * controls - A=2, K=1 * other "vectors" - AKQ-points, etc * losers - the losing trick count * * All of these functions have the same interface, namely, they * can be called suit-by-suit or for the entire hand. For example: * * [hcp south] computes the total hcp for south * [hcp south spades] computes the hcp held by south in spades * * Additive functions are created with five parameters: * interp - Tcl interpreter where the function is to be defined * name - The name for the additive function * func - ptr to function of type * "int func(int hand, int suit, void *data)" * data - Arbitrary data used by "func" * freefunc - Function for freeing the data, ignored if NULL * * Note, additive functions are mostly superceded by the holdingProc * code in holdings.c. * * Additive functions only return integers. * */ #include "deal.h" #include "additive.h" #include "dealtypes.h" /* Data structure for holding information about an additive function */ typedef struct additivecounter { int (*func) PROTO((int /* holding */, void * /* data */)); void *data; Tcl_CmdDeleteProc *freefunc; } *AdditiveFunction; #define AddFuncCall(addfunc,holding) \ (addfunc)->func(holding,(addfunc)->data) static AdditiveFunction newAdditiveFunction(func,data,freefunc) int (*func) PROTO((int /* holding */, void * /* data */)); Tcl_CmdDeleteProc *freefunc; void *data; { AdditiveFunction result=(AdditiveFunction) Tcl_Alloc(sizeof(struct additivecounter)); if (result==NULL) { return NULL; } result->func=func; result->data=data; result->freefunc=freefunc; return result; } static void deleteAdditiveFunction(ClientData ptr) { AdditiveFunction addf=(AdditiveFunction)ptr; if (addf->freefunc!=0) { (addf->freefunc)(addf->data); } Tcl_Free((void*)ptr); } /* * This is the procedure as called from Tcl */ int tcl_count_additive( TCLOBJ_PARAMS ) TCLOBJ_DECL { static int subCmdInit=1, handSubCmd=-1, holdingSubCmd=-1; int hand; int suit; AdditiveFunction addfunc=(AdditiveFunction)cd; int total=0; int i,subCmd; if (subCmdInit) { handSubCmd=Keyword_addKey("hand"); holdingSubCmd=Keyword_addKey("holding"); subCmdInit=0; } if (objc==1) { char *name=Tcl_GetString(objv[0]); Tcl_AppendResult(interp, "Usage Error: No args. Us either:\n\t", name," [ ... ]\nor\n\t", name," hand [ ...]\nor\n\t", name," holding [ ...]", (char *)NULL); return TCL_ERROR; } if (NOSEAT!=(hand=getHandNumFromObj(interp,objv[1]))) { /* First argument is a hand name - hand is set to the hand number */ FINISH(hand); /* Make sure the hand is dealt */ if (objc==2) { for (suit=0; suit<4; suit++) { total += AddFuncCall(addfunc,globalDeal.hand[hand].suit[suit]); } } else { for (i=2; i"); return TCL_ERROR; } if (TCL_OK!=getHandHoldingsFromObj(interp,objv[2],hnum)) { Tcl_AppendResult(interp,"\nError: '",Tcl_GetString(objv[2]), "' is not a proper hand",NULL); return TCL_ERROR; } for (suit=0; suit<4; suit++) { total += AddFuncCall(addfunc,hnum[suit]); } Tcl_SetObjResult(interp,Tcl_NewIntObj(total)); return TCL_OK; } if (subCmd==holdingSubCmd) { int total=0; for (i=2; i=$min && $hcp<=$max}] } return 0 } # # In Roth's picture bidding, he allows 5-card majors to open # 1NT. Roth_nt_shape needs to be defined # proc Roth_nt {hand min max} { if {[Roth_nt_shape $hand]} { set hcp [hcp $hand] return [expr {$hcp>=$min && $hcp<=$max}] } else { return 0 } } proc 5CM_nt {hand min max} { set s [spades $hand] set h [hearts $hand] set d [diamonds $hand] set c [clubs $hand] set count(0) 0 set count(1) 0 set count(4) 0 set count(5) 0 set count(6) 0 set count(7) 0 set count($s) 1 set count($h) 1 set count($d) 1 set count($c) 1 if { ($count(1)==0) && ($count(0)==0) && ($count(6)==0) && ($count(7)==0) } { if {$count(5)==1 && $count(4)==1} { return 0 } set hcp [hcp $hand] return [expr {$hcp>=$min && $hcp<=$max}] } return 0 } defvector Top0 0 defvector Top1 1 defvector Aces 1 defvector Top2 1 1 defvector Top3 1 1 1 defvector Top4 1 1 1 1 defvector Honors 1 1 1 1 defvector Top5 1 1 1 1 1 defvector Top6 1 1 1 1 1 1 defvector Top7 1 1 1 1 1 1 1 defvector Top5Q 2 2 2 1 1 defvector Ace 1 defvector King 0 1 defvector AceKing 1 1 defvector Queen 0 0 1 defvector JT 0 0 0 1 1 set Losers(0) 0 set Losers(1) 1 set Losers(2) 2 set Losers(3) 3 set Losers(4) 4 set Losers(5) 4 set Losers(6) 3 set Losers(7) 3 set Losers(8) 2 set Losers(9) 2 set Losers(10) 2 set Losers(11) 1 set Losers(12) 1 set Losers(13) 0 # # This returns 2X the number of expected defensive tricks # from a suit. This is a crude estimate. # holdingProc defense {A K Q len} { set defense 0 if {$A} { incr defense 2 } if {$K&&$len<7} { incr defense 2 } if {$Q&&$len<6} { if {$A||$K} { incr defense 2 } else { incr defense 1 } } return $defense } proc defense {hand suit} { set len [$suit $hand] set defense 0 if {[Ace $hand $suit]} { incr defense 2 } if {[King $hand $suit] && $len < 7} { incr defense 2 } if {[Queen $hand $suit] && $len < 6} { if {[AceKing $hand $suit]>0} { incr defense 2 } else { incr defense 1 } } return $defense } # # This routine needs some work # defvector losers0_1 100 defvector losers0_2 50 50 defvector losers0_3 50 25 25 defvector losers0_4 40 30 20 10 10 defvector losers1_2 100 50 50 defvector losers1_3 50 50 30 20 defvector losers1_4 30 30 30 30 10 10 defvector losers2_3 100 50 50 30 20 20 defvector losers2_4 40 40 40 40 10 10 10 defvector losers3_4 100 60 60 30 10 5 5 proc offense {hand suit} { global Losers set len [$suit $hand] set baselose $Losers($len) if {$baselose == 0} { return $len } if {$baselose == 1} { return [expr $len-1+[Aces $hand $suit]]; } if {$baselose == 2} { if {[losers0_2 $hand $suit]>=100} { return $len } if {[losers1_2 $hand $suit]>=100} { return [expr $len-1] } return [expr $len-2] } if {$baselose == 3} { if {[losers0_3 $hand $suit]>=100} { return $len } if {[losers1_3 $hand $suit]>=100} { return [expr $len-1] } if {[losers2_3 $hand $suit]>=100} { return [expr $len-2] } return [expr $len-3] } if {[losers0_4 $hand $suit]>=100} { return $len } if {[losers1_4 $hand $suit]>=100} { return [expr $len-1] } if {[losers2_4 $hand $suit]>=100} { return [expr $len-2] } if {[losers3_4 $hand $suit]>=100} { return [expr $len-3] } return [expr $len-4] } proc sOP {hand suit} { set offense [offense $hand $suit] set defense [defense $hand $suit] return [expr $offense-$defense] } proc OP {hand} { return [expr { [sOP $hand hearts] + [sOP $hand spades] + [sOP $hand diamonds] + [sOP $hand clubs] } ] } proc thomas_opener {hand} { set hcp [hcp $hand] if {$hcp>12} {return 1} if {[balanced $hand] && $hcp==12} {return 1} if {[losers $hand]<=2+$hcp} { if {[Aces $hand]>1} {return 1} if {[OP $hand]<4} {return 1} } return 0 } proc sound_opener {hand} { return [expr { ([losers $hand]+38<=4*[hcp $hand]) || [nt $hand 13 15] } ] } proc roth_opener {hand} { set h [dhcp $hand] if {$h>14} { return 1 } if {$h<12} { return 0 } set l [losers $hand] if {$l>8} { return 0 } if {$h>13} { return 1 } set count 0 if {[Aces $hand]<1} { incr count } if {$l>6} {incr count } if {[spades $hand]<=1} {incr count } if {[hearts $hand]+[spades $hand]<4} {incr count} if {$h-$count>=12} { return 1 } return 0 } proc standard_opening_suit {hand} { set s [spades $hand] set h [hearts $hand] set d [diamonds $hand] set c [clubs $hand] if {($s >= 5) && ($s >= $h) && ($s >= $d) && ($s >= $c)} { return "spades" } if {($h >=5) && ($h >= $d) && ($h >= $c)} { return "hearts" } if {$d>$c} { return diamonds } if {$d==$c && $d>=5} { return diamonds } return "clubs" } proc solid_suit {hand suit} { expr "[Top3 $hand $suit]==3 && [$suit $hand]>=7" } proc gambling_nt {hand} { if {[hearts $hand]>=4 || [spades $hand]>=4} {return 0} return [expr { (([clubs $hand]<=3 && [solid_suit $hand diamonds]) || ([diamonds $hand]<=3 && [solid_suit $hand clubs])) && [controls $hand] <= 4 && [hcp $hand] <= 13 }] } proc r1_control_suit {hand suit} { if {[$suit hand] = 0} {return 1} if {[Ace $hand] = 1} {return 1} return 0 } proc r2_control_suit {hand suit} { if {[$suit hand] <= 1} {return 1} if {[King $hand] = 1} {return 1} return 0 } proc weak_two_quality {hand suit} { if {[weak_two_qualvec $hand $suit] < 4} { return 0 } return 1 } proc partner {hand} { if {$hand >= "south"} { if {$hand == "south"} { return "north" } return "east" } if {$hand == "north"} {return "south"} return "west" } defvector dhcp0 0 defvector dhcp1 4 2 0 0 defvector dhcp2 4 3 1 1 defvector dhcp3 4 3 2 1 proc dhcp {hand} { set total 0 foreach suit {spades hearts diamonds clubs} { set count [$suit $hand] if {$count>3} { set count 3 } incr total [dhcp$count $hand $suit] } return $total } defvector newhcpvector 11 7 4 2 1 proc newhcp {hand args} { set total 0 if {$args==""} { set suits "spades hearts diamonds clubs" } else { set suits $args } foreach suit "$suits" { set val [newhcpvector $hand $suit] set count [$suit $hand] if {$count==1 && $val<=7 && $val>=2} { incr val -2 } if {[Top4 $hand $suit]>=2} { incr val 2 } if {$count==1} { incr val 2 } if {$count==0} { incr val 3 } if {$count>=5} { incr val [expr 2*($count-4)] } incr total $val } return $total } holdingProc -string distinct_cards {A K Q J T x9 x8 x7 x6 x5 x4 x3 x2} { set L [list] set last 0 foreach card {A K Q J T 9 8 7 6 5 4 3 2} \ hasit [list $A $K $Q $J $T $x9 $x8 $x7 $x6 $x5 $x4 $x3 $x2] { if {$hasit &! $last} { lappend L $card } set last $hasit } set L } deal319/lib/binky-data.tcl0000644000175200017520000004234111224443222013565 0ustar cbecbeadd 4-3-3-3 3.12 3.60 add 4-4-3-2 3.07 3.89 add 5-3-3-2 3.04 3.93 add 5-4-2-2 2.98 4.19 add 6-3-2-2 2.98 4.25 add 4-4-4-1 3.05 4.41 add 5-4-3-1 3.00 4.47 add 6-3-3-1 3.00 4.52 add 7-2-2-2 2.92 4.59 add 6-4-2-1 2.95 4.76 add 5-5-2-1 2.89 4.76 add 7-3-2-1 2.97 4.84 add 5-4-4-0 3.17 5.12 add 8-2-2-1 2.93 5.20 add 5-5-3-0 3.11 5.22 add 6-4-3-0 3.16 5.23 add 7-3-3-0 3.11 5.26 add 7-4-1-1 2.92 5.29 add 6-5-1-1 2.84 5.32 add 8-3-1-1 2.91 5.40 add 7-4-2-0 3.08 5.50 add 6-5-2-0 2.97 5.53 add 8-3-2-0 3.00 5.54 add 9-2-1-1 2.87 5.75 add 9-2-2-0 2.83 5.88 add 8-4-1-0 3.06 5.96 add 7-5-1-0 2.99 6.07 add 9-3-1-0 3.02 6.09 add 6-6-1-0 2.83 6.10 add 10-1-1-1 2.36 6.19 add 10-2-1-0 2.61 6.36 add 10-3-0-0 2.80 6.64 add 9-4-0-0 3.08 6.68 add 11-1-1-0 1.98 6.75 add 8-5-0-0 3.00 6.75 add 7-6-0-0 3.00 6.90 add 11-2-0-0 2.23 6.91 add 12-1-0-0 1.00 7.25 add 13-0-0-0 -0.59 7.69 add - 0.00 0.00 add x -0.29 -0.17 add 9 -0.26 -0.15 add T -0.22 -0.12 add J -0.08 -0.05 add Q 0.17 0.08 add K 0.60 0.31 add A 1.84 1.16 add xx -0.76 -0.49 add 9x -0.72 -0.46 add Tx -0.64 -0.41 add T9 -0.59 -0.37 add Jx -0.43 -0.31 add J9 -0.40 -0.28 add JT -0.33 -0.23 add Qx -0.09 -0.09 add Q9 -0.03 -0.05 add QT 0.03 -0.01 add QJ 0.20 0.09 add Kx 0.73 0.46 add K9 0.78 0.49 add KT 0.86 0.55 add KJ 1.10 0.67 add KQ 1.38 0.87 add Ax 1.55 1.04 add A9 1.59 1.07 add AT 1.66 1.11 add AJ 1.83 1.23 add AQ 2.36 1.55 add AK 2.79 1.93 add xxx -1.26 -0.84 add 9xx -1.21 -0.81 add Txx -1.10 -0.74 add T9x -1.05 -0.70 add Jxx -0.84 -0.59 add J9x -0.77 -0.53 add JTx -0.68 -0.47 add JT9 -0.63 -0.41 add Qxx -0.34 -0.30 add Q9x -0.25 -0.24 add QTx -0.10 -0.16 add QT9 -0.02 -0.10 add QJx 0.17 -0.02 add QJ9 0.25 0.01 add QJT 0.31 0.09 add Kxx 0.29 0.20 add K9x 0.37 0.26 add KTx 0.54 0.36 add KT9 0.57 0.37 add KJx 0.81 0.53 add KJ9 0.87 0.55 add KJT 0.95 0.62 add Axx 1.06 0.77 add KQx 1.17 0.78 add A9x 1.12 0.81 add KQ9 1.26 0.83 add KQT 1.31 0.86 add ATx 1.28 0.92 add KQJ 1.44 0.96 add AT9 1.32 0.97 add AJx 1.59 1.11 add AJ9 1.71 1.18 add AJT 1.82 1.26 add AQx 1.98 1.40 add AQ9 2.05 1.46 add AQT 2.16 1.52 add AQJ 2.31 1.64 add AKx 2.44 1.77 add AK9 2.48 1.82 add AKT 2.61 1.88 add AKJ 2.77 2.01 add AKQ 3.01 2.22 add xxxx -1.70 -1.16 add 9xxx -1.59 -1.10 add Txxx -1.44 -1.02 add T9xx -1.36 -0.98 add Jxxx -1.15 -0.87 add J9xx -1.04 -0.81 add JTxx -0.92 -0.73 add JT9x -0.85 -0.68 add Qxxx -0.75 -0.59 add Q9xx -0.63 -0.52 add QTxx -0.47 -0.43 add QT9x -0.40 -0.37 add QJxx -0.27 -0.29 add QJ9x -0.20 -0.25 add QJTx -0.10 -0.18 add QJT9 -0.06 -0.13 add Kxxx -0.17 -0.11 add K9xx -0.05 -0.04 add KTxx 0.10 0.07 add KT9x 0.20 0.12 add KJxx 0.36 0.25 add KJ9x 0.46 0.32 add KJTx 0.55 0.38 add KJT9 0.63 0.43 add Axxx 0.57 0.45 add KQxx 0.66 0.48 add A9xx 0.68 0.53 add KQ9x 0.76 0.55 add KQTx 0.85 0.60 add KQT9 0.86 0.62 add ATxx 0.85 0.63 add AT9x 0.95 0.69 add KQJx 1.03 0.72 add KQJT 1.12 0.74 add KQJ9 1.05 0.77 add AJxx 1.11 0.82 add AJ9x 1.23 0.90 add AJT9 1.33 0.98 add AJTx 1.35 0.99 add AQxx 1.47 1.10 add AQ9x 1.57 1.17 add AQT9 1.67 1.25 add AQTx 1.70 1.26 add AQJx 1.89 1.41 add AQJ9 1.94 1.45 add AQJT 1.91 1.45 add AKxx 1.93 1.48 add AK9x 2.02 1.55 add AKTx 2.16 1.64 add AKT9 2.18 1.64 add AKJ9 2.36 1.77 add AKJx 2.34 1.77 add AKJT 2.46 1.85 add AKQx 2.67 1.99 add AKQ9 2.70 2.00 add AKQT 2.76 2.06 add AKQJ 2.91 2.14 add xxxxx -2.05 -1.42 add 9xxxx -1.97 -1.38 add Txxxx -1.81 -1.30 add T9xxx -1.74 -1.24 add Jxxxx -1.55 -1.14 add J9xxx -1.47 -1.08 add JTxxx -1.38 -1.00 add JT9xx -1.31 -0.95 add Qxxxx -1.17 -0.87 add Q9xxx -1.06 -0.79 add QTxxx -0.95 -0.72 add QT9xx -0.86 -0.65 add QJxxx -0.73 -0.57 add QJ9xx -0.68 -0.53 add QJTxx -0.56 -0.43 add Kxxxx -0.58 -0.42 add QJT9x -0.55 -0.42 add K9xxx -0.47 -0.33 add KTxxx -0.33 -0.24 add KT9xx -0.21 -0.16 add KJxxx -0.06 -0.06 add KJ9xx 0.01 0.00 add KJTxx 0.11 0.06 add KJT9x 0.16 0.13 add KQxxx 0.24 0.16 add Axxxx 0.18 0.17 add A9xxx 0.28 0.23 add KQ9xx 0.35 0.25 add KQTxx 0.43 0.31 add ATxxx 0.46 0.35 add KQT9x 0.52 0.39 add AT9xx 0.53 0.42 add KQJxx 0.63 0.43 add KQJ9x 0.69 0.47 add AJxxx 0.72 0.53 add KQJTx 0.75 0.53 add KQJT9 0.82 0.54 add AJ9xx 0.83 0.62 add AJTxx 0.99 0.70 add AJT9x 1.00 0.74 add AQxxx 1.10 0.81 add AQ9xx 1.20 0.89 add AQTxx 1.32 0.96 add AQT9x 1.41 1.03 add AQJxx 1.54 1.10 add AQJT9 1.57 1.15 add AQJ9x 1.59 1.16 add AQJTx 1.60 1.16 add AKxxx 1.55 1.18 add AK9xx 1.66 1.26 add AKTxx 1.80 1.34 add AKT9x 1.91 1.42 add AKJxx 2.06 1.50 add AKJ9x 2.16 1.55 add AKJTx 2.20 1.58 add AKJT9 2.18 1.61 add AKQxx 2.41 1.71 add AKQ9x 2.44 1.74 add AKQTx 2.55 1.77 add AKQT9 2.58 1.80 add AKQJ9 2.73 1.88 add AKQJx 2.75 1.89 add AKQJT 2.84 1.97 add xxxxxx -2.45 -1.63 add 9xxxxx -2.36 -1.62 add Txxxxx -2.22 -1.53 add T9xxxx -2.15 -1.45 add Jxxxxx -1.97 -1.37 add J9xxxx -1.94 -1.32 add JTxxxx -1.86 -1.23 add JT9xxx -1.83 -1.19 add Qxxxxx -1.60 -1.11 add Q9xxxx -1.56 -1.08 add QTxxxx -1.44 -0.98 add QT9xxx -1.39 -0.91 add QJxxxx -1.22 -0.81 add QJ9xxx -1.16 -0.75 add Kxxxxx -0.99 -0.70 add QJTxxx -1.12 -0.70 add QJT9xx -1.07 -0.65 add K9xxxx -0.91 -0.61 add KTxxxx -0.76 -0.54 add KT9xxx -0.69 -0.46 add KJxxxx -0.53 -0.37 add KJ9xxx -0.41 -0.28 add KJTxxx -0.34 -0.22 add KQxxxx -0.16 -0.13 add KJT9xx -0.25 -0.12 add Axxxxx -0.24 -0.12 add KQ9xxx -0.13 -0.08 add A9xxxx -0.12 -0.02 add KQTxxx 0.00 0.02 add KQT9xx 0.06 0.06 add ATxxxx 0.06 0.07 add KQJxxx 0.20 0.14 add AT9xxx 0.13 0.14 add KQJ9xx 0.21 0.19 add AJxxxx 0.32 0.23 add KQJTxx 0.29 0.26 add KQJT9x 0.29 0.29 add AJ9xxx 0.44 0.29 add AJTxxx 0.57 0.40 add AJT9xx 0.63 0.45 add AQxxxx 0.76 0.52 add AQ9xxx 0.86 0.57 add AQTxxx 0.99 0.65 add AQT9xx 1.02 0.71 add AQJxxx 1.16 0.79 add AQJ9xx 1.24 0.83 add AKxxxx 1.27 0.88 add AQJTxx 1.33 0.89 add AQJT9x 1.36 0.91 add AK9xxx 1.41 0.97 add AKTxxx 1.54 1.03 add AKT9xx 1.60 1.09 add AKJxxx 1.84 1.18 add AKJ9xx 1.93 1.25 add AKJTxx 1.95 1.30 add AKJT9x 2.02 1.32 add AKQxxx 2.21 1.40 add AKQ9xx 2.26 1.46 add AKQT9x 2.46 1.48 add AKQTxx 2.35 1.51 add AKQJxx 2.56 1.61 add AKQJ9x 2.60 1.66 add AKQJTx 2.74 1.69 add AKQJT9 2.86 1.75 add xxxxxxx -2.84 -1.84 add 9xxxxxx -2.83 -1.83 add Txxxxxx -2.64 -1.67 add T9xxxxx -2.62 -1.66 add Jxxxxxx -2.35 -1.53 add J9xxxxx -2.34 -1.52 add JTxxxxx -2.36 -1.42 add JT9xxxx -2.34 -1.40 add Qxxxxxx -2.05 -1.28 add Q9xxxxx -2.03 -1.27 add QTxxxxx -1.93 -1.21 add QT9xxxx -1.91 -1.20 add QJxxxxx -1.74 -1.01 add QJ9xxxx -1.72 -1.00 add Kxxxxxx -1.40 -0.90 add K9xxxxx -1.38 -0.88 add QJTxxxx -1.63 -0.88 add QJT9xxx -1.61 -0.86 add KTxxxxx -1.14 -0.71 add KT9xxxx -1.12 -0.70 add KJxxxxx -0.94 -0.57 add KJ9xxxx -0.92 -0.56 add KJTxxxx -0.85 -0.45 add KJT9xxx -0.83 -0.44 add Axxxxxx -0.52 -0.32 add KQxxxxx -0.59 -0.32 add A9xxxxx -0.50 -0.31 add KQ9xxxx -0.57 -0.30 add KQTxxxx -0.54 -0.23 add KQT9xxx -0.52 -0.21 add ATxxxxx -0.27 -0.15 add AT9xxxx -0.25 -0.14 add KQJxxxx -0.38 -0.11 add KQJ9xxx -0.36 -0.10 add KQJTxxx -0.32 -0.04 add KQJT9xx -0.30 -0.02 add AJxxxxx 0.03 0.02 add AJ9xxxx 0.04 0.04 add AJTxxxx 0.15 0.11 add AJT9xxx 0.17 0.12 add AQxxxxx 0.49 0.26 add AQ9xxxx 0.51 0.27 add AQTxxxx 0.66 0.39 add AQT9xxx 0.68 0.41 add AQJxxxx 0.87 0.51 add AQJ9xxx 0.89 0.53 add AKxxxxx 1.05 0.64 add AK9xxxx 1.07 0.66 add AQJTxxx 1.06 0.67 add AQJT9xx 1.08 0.69 add AKTxxxx 1.30 0.76 add AKT9xxx 1.32 0.78 add AKJxxxx 1.67 0.92 add AKJ9xxx 1.69 0.94 add AKJTxxx 1.69 0.98 add AKJT9xx 1.71 0.99 add AKQxxxx 2.01 1.11 add AKQ9xxx 2.02 1.12 add AKQTxxx 2.14 1.19 add AKQT9xx 2.15 1.20 add AKQJxxx 2.31 1.29 add AKQJ9xx 2.33 1.30 add AKQJTxx 2.33 1.32 add AKQJT9x 2.34 1.33 add Txxxxxxx -3.54 -2.17 add T9xxxxxx -3.53 -2.15 add JTxxxxxx -3.01 -1.72 add JT9xxxxx -3.00 -1.71 add Jxxxxxxx -2.71 -1.66 add J9xxxxxx -2.69 -1.65 add Qxxxxxxx -2.64 -1.65 add Q9xxxxxx -2.63 -1.64 add 9xxxxxxx -2.61 -1.54 add QTxxxxxx -2.26 -1.30 add QT9xxxxx -2.24 -1.29 add QJxxxxxx -2.38 -1.17 add QJ9xxxxx -2.36 -1.16 add QJTxxxxx -2.22 -1.09 add QJT9xxxx -2.21 -1.07 add KTxxxxxx -1.73 -1.00 add KT9xxxxx -1.71 -0.99 add Kxxxxxxx -1.39 -0.83 add K9xxxxxx -1.38 -0.82 add KJxxxxxx -1.45 -0.80 add KJ9xxxxx -1.43 -0.79 add KJTxxxxx -1.49 -0.72 add KJT9xxxx -1.47 -0.70 add KQxxxxxx -1.21 -0.59 add KQ9xxxxx -1.20 -0.57 add Axxxxxxx -0.79 -0.50 add A9xxxxxx -0.77 -0.49 add KQTxxxxx -1.09 -0.46 add KQT9xxxx -1.08 -0.45 add AJxxxxxx -0.43 -0.32 add AJ9xxxxx -0.42 -0.31 add KQJxxxxx -0.85 -0.24 add KQJ9xxxx -0.83 -0.23 add ATxxxxxx -0.42 -0.20 add AJTxxxxx -0.39 -0.20 add AT9xxxxx -0.41 -0.19 add KQJTxxxx -0.80 -0.19 add AJT9xxxx -0.37 -0.19 add KQJT9xxx -0.79 -0.18 add AQxxxxxx 0.06 -0.04 add AQ9xxxxx 0.07 -0.03 add AQTxxxxx 0.09 -0.01 add AQT9xxxx 0.11 0.00 add AQJxxxxx 0.53 0.21 add AQJ9xxxx 0.55 0.22 add AQJTxxxx 0.57 0.36 add AQJT9xxx 0.59 0.37 add AKxxxxxx 0.76 0.40 add AK9xxxxx 0.77 0.41 add AKTxxxxx 1.13 0.59 add AKT9xxxx 1.15 0.60 add AKJxxxxx 1.40 0.63 add AKJ9xxxx 1.41 0.64 add AKJTxxxx 1.29 0.66 add AKJT9xxx 1.31 0.67 add AKQTxxxx 1.83 0.88 add AKQxxxxx 1.82 0.89 add AKQT9xxx 1.85 0.89 add AKQ9xxxx 1.84 0.90 add AKQJxxxx 1.92 1.00 add AKQJ9xxx 1.93 1.01 add AKQJTxxx 2.20 1.08 add AKQJT9xx 2.22 1.09 add J9xxxxxxx -3.61 -2.02 add JTxxxxxxx -3.59 -2.01 add JT9xxxxxx -3.57 -1.99 add T9xxxxxxx -3.09 -1.77 add Q9xxxxxxx -2.77 -1.39 add QTxxxxxxx -2.74 -1.37 add QT9xxxxxx -2.73 -1.36 add K9xxxxxxx -3.12 -1.22 add KTxxxxxxx -3.10 -1.21 add KT9xxxxxx -3.09 -1.20 add QJxxxxxxx -2.83 -1.19 add QJ9xxxxxx -2.82 -1.18 add QJTxxxxxx -2.79 -1.17 add QJT9xxxxx -2.77 -1.16 add KJxxxxxxx -2.03 -1.00 add KJ9xxxxxx -2.01 -0.99 add KJTxxxxxx -1.99 -0.97 add KJT9xxxxx -1.97 -0.96 add KQxxxxxxx -2.06 -0.82 add KQ9xxxxxx -2.04 -0.81 add KQTxxxxxx -2.02 -0.79 add KQT9xxxxx -2.00 -0.78 add A9xxxxxxx -1.25 -0.56 add ATxxxxxxx -1.23 -0.54 add AT9xxxxxx -1.22 -0.53 add KQJxxxxxx -1.62 -0.53 add KQJ9xxxxx -1.61 -0.52 add KQJTxxxxx -1.58 -0.50 add KQJT9xxxx -1.57 -0.49 add AJxxxxxxx -0.50 -0.31 add AJ9xxxxxx -0.49 -0.30 add AJTxxxxxx -0.46 -0.29 add AJT9xxxxx -0.44 -0.27 add AQxxxxxxx 0.18 -0.11 add AQ9xxxxxx 0.19 -0.11 add AQTxxxxxx 0.22 -0.09 add AQT9xxxxx 0.23 -0.08 add AQJxxxxxx 0.14 0.01 add AQJ9xxxxx 0.16 0.02 add AQJTxxxxx 0.19 0.04 add AQJT9xxxx 0.20 0.05 add AKxxxxxxx 0.96 0.43 add AK9xxxxxx 0.98 0.44 add AKTxxxxxx 1.00 0.46 add AKT9xxxxx 1.01 0.47 add AKJxxxxxx 1.12 0.47 add AKJ9xxxxx 1.14 0.48 add AKJTxxxxx 1.16 0.50 add AKJT9xxxx 1.18 0.51 add AKQxxxxxx 1.60 0.62 add AKQ9xxxxx 1.61 0.63 add AKQTxxxxx 1.64 0.64 add AKQT9xxxx 1.65 0.65 add AKQJxxxxx 1.44 0.68 add AKQJ9xxxx 1.46 0.69 add AKQJTxxxx 1.48 0.71 add AKQJT9xxx 1.49 0.72 add JT9xxxxxxx -3.44 -1.72 add QT9xxxxxxx -2.91 -1.57 add KT9xxxxxxx -3.21 -1.40 add QJ9xxxxxxx -2.67 -1.35 add QJTxxxxxxx -2.65 -1.33 add QJT9xxxxxx -2.63 -1.32 add KJ9xxxxxxx -2.20 -1.02 add KJTxxxxxxx -2.18 -1.01 add KJT9xxxxxx -2.17 -1.00 add KQ9xxxxxxx -2.20 -0.83 add KQTxxxxxxx -2.18 -0.81 add KQT9xxxxxx -2.17 -0.80 add KQJxxxxxxx -2.18 -0.75 add KQJ9xxxxxx -2.17 -0.74 add KQJTxxxxxx -2.15 -0.72 add KQJT9xxxxx -2.13 -0.71 add AT9xxxxxxx -2.32 -0.42 add AJ9xxxxxxx -0.80 -0.39 add AJTxxxxxxx -0.78 -0.37 add AJT9xxxxxx -0.76 -0.36 add AQJxxxxxxx 0.07 -0.10 add AQJ9xxxxxx 0.09 -0.09 add AQJTxxxxxx 0.11 -0.07 add AQ9xxxxxxx 0.07 -0.07 add AQJT9xxxxx 0.12 -0.06 add AQTxxxxxxx 0.09 -0.05 add AQT9xxxxxx 0.10 -0.04 add AK9xxxxxxx 0.71 0.21 add AKTxxxxxxx 0.73 0.23 add AKT9xxxxxx 0.74 0.23 add AKJxxxxxxx 0.81 0.27 add AKJ9xxxxxx 0.82 0.29 add AKJTxxxxxx 0.84 0.30 add AKJT9xxxxx 0.86 0.31 add AKQxxxxxxx 0.85 0.35 add AKQ9xxxxxx 0.86 0.36 add AKQTxxxxxx 0.88 0.37 add AKQT9xxxxx 0.89 0.38 add AKQJxxxxxx 1.00 0.45 add AKQJ9xxxxx 1.01 0.46 add AKQJTxxxxx 1.03 0.47 add AKQJT9xxxx 1.05 0.48 add QJT9xxxxxxx -3.17 -1.27 add KJT9xxxxxxx -2.42 -1.23 add KQT9xxxxxxx -2.45 -0.91 add KQJ9xxxxxxx -2.40 -0.88 add KQJTxxxxxxx -2.38 -0.86 add KQJT9xxxxxx -2.37 -0.86 add AJT9xxxxxxx -0.20 -0.23 add AQT9xxxxxxx -0.16 -0.22 add AQJ9xxxxxxx -0.10 -0.19 add AQJTxxxxxxx -0.08 -0.18 add AQJT9xxxxxx -0.07 -0.17 add AKT9xxxxxxx 0.35 0.13 add AKJ9xxxxxxx 0.40 0.15 add AKJTxxxxxxx 0.41 0.17 add AKJT9xxxxxx 0.43 0.17 add AKQ9xxxxxxx 0.49 0.20 add AKQTxxxxxxx 0.50 0.21 add AKQT9xxxxxx 0.51 0.22 add AKQJxxxxxxx 0.56 0.24 add AKQJ9xxxxxx 0.57 0.25 add AKQJTxxxxxx 0.59 0.26 add AKQJT9xxxxx 0.60 0.27 add KQJT9xxxxxxx -2.01 -0.98 add AQJT9xxxxxxx -0.25 -0.07 add AKJT9xxxxxxx 0.17 0.05 add AKQT9xxxxxxx 0.14 0.06 add AKQJ9xxxxxxx 0.19 0.09 add AKQJTxxxxxxx 0.21 0.10 add AKQJT9xxxxxx 0.22 0.10 add AKQJT9xxxxxxx 0.00 0.00 deal319/lib/shapes.tcl0000644000175200017520000000216011063454130013021 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: shapes.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # shapeclass spade_shape {expr $s>=5 && $s>=$h && $d<=$s && $c<=$s} shapeclass heart_shape {expr $h>=5 && $s<$h && $d<=$h && $c<=$h} shapeclass diamond_shape {expr ($s<5 || $d>$s) && ($h<5 || $d>$h) && ($d>$c || ($d==$c && $d>=5))} shapeclass club_shape {expr ($s<5 || $c>$s) && ($h<5 || $c>$h) && ($d<$c || ($d==$c && $c<5))} deal319/lib/score.tcl0000644000175200017520000006111011063454130012651 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: score.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # namespace eval score { variable words set words(doubled) 1 set words(undoubled) 0 set words(redoubled) 2 set words(vul) 1 set words(nonvul) 0 set words(0) 0 set words(1) 1 set words(2) 2 set words() 0 # # - contract should be something like: # 2 spades # 6 notrump doubled # # - vulword should be one of "vul" or "nonvul" # # - tricks should be the number of tricks taken # # So you might say: # # % score {6 spades doubled} vul 12 # 1660 proc score {contract vulword tricks} { set bid [lindex $contract 0] set denom [lindex $contract 1] set dword [lindex $contract 2] variable words set dlevel $words($dword) set vul $words($vulword) if {$tricks>=$bid+6} { return [score_make $vul $denom $bid $tricks $dlevel] } else { return [score_set $vul [expr {$bid+6-$tricks}] $dlevel] } } proc is_minor {suit} { expr {"$suit"=="clubs"||"$suit"=="diamonds"} } proc is_major {suit} { expr {"$suit"=="spades"||"$suit"=="hearts"} } variable downdoubled set downdoubled(1) [list 0 200 500 800 1100 1400 1700 2000 2300 2600 2900 3200 3500 3800] set downdoubled(0) [list 0 100 300 500 800 1100 1400 1700 2000 2300 2600 2900 3200 3500] proc score_set {vul deficit dlevel} { if {$dlevel==0} { return [expr {-50*$deficit*($vul+1)}] } variable downdoubled expr {[lindex $downdoubled($vul) $deficit]*$dlevel*-1} } proc score_make {vul denom bid tricks dlevel} { set firstv 0 if {[is_minor $denom]} { set trickv 20 } elseif {[is_major $denom]} { set trickv 30 } else { set trickv 30 set firstv 10 } set base 0 if {$dlevel>0} { set trickv [expr {$dlevel*2*$trickv}] set firstv [expr {$dlevel*2*$firstv}] set overtrickv [expr {100*$dlevel*($vul+1)}] incr base [expr {50*$dlevel}] } else { set overtrickv $trickv } set bidtricks [expr 6+$bid] set overtricks [expr {$tricks-$bidtricks}] set contractvalue [expr {$trickv*$bid+$firstv}] if {$contractvalue>=100} { # game! incr base [expr {$vul? 500 : 300}] } else { # partscore incr base 50 } incr base $contractvalue incr base [expr {$overtricks*$overtrickv}] if {12==$bidtricks} { incr base [expr {$vul?750:500}] } if {13==$bidtricks} { incr base [expr {$vul?1500:1000}] } set base } namespace export score variable scoredata proc initdata {} { variable scoredata foreach {result score} { {1 clubs vul} {-700 -600 -500 -400 -300 -200 -100 70 90 110 130 150 170 190} {1 clubs nonvul} {-350 -300 -250 -200 -150 -100 -50 70 90 110 130 150 170 190} {1 clubs doubled vul} {-2000 -1700 -1400 -1100 -800 -500 -200 140 340 540 740 940 1140 1340} {1 clubs doubled nonvul} {-1700 -1400 -1100 -800 -500 -300 -100 140 240 340 440 540 640 740} {1 clubs redoubled vul} {-4000 -3400 -2800 -2200 -1600 -1000 -400 230 630 1030 1430 1830 2230 2630} {1 clubs redoubled nonvul} {-3400 -2800 -2200 -1600 -1000 -600 -200 230 430 630 830 1030 1230 1430} {1 diamonds vul} {-700 -600 -500 -400 -300 -200 -100 70 90 110 130 150 170 190} {1 diamonds nonvul} {-350 -300 -250 -200 -150 -100 -50 70 90 110 130 150 170 190} {1 diamonds doubled vul} {-2000 -1700 -1400 -1100 -800 -500 -200 140 340 540 740 940 1140 1340} {1 diamonds doubled nonvul} {-1700 -1400 -1100 -800 -500 -300 -100 140 240 340 440 540 640 740} {1 diamonds redoubled vul} {-4000 -3400 -2800 -2200 -1600 -1000 -400 230 630 1030 1430 1830 2230 2630} {1 diamonds redoubled nonvul} {-3400 -2800 -2200 -1600 -1000 -600 -200 230 430 630 830 1030 1230 1430} {1 hearts vul} {-700 -600 -500 -400 -300 -200 -100 80 110 140 170 200 230 260} {1 hearts nonvul} {-350 -300 -250 -200 -150 -100 -50 80 110 140 170 200 230 260} {1 hearts doubled vul} {-2000 -1700 -1400 -1100 -800 -500 -200 160 360 560 760 960 1160 1360} {1 hearts doubled nonvul} {-1700 -1400 -1100 -800 -500 -300 -100 160 260 360 460 560 660 760} {1 hearts redoubled vul} {-4000 -3400 -2800 -2200 -1600 -1000 -400 720 1120 1520 1920 2320 2720 3120} {1 hearts redoubled nonvul} {-3400 -2800 -2200 -1600 -1000 -600 -200 520 720 920 1120 1320 1520 1720} {1 spades vul} {-700 -600 -500 -400 -300 -200 -100 80 110 140 170 200 230 260} {1 spades nonvul} {-350 -300 -250 -200 -150 -100 -50 80 110 140 170 200 230 260} {1 spades doubled vul} {-2000 -1700 -1400 -1100 -800 -500 -200 160 360 560 760 960 1160 1360} {1 spades doubled nonvul} {-1700 -1400 -1100 -800 -500 -300 -100 160 260 360 460 560 660 760} {1 spades redoubled vul} {-4000 -3400 -2800 -2200 -1600 -1000 -400 720 1120 1520 1920 2320 2720 3120} {1 spades redoubled nonvul} {-3400 -2800 -2200 -1600 -1000 -600 -200 520 720 920 1120 1320 1520 1720} {1 notrump vul} {-700 -600 -500 -400 -300 -200 -100 90 120 150 180 210 240 270} {1 notrump nonvul} {-350 -300 -250 -200 -150 -100 -50 90 120 150 180 210 240 270} {1 notrump doubled vul} {-2000 -1700 -1400 -1100 -800 -500 -200 180 380 580 780 980 1180 1380} {1 notrump doubled nonvul} {-1700 -1400 -1100 -800 -500 -300 -100 180 280 380 480 580 680 780} {1 notrump redoubled vul} {-4000 -3400 -2800 -2200 -1600 -1000 -400 760 1160 1560 1960 2360 2760 3160} {1 notrump redoubled nonvul} {-3400 -2800 -2200 -1600 -1000 -600 -200 560 760 960 1160 1360 1560 1760} {2 clubs vul} {-800 -700 -600 -500 -400 -300 -200 -100 90 110 130 150 170 190} {2 clubs nonvul} {-400 -350 -300 -250 -200 -150 -100 -50 90 110 130 150 170 190} {2 clubs doubled vul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -200 180 380 580 780 980 1180} {2 clubs doubled nonvul} {-2000 -1700 -1400 -1100 -800 -500 -300 -100 180 280 380 480 580 680} {2 clubs redoubled vul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 760 1160 1560 1960 2360 2760} {2 clubs redoubled nonvul} {-4000 -3400 -2800 -2200 -1600 -1000 -600 -200 560 760 960 1160 1360 1560} {2 diamonds vul} {-800 -700 -600 -500 -400 -300 -200 -100 90 110 130 150 170 190} {2 diamonds nonvul} {-400 -350 -300 -250 -200 -150 -100 -50 90 110 130 150 170 190} {2 diamonds doubled vul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -200 180 380 580 780 980 1180} {2 diamonds doubled nonvul} {-2000 -1700 -1400 -1100 -800 -500 -300 -100 180 280 380 480 580 680} {2 diamonds redoubled vul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 760 1160 1560 1960 2360 2760} {2 diamonds redoubled nonvul} {-4000 -3400 -2800 -2200 -1600 -1000 -600 -200 560 760 960 1160 1360 1560} {2 hearts vul} {-800 -700 -600 -500 -400 -300 -200 -100 110 140 170 200 230 260} {2 hearts nonvul} {-400 -350 -300 -250 -200 -150 -100 -50 110 140 170 200 230 260} {2 hearts doubled vul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -200 670 870 1070 1270 1470 1670} {2 hearts doubled nonvul} {-2000 -1700 -1400 -1100 -800 -500 -300 -100 470 570 670 770 870 970} {2 hearts redoubled vul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 840 1240 1640 2040 2440 2840} {2 hearts redoubled nonvul} {-4000 -3400 -2800 -2200 -1600 -1000 -600 -200 640 840 1040 1240 1440 1640} {2 spades vul} {-800 -700 -600 -500 -400 -300 -200 -100 110 140 170 200 230 260} {2 spades nonvul} {-400 -350 -300 -250 -200 -150 -100 -50 110 140 170 200 230 260} {2 spades doubled vul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -200 670 870 1070 1270 1470 1670} {2 spades doubled nonvul} {-2000 -1700 -1400 -1100 -800 -500 -300 -100 470 570 670 770 870 970} {2 spades redoubled vul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 840 1240 1640 2040 2440 2840} {2 spades redoubled nonvul} {-4000 -3400 -2800 -2200 -1600 -1000 -600 -200 640 840 1040 1240 1440 1640} {2 notrump vul} {-800 -700 -600 -500 -400 -300 -200 -100 120 150 180 210 240 270} {2 notrump nonvul} {-400 -350 -300 -250 -200 -150 -100 -50 120 150 180 210 240 270} {2 notrump doubled vul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -200 690 890 1090 1290 1490 1690} {2 notrump doubled nonvul} {-2000 -1700 -1400 -1100 -800 -500 -300 -100 490 590 690 790 890 990} {2 notrump redoubled vul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 880 1280 1680 2080 2480 2880} {2 notrump redoubled nonvul} {-4000 -3400 -2800 -2200 -1600 -1000 -600 -200 680 880 1080 1280 1480 1680} {3 clubs vul} {-900 -800 -700 -600 -500 -400 -300 -200 -100 110 130 150 170 190} {3 clubs nonvul} {-450 -400 -350 -300 -250 -200 -150 -100 -50 110 130 150 170 190} {3 clubs doubled vul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 670 870 1070 1270 1470} {3 clubs doubled nonvul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 470 570 670 770 870} {3 clubs redoubled vul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 840 1240 1640 2040 2440} {3 clubs redoubled nonvul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 640 840 1040 1240 1440} {3 diamonds vul} {-900 -800 -700 -600 -500 -400 -300 -200 -100 110 130 150 170 190} {3 diamonds nonvul} {-450 -400 -350 -300 -250 -200 -150 -100 -50 110 130 150 170 190} {3 diamonds doubled vul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 670 870 1070 1270 1470} {3 diamonds doubled nonvul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 470 570 670 770 870} {3 diamonds redoubled vul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 840 1240 1640 2040 2440} {3 diamonds redoubled nonvul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 640 840 1040 1240 1440} {3 hearts vul} {-900 -800 -700 -600 -500 -400 -300 -200 -100 140 170 200 230 260} {3 hearts nonvul} {-450 -400 -350 -300 -250 -200 -150 -100 -50 140 170 200 230 260} {3 hearts doubled vul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 730 930 1130 1330 1530} {3 hearts doubled nonvul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 530 630 730 830 930} {3 hearts redoubled vul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 960 1360 1760 2160 2560} {3 hearts redoubled nonvul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 760 960 1160 1360 1560} {3 spades vul} {-900 -800 -700 -600 -500 -400 -300 -200 -100 140 170 200 230 260} {3 spades nonvul} {-450 -400 -350 -300 -250 -200 -150 -100 -50 140 170 200 230 260} {3 spades doubled vul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 730 930 1130 1330 1530} {3 spades doubled nonvul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 530 630 730 830 930} {3 spades redoubled vul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 960 1360 1760 2160 2560} {3 spades redoubled nonvul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 760 960 1160 1360 1560} {3 notrump vul} {-900 -800 -700 -600 -500 -400 -300 -200 -100 600 630 660 690 720} {3 notrump nonvul} {-450 -400 -350 -300 -250 -200 -150 -100 -50 400 430 460 490 520} {3 notrump doubled vul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 750 950 1150 1350 1550} {3 notrump doubled nonvul} {-2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 550 650 750 850 950} {3 notrump redoubled vul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1000 1400 1800 2200 2600} {3 notrump redoubled nonvul} {-4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 800 1000 1200 1400 1600} {4 clubs vul} {-1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 130 150 170 190} {4 clubs nonvul} {-500 -450 -400 -350 -300 -250 -200 -150 -100 -50 130 150 170 190} {4 clubs doubled vul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 710 910 1110 1310} {4 clubs doubled nonvul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 510 610 710 810} {4 clubs redoubled vul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 920 1320 1720 2120} {4 clubs redoubled nonvul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 720 920 1120 1320} {4 diamonds vul} {-1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 130 150 170 190} {4 diamonds nonvul} {-500 -450 -400 -350 -300 -250 -200 -150 -100 -50 130 150 170 190} {4 diamonds doubled vul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 710 910 1110 1310} {4 diamonds doubled nonvul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 510 610 710 810} {4 diamonds redoubled vul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 920 1320 1720 2120} {4 diamonds redoubled nonvul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 720 920 1120 1320} {4 hearts vul} {-1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 620 650 680 710} {4 hearts nonvul} {-500 -450 -400 -350 -300 -250 -200 -150 -100 -50 420 450 480 510} {4 hearts doubled vul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 790 990 1190 1390} {4 hearts doubled nonvul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 590 690 790 890} {4 hearts redoubled vul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1080 1480 1880 2280} {4 hearts redoubled nonvul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 880 1080 1280 1480} {4 spades vul} {-1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 620 650 680 710} {4 spades nonvul} {-500 -450 -400 -350 -300 -250 -200 -150 -100 -50 420 450 480 510} {4 spades doubled vul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 790 990 1190 1390} {4 spades doubled nonvul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 590 690 790 890} {4 spades redoubled vul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1080 1480 1880 2280} {4 spades redoubled nonvul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 880 1080 1280 1480} {4 notrump vul} {-1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 630 660 690 720} {4 notrump nonvul} {-500 -450 -400 -350 -300 -250 -200 -150 -100 -50 430 460 490 520} {4 notrump doubled vul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 810 1010 1210 1410} {4 notrump doubled nonvul} {-2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 610 710 810 910} {4 notrump redoubled vul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1120 1520 1920 2320} {4 notrump redoubled nonvul} {-5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 920 1120 1320 1520} {5 clubs vul} {-1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 600 620 640} {5 clubs nonvul} {-550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 400 420 440} {5 clubs doubled vul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 750 950 1150} {5 clubs doubled nonvul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 550 650 750} {5 clubs redoubled vul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1000 1400 1800} {5 clubs redoubled nonvul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 800 1000 1200} {5 diamonds vul} {-1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 600 620 640} {5 diamonds nonvul} {-550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 400 420 440} {5 diamonds doubled vul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 750 950 1150} {5 diamonds doubled nonvul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 550 650 750} {5 diamonds redoubled vul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1000 1400 1800} {5 diamonds redoubled nonvul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 800 1000 1200} {5 hearts vul} {-1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 650 680 710} {5 hearts nonvul} {-550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 450 480 510} {5 hearts doubled vul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 850 1050 1250} {5 hearts doubled nonvul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 650 750 850} {5 hearts redoubled vul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1200 1600 2000} {5 hearts redoubled nonvul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1000 1200 1400} {5 spades vul} {-1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 650 680 710} {5 spades nonvul} {-550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 450 480 510} {5 spades doubled vul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 850 1050 1250} {5 spades doubled nonvul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 650 750 850} {5 spades redoubled vul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1200 1600 2000} {5 spades redoubled nonvul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1000 1200 1400} {5 notrump vul} {-1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 660 690 720} {5 notrump nonvul} {-550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 460 490 520} {5 notrump doubled vul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 870 1070 1270} {5 notrump doubled nonvul} {-2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 670 770 870} {5 notrump redoubled vul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1240 1640 2040} {5 notrump redoubled nonvul} {-5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1040 1240 1440} {6 clubs vul} {-1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 1370 1390} {6 clubs nonvul} {-600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 920 940} {6 clubs doubled vul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 1540 1740} {6 clubs doubled nonvul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1090 1190} {6 clubs redoubled vul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1830 2230} {6 clubs redoubled nonvul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1380 1580} {6 diamonds vul} {-1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 1370 1390} {6 diamonds nonvul} {-600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 920 940} {6 diamonds doubled vul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 1540 1740} {6 diamonds doubled nonvul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1090 1190} {6 diamonds redoubled vul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 1830 2230} {6 diamonds redoubled nonvul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1380 1580} {6 hearts vul} {-1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 1430 1460} {6 hearts nonvul} {-600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 980 1010} {6 hearts doubled vul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 1660 1860} {6 hearts doubled nonvul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1210 1310} {6 hearts redoubled vul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2070 2470} {6 hearts redoubled nonvul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1620 1820} {6 spades vul} {-1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 1430 1460} {6 spades nonvul} {-600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 980 1010} {6 spades doubled vul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 1660 1860} {6 spades doubled nonvul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1210 1310} {6 spades redoubled vul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2070 2470} {6 spades redoubled nonvul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1620 1820} {6 notrump vul} {-1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 1440 1470} {6 notrump nonvul} {-600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 990 1020} {6 notrump doubled vul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 1680 1880} {6 notrump doubled nonvul} {-3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1230 1330} {6 notrump redoubled vul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2110 2510} {6 notrump redoubled nonvul} {-6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1660 1860} {7 clubs vul} {-1300 -1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 2140} {7 clubs nonvul} {-650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 1440} {7 clubs doubled vul} {-3800 -3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 2330} {7 clubs doubled nonvul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1630} {7 clubs redoubled vul} {-7600 -7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2660} {7 clubs redoubled nonvul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1960} {7 diamonds vul} {-1300 -1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 2140} {7 diamonds nonvul} {-650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 1440} {7 diamonds doubled vul} {-3800 -3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 2330} {7 diamonds doubled nonvul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1630} {7 diamonds redoubled vul} {-7600 -7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2660} {7 diamonds redoubled nonvul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 1960} {7 hearts vul} {-1300 -1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 2210} {7 hearts nonvul} {-650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 1510} {7 hearts doubled vul} {-3800 -3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 2470} {7 hearts doubled nonvul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1770} {7 hearts redoubled vul} {-7600 -7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2940} {7 hearts redoubled nonvul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 2240} {7 spades vul} {-1300 -1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 2210} {7 spades nonvul} {-650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 1510} {7 spades doubled vul} {-3800 -3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 2470} {7 spades doubled nonvul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1770} {7 spades redoubled vul} {-7600 -7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2940} {7 spades redoubled nonvul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 2240} {7 notrump vul} {-1300 -1200 -1100 -1000 -900 -800 -700 -600 -500 -400 -300 -200 -100 2220} {7 notrump nonvul} {-650 -600 -550 -500 -450 -400 -350 -300 -250 -200 -150 -100 -50 1520} {7 notrump doubled vul} {-3800 -3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -200 2490} {7 notrump doubled nonvul} {-3500 -3200 -2900 -2600 -2300 -2000 -1700 -1400 -1100 -800 -500 -300 -100 1790} {7 notrump redoubled vul} {-7600 -7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -400 2980} {7 notrump redoubled nonvul} {-7000 -6400 -5800 -5200 -4600 -4000 -3400 -2800 -2200 -1600 -1000 -600 -200 2280} } { set scoredata($result) $score } } initdata proc fastscore {contract vul tricks} { variable scoredata lappend contract $vul return [lindex $scoredata($contract) $tricks] } } proc score {contract vul tricks} { score::fastscore $contract $vul $tricks } deal319/lib/binky.tcl0000644000175200017520000000461411102641632012657 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: binky.tcl 290 2008-10-31 17:42:49Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/handProc.tcl namespace eval binky { variable binkyData set binkyData(nt) 0 set binkyData(suit) 1 proc add {key args} { variable binkyData set binkyData($key) $args } proc ddlookup {key column} { variable binkyData if {[info exists binkyData($key)]} { set result [lindex $binkyData($key) $column] return $result } puts stderr "Got unknown key $key" return -1000.00 } proc ddvalue {column holding len} { ddlookup $holding $column } holdingProc -string binkyconvert {A K Q J T x9 len string} { regsub -all {[2-8]} $string x string if {$len==0} { return "-" } if {$len>=1 && $len<=5} { return $string } return $string regsub 9 $string x string if {$len>=7} { regsub T $string x string } if {$len>=8} { #regsub J $string x string } return $string } proc initialize {} { variable binkyData set hbody { set converted [::binkyconvert holding $string] ::binky::ddvalue %d $converted $len } set sbody { ::binky::ddlookup [join [lsort -decreasing -integer [list $s $h $d $c]] "-"] %d } set body { expr {[binkys.%s %%h]+[binkyh.%s %%h]} } foreach contract {nt suit} { set column $binkyData($contract) holdingProc -double binkyh.$contract {x2 string len} [format $hbody $column] shapefunc binkys.$contract [format $sbody $column] handProc $contract [format $body $contract $contract] namespace export $contract } } source lib/binky-data.tcl initialize } deal319/lib/handFactory.tcl0000644000175200017520000001676111341055246014020 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: handFactory.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This source file defines a handFactory class. # It is primarily used by the "stackhand" input method, # but it can be used in other ways as well. # # When the handFactory generates a hand, it does *not* # change the status of the dealer - the current deal is not # altered. # namespace eval handFactory { variable data set data(count) 0 # dumb lookups set data(spades) 0 set data(hearts) 1 set data(diamonds) 2 set data(clubs) 3 set data(0) 0 set data(1) 1 set data(2) 2 set data(3) 3 # # Says that the data table is not up to date # proc invalidate {id} { variable data set data($id:invalid) 1 } # # The constructor. Very similar to the "stackhands" initializer, # only a handFactory does not know which seat it is going to. # proc create {{shapeclass AllShapes} {evaluator zerovector} {range {0 0}}} { variable data set id $data(count) incr data(count) proc pov$id {cmd args} "docmd \$cmd $id \$args" init $id $shapeclass $evaluator $range return "::handFactory::pov$id" } # # Utility procedure for dispatching object methods # proc docmd {command id arglist} { set cmd [list $command $id] foreach arg $arglist { lappend cmd $arg } eval $cmd } proc init {id shapeclass evaluator range} { variable data set myshape [list] set value(list:0) [list] set value(list:1) [list] set value(list:2) [list] set value(list:3) [list] set data($id:evaluator) $evaluator set data($id:evalmin) [lindex $range 0] set data($id:evalmax) [lindex $range 1] set data($id:shapeclass) $shapeclass foreach suitnum {0 1 2 3} { set data($id:$suitnum:requirements) [list] } # make invalid - means attempts to generate new deal will # construct new data table invalidate $id } proc restrictSuit {id suitname cardset {compare disjoint}} { variable data set len [holding length $cardset] if {$len>0} { set suitnum $data($suitname) addHoldingCond $id "holding $compare \$h $cardset" $suitnum } } proc restrictHand {id hand} { foreach cards $hand suitname {spades hearts diamonds clubs} { restrictSuit $id $suitname $cards } } proc addHoldingCond {id code args} { variable data if {[llength $args]==0} { set suitnums [list 0 1 2 3] } else { set suitnums [list] foreach arg $args { lappend suitnums $data($arg) } } foreach suitnum $suitnums { lappend data($id:$suitnum:requirements) $code } invalidate $id } proc setShapeclass {id class} { variable data set pov($id:shapeclass) $class invalidate $id } proc setEvaluator {id hproc min max} { variable data set data($id:evaluator) $hproc set data($id:evalmin) $min set data($id:evalmax) $max invalidate $id } proc updateData {id} { variable data if {!$data($id:invalid)} { return } set evaluator $data($id:evaluator) #deal::debug starting to update data for handFactory $id set shapeclass $data($id:shapeclass) foreach shape [$shapeclass list] { foreach suitnum {0 1 2 3} len $shape { set lengths($suitnum:$len) 1 } } foreach suitnum {0 1 2 3} { set max 0 set min 13 set rqs $data($id:$suitnum:requirements) foreachHolding h { #deal::debug holding $h in suit $suitnum set l [holding length $h] if {![info exists lengths($suitnum:$l)]} { continue } set passed 1 foreach rq $data($id:$suitnum:requirements) { if {![eval $rq]} { set passed 0 ; break } } if {!$passed} {continue} # Okay, we've decided this holding is compatible if {$l>$max} { set max $l } if {$l<$min} { set min $l } set ev [$evaluator holding $h] if {![info exists value($suitnum:$ev)]} { set value($suitnum:$ev) 1 lappend value(list:$suitnum) $ev } if {![info exists data($id:$suitnum:$l:$ev)]} { set data($id:$suitnum:$l:$ev) [list] } lappend data($id:$suitnum:$l:$ev) $h } set data($id:$suitnum:max) $max set data($id:$suitnum:min) $min } set emin $data($id:evalmin) set emax $data($id:evalmax) set data($id:values) [list] foreach s1 $value(list:0) { foreach s2 $value(list:1) { foreach s3 $value(list:2) { foreach s4 $value(list:3) { set tot [expr {$s1+$s2+$s3+$s4}] if {$tot>=$emin&&$tot<=$emax} { lappend data($id:values) [list $s1 $s2 $s3 $s4] } } } } } set total 0.0 set data($id:eshapes) [list] set countlist [list] set shapeclass $data($id:shapeclass) set code [list reject if] foreach suitnum {0 1 2 3} v {s h d c} { lappend code "\$$v>$data($id:$suitnum:max)" "\$$v<$data($id:$suitnum:min)" } lappend code "!(\[$shapeclass eval \$s \$h \$d \$c\])" shapeclass hfactory.shapeclass$id $code foreach shape [hfactory.shapeclass$id list] { foreach valueset $data($id:values) { set count 1.0 foreach suitnum {0 1 2 3} len $shape v $valueset { if {[info exists data($id:$suitnum:$len:$v)]} { set count [expr {$count*[llength $data($id:$suitnum:$len:$v)]}] } else { set count 0.0 } } if {$count>=1.0} { lappend data($id:eshapes) [list $shape $valueset] lappend countlist $count set total [expr {$total+$count}] } } } set sumprob 0.0 set data($id:problist) [list] if ($total<0.5) { error "No such hands exist" } foreach shape $data($id:eshapes) count $countlist { lappend data($id:sums) $sumprob set prob [expr {$count*1.0/$total}] lappend data($id:problist) $prob set sumprob [expr {$sumprob+$prob}] } set data($id:invalid) 0 } proc getdata {id {mult 1.0}} { updateData $id variable data set result [list] foreach eshape $data($id:eshapes) prob $data($id:problist) { lappend eshape [expr {$prob*$mult}] lappend result $eshape } return $result } proc chooseshape {id} { variable data set shapes $data($id:eshapes) set probs $data($id:sums) set i 0 set max [llength $probs] set j [expr {$max-1}] set rand [rand] # binary search code... while {$j>$i&&$i<$max} { set mid [expr {int(($j+$i+1)/2)}] if {[lindex $probs $mid]>$rand} { set j [expr {$mid-1}] } else { set i $mid } } return [lindex $shapes $i] } proc sample {id} { updateData $id variable data set pattern [chooseshape $id] set shape [lindex $pattern 0] set values [lindex $pattern 1] set hand [list] foreach suitnum {0 1 2 3} len $shape val $values { set l [llength $data($id:$suitnum:$len:$val)] lappend hand [lindex $data($id:$suitnum:$len:$val) [rand $l]] } return $hand } } defvector zerovector 0 deal319/lib/handProc.tcl0000644000175200017520000000324611063454130013302 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: handProc.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # proc handProc {name body} { set part(1) $body set part(2) $body set triples { %h $hand {hand $hand} %S {$hand spades} {hand $hand spades]} %H {$hand hearts} {hand $hand hearts]} %D {$hand diamonds} {hand $hand diamonds]} %C {$hand clubs} {hand $hand clubs]} %% % % } set procBody { if {0==[string compare $hand hand]} { set hand [lindex $args 0] set args [lrange $args 1 end] %2 } else { %1 } } foreach var {1 2} { foreach {code replace(1) replace(2)} $triples { regsub -all $code $part($var) $replace($var) part($var) } regsub -all "%$var" $procBody $part($var) procBody } uplevel [list proc $name {hand args} $procBody] } deal319/lib/ddeval.tcl0000644000175200017520000006106511063454127013014 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: ddeval.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/handProc.tcl namespace eval ddeval { variable ddData set ddData(offense/nt) 2 set ddData(defense/nt) 3 set ddData(offense/suit) 4 set ddData(defense/suit) 5 set ddData(offense/best) 0 set ddData(defense/best) 1 proc add {key count args} { variable ddData set ddData($key) $args } proc ddlookup {key column} { variable ddData if {[info exists ddData($key)]} { set result [lindex $ddData($key) $column] return $result } return -13.00 } proc ddvalue {column holding len} { set holdingval [ddlookup $holding $column] set lengthval [ddlookup length$len $column] expr {$holdingval-$lengthval} } holdingProc -string convert {A K Q J T x9 len string} { regsub -all {[2-8]} $string x string if {$len==0} { return "-" } if {$len>=1 && $len<=5} { return $string } regsub 9 $string x string if {$len>=7} { regsub T $string x string } if {$len>=8} { regsub J $string x string } return $string } proc initialize {} { variable ddData set hbody { set converted [::convert holding $string] ::ddeval::ddvalue %d $converted $len } set sbody { ::ddeval::ddlookup [join [lsort -decreasing -integer [list $s $h $d $c]] "-"] %d } set body { expr {[dds.%s.%s %%h]+[ddh.%s.%s %%h]} } foreach val {offense defense} { foreach contract {nt suit best} { set column $ddData($val/$contract) holdingProc -double ddh.$val.$contract {x2 string len} [format $hbody $column] shapefunc dds.$val.$contract [format $sbody $column] handProc $val.$contract [format $body $val $contract $val $contract] namespace export $val.$contract } } } # Raw data used # Average for lengths add length0 146816 9.62 4.54 6.14 7.25 9.62 4.58 add length1 919147 8.90 4.53 6.00 7.04 8.89 4.56 add length2 2360473 8.40 4.51 6.04 6.96 8.39 4.52 add length3 3284394 8.21 4.56 6.09 6.91 8.19 4.58 add length4 2740694 8.34 4.65 6.08 6.86 8.32 4.67 add length5 1430496 8.58 4.58 6.03 6.92 8.57 4.60 add length6 476133 8.91 4.38 6.01 7.17 8.90 4.41 add length7 100949 9.33 4.12 5.99 7.57 9.32 4.16 add length8 13488 9.84 3.82 5.96 8.04 9.84 3.86 add length9 993 10.40 3.39 5.72 8.43 10.40 3.44 add length10 48 11.00 3.29 5.90 9.29 11.00 3.35 add length11 1 12.00 4.00 6.00 6.00 12.00 4.00 # Average for shapes add 4-3-3-3 302661 7.80 4.59 6.15 6.83 7.76 4.59 add 4-4-3-2 619409 8.09 4.67 6.10 6.80 8.07 4.68 add 4-4-4-1 85946 8.62 4.83 6.09 6.79 8.61 4.85 add 5-3-3-2 443513 8.14 4.52 6.07 6.90 8.13 4.53 add 5-4-2-2 303105 8.41 4.56 6.01 6.87 8.40 4.57 add 5-4-3-1 371483 8.69 4.68 6.03 6.88 8.68 4.70 add 5-4-4-0 35658 9.38 4.80 6.19 6.99 9.37 4.84 add 5-5-2-1 91467 9.03 4.53 5.94 6.95 9.03 4.56 add 5-5-3-0 25826 9.51 4.66 6.12 7.07 9.51 4.71 add 6-3-2-2 161401 8.51 4.30 6.00 7.16 8.50 4.32 add 6-3-3-1 98854 8.78 4.43 6.03 7.17 8.77 4.46 add 6-4-2-1 134700 9.02 4.41 5.97 7.13 9.02 4.45 add 6-4-3-0 37917 9.51 4.59 6.18 7.25 9.51 4.63 add 6-5-1-1 20206 9.61 4.28 5.83 7.15 9.61 4.32 add 6-5-2-0 18685 9.88 4.38 6.03 7.27 9.88 4.43 add 6-6-1-0 2098 10.51 4.08 5.83 7.40 10.51 4.14 add 7-2-2-2 14761 8.91 4.03 5.95 7.54 8.91 4.05 add 7-3-2-1 53849 9.14 4.09 5.94 7.53 9.13 4.13 add 7-3-3-0 7522 9.65 4.29 6.16 7.64 9.64 4.35 add 7-4-1-1 11107 9.67 4.16 5.98 7.61 9.66 4.20 add 7-4-2-0 10387 9.89 4.25 6.14 7.69 9.88 4.30 add 7-5-1-0 3149 10.50 4.11 6.00 7.75 10.50 4.15 add 7-6-0-0 174 11.18 3.80 6.14 7.59 11.18 3.86 add 8-2-2-1 5565 9.57 3.76 5.87 7.96 9.57 3.80 add 8-3-1-1 3403 9.83 3.84 5.96 8.11 9.82 3.88 add 8-3-2-0 3076 10.00 3.87 6.08 8.07 9.99 3.92 add 8-4-1-0 1333 10.49 3.88 6.06 8.16 10.49 3.92 add 8-5-0-0 111 11.26 3.70 6.02 7.98 11.26 3.71 add 9-2-1-1 468 10.19 3.31 5.61 8.34 10.19 3.36 add 9-2-2-0 228 10.56 3.54 5.99 8.73 10.55 3.60 add 9-3-1-0 268 10.56 3.39 5.63 8.31 10.55 3.44 add 9-4-0-0 29 11.24 3.41 6.17 8.62 11.24 3.41 add 10-1-1-1 9 10.89 3.33 4.89 9.11 10.89 3.56 add 10-2-1-0 38 10.97 3.21 5.95 9.24 10.97 3.24 add 10-3-0-0 1 13.00 6.00 13.00 13.00 13.00 6.00 add 11-1-1-0 1 12.00 4.00 6.00 6.00 12.00 4.00 # Average for holdings add - 146816 9.62 4.54 6.14 7.25 9.62 4.58 add x 495231 8.81 4.41 5.84 6.89 8.80 4.44 add 9 70427 8.82 4.42 5.85 6.89 8.81 4.46 add T 70675 8.82 4.43 5.86 6.91 8.81 4.46 add J 71048 8.85 4.49 5.92 6.99 8.85 4.52 add Q 70924 8.89 4.58 6.02 7.08 8.88 4.61 add K 70241 8.97 4.75 6.26 7.28 8.96 4.77 add A 70601 9.62 5.31 7.23 8.16 9.61 5.33 add xx 635907 8.10 4.17 5.55 6.51 8.09 4.19 add 9x 212118 8.11 4.19 5.56 6.52 8.10 4.21 add Tx 212445 8.13 4.22 5.60 6.56 8.11 4.24 add T9 30256 8.13 4.23 5.62 6.57 8.12 4.25 add Jx 211292 8.18 4.30 5.72 6.67 8.17 4.32 add J9 29947 8.19 4.32 5.75 6.69 8.18 4.33 add JT 30091 8.23 4.35 5.76 6.72 8.22 4.37 add Q9 30585 8.31 4.46 5.93 6.86 8.29 4.47 add Qx 211693 8.31 4.45 5.95 6.87 8.29 4.47 add QT 29998 8.35 4.51 6.00 6.95 8.33 4.52 add QJ 30423 8.39 4.56 6.05 7.00 8.37 4.57 add Kx 211718 8.71 4.84 6.56 7.40 8.69 4.86 add K9 30151 8.73 4.86 6.58 7.43 8.71 4.88 add KT 30110 8.75 4.90 6.63 7.47 8.73 4.91 add KJ 30345 8.83 5.01 6.77 7.62 8.80 5.02 add KQ 30192 8.94 5.14 6.91 7.79 8.92 5.15 add Ax 211106 9.09 5.20 7.10 7.95 9.08 5.22 add A9 30596 9.10 5.22 7.10 7.95 9.08 5.24 add AT 30558 9.12 5.26 7.14 7.99 9.10 5.27 add AJ 30125 9.20 5.34 7.26 8.11 9.18 5.35 add AQ 30399 9.43 5.58 7.65 8.42 9.40 5.59 add AK 30418 9.65 5.85 7.85 8.62 9.63 5.86 add xxx 401886 7.64 3.97 5.23 6.13 7.62 3.98 add 9xx 241434 7.65 3.99 5.24 6.14 7.63 4.00 add Txx 241139 7.70 4.04 5.32 6.21 7.68 4.05 add T9x 80254 7.72 4.06 5.34 6.23 7.70 4.07 add Jxx 241111 7.80 4.16 5.51 6.37 7.78 4.17 add J9x 80790 7.83 4.20 5.54 6.40 7.81 4.21 add JTx 80365 7.88 4.23 5.60 6.46 7.86 4.24 add JT9 11637 7.92 4.26 5.61 6.48 7.90 4.27 add Qxx 240850 8.02 4.38 5.89 6.69 8.00 4.39 add Q9x 80391 8.06 4.42 5.94 6.74 8.03 4.43 add QT9 11313 8.12 4.56 6.09 6.88 8.09 4.56 add QTx 80633 8.12 4.52 6.07 6.86 8.10 4.52 add QJ9 11575 8.20 4.62 6.23 7.01 8.17 4.63 add QJx 80296 8.21 4.62 6.24 7.01 8.18 4.62 add QJT 11524 8.26 4.67 6.29 7.06 8.22 4.67 add Kxx 241066 8.36 4.71 6.31 7.10 8.33 4.72 add K9x 80122 8.40 4.76 6.37 7.16 8.38 4.77 add KTx 80536 8.47 4.84 6.48 7.26 8.44 4.84 add KT9 11304 8.52 4.90 6.57 7.34 8.49 4.91 add KJx 80827 8.62 4.99 6.70 7.46 8.58 5.00 add KJ9 11500 8.62 5.04 6.73 7.48 8.59 5.05 add KJT 11448 8.66 5.08 6.79 7.54 8.63 5.09 add Axx 240375 8.71 5.03 6.79 7.59 8.69 5.04 add A9x 80825 8.76 5.09 6.85 7.65 8.74 5.10 add KQx 80907 8.76 5.17 6.90 7.66 8.73 5.17 add KQ9 11528 8.76 5.19 6.91 7.66 8.73 5.20 add ATx 79893 8.82 5.18 6.95 7.73 8.79 5.19 add AT9 11583 8.85 5.21 6.97 7.75 8.82 5.22 add KQT 11434 8.85 5.25 7.01 7.76 8.82 5.25 add KQJ 11431 8.85 5.32 7.03 7.78 8.82 5.32 add AJx 80441 8.97 5.32 7.19 7.93 8.94 5.33 add AJ9 11585 9.03 5.36 7.23 7.99 9.00 5.37 add AJT 11452 9.05 5.44 7.32 8.06 9.03 5.44 add AQx 79757 9.18 5.52 7.44 8.18 9.15 5.53 add AQ9 11600 9.20 5.57 7.49 8.24 9.18 5.58 add AQT 11377 9.27 5.64 7.57 8.30 9.23 5.65 add AQJ 11643 9.34 5.74 7.65 8.38 9.30 5.75 add AKx 80396 9.38 5.76 7.67 8.44 9.35 5.77 add AK9 11370 9.43 5.84 7.73 8.51 9.40 5.84 add AKT 11542 9.49 5.91 7.83 8.58 9.46 5.92 add AKJ 11595 9.57 6.02 7.93 8.70 9.54 6.02 add AKQ 11659 9.68 6.15 7.99 8.81 9.65 6.16 add xxxx 134325 7.53 3.84 4.92 5.76 7.52 3.86 add 9xxx 133916 7.57 3.88 4.99 5.82 7.56 3.90 add Txxx 134132 7.63 3.94 5.11 5.91 7.62 3.96 add T9xx 80515 7.66 3.98 5.17 5.96 7.65 4.00 add Jxxx 134518 7.75 4.07 5.33 6.10 7.74 4.08 add J9xx 80574 7.80 4.11 5.41 6.16 7.78 4.13 add JTxx 80373 7.83 4.16 5.49 6.23 7.81 4.17 add JT9x 26964 7.85 4.18 5.52 6.27 7.83 4.19 add Qxxx 134360 7.94 4.24 5.59 6.35 7.92 4.26 add Q9xx 80247 8.00 4.31 5.70 6.45 7.99 4.33 add QTxx 80282 8.05 4.38 5.78 6.52 8.03 4.39 add QT9x 26750 8.11 4.45 5.88 6.61 8.09 4.45 add QJxx 80871 8.16 4.49 5.94 6.68 8.13 4.50 add QJ9x 26680 8.18 4.53 5.99 6.73 8.15 4.54 add QJTx 26374 8.23 4.56 6.02 6.78 8.20 4.57 add Kxxx 133668 8.26 4.56 5.98 6.73 8.24 4.58 add QJT9 3851 8.27 4.63 6.09 6.88 8.24 4.64 add K9xx 80561 8.32 4.63 6.07 6.81 8.30 4.64 add KTxx 80481 8.41 4.72 6.21 6.95 8.39 4.73 add KT9x 26815 8.45 4.78 6.28 7.01 8.42 4.79 add KJxx 80533 8.54 4.84 6.37 7.12 8.52 4.85 add KJ9x 26653 8.59 4.90 6.44 7.20 8.57 4.91 add Axxx 133756 8.61 4.92 6.43 7.20 8.60 4.93 add KJT9 3793 8.61 4.88 6.43 7.18 8.58 4.89 add KJTx 26936 8.63 4.93 6.47 7.25 8.61 4.94 add KQxx 80503 8.67 4.99 6.53 7.30 8.65 5.00 add A9xx 80552 8.68 4.99 6.53 7.29 8.67 5.00 add KQ9x 26862 8.72 5.03 6.58 7.38 8.69 5.04 add KQT9 3864 8.75 5.12 6.66 7.43 8.72 5.12 add ATxx 80823 8.76 5.07 6.65 7.40 8.74 5.08 add KQTx 26799 8.79 5.11 6.67 7.47 8.76 5.11 add AT9x 26668 8.81 5.13 6.74 7.47 8.79 5.14 add KQJx 26727 8.83 5.17 6.73 7.54 8.80 5.17 add KQJT 3726 8.86 5.25 6.81 7.66 8.82 5.25 add AJxx 80271 8.90 5.20 6.83 7.59 8.88 5.21 add KQJ9 3816 8.91 5.25 6.79 7.63 8.89 5.25 add AJ9x 26980 8.98 5.29 6.96 7.71 8.96 5.30 add AJTx 27168 9.03 5.33 7.01 7.79 9.00 5.34 add AJT9 3879 9.05 5.39 7.06 7.80 9.02 5.40 add AQxx 80642 9.10 5.40 7.07 7.84 9.09 5.41 add AQ9x 26929 9.15 5.43 7.13 7.90 9.13 5.44 add AQTx 26813 9.21 5.52 7.23 8.01 9.19 5.53 add AQT9 3866 9.28 5.59 7.28 8.09 9.26 5.59 add AQJ9 3843 9.29 5.62 7.32 8.12 9.27 5.63 add AKxx 80322 9.30 5.65 7.29 8.09 9.28 5.66 add AQJx 26978 9.30 5.61 7.31 8.12 9.28 5.62 add AK9x 27156 9.36 5.71 7.37 8.17 9.34 5.72 add AQJT 3810 9.38 5.69 7.38 8.19 9.35 5.70 add AKTx 26814 9.41 5.77 7.44 8.26 9.39 5.79 add AKT9 3914 9.45 5.74 7.47 8.29 9.42 5.75 add AKJx 26984 9.52 5.86 7.59 8.43 9.49 5.87 add AKJT 3777 9.55 5.93 7.60 8.45 9.52 5.93 add AKJ9 3819 9.59 5.94 7.67 8.52 9.56 5.95 add AKQx 27008 9.63 5.98 7.73 8.62 9.60 5.98 add AKQT 3889 9.69 6.05 7.81 8.71 9.66 6.05 add AKQJ 3734 9.74 6.02 7.80 8.77 9.70 6.02 add AKQ9 3830 9.74 6.04 7.82 8.77 9.72 6.04 add xxxxx 23435 7.61 3.73 4.67 5.50 7.60 3.77 add 9xxxx 38712 7.62 3.73 4.71 5.53 7.62 3.77 add Txxxx 38924 7.71 3.78 4.83 5.65 7.71 3.82 add T9xxx 39308 7.72 3.80 4.84 5.65 7.71 3.83 add Jxxxx 39174 7.79 3.88 5.01 5.80 7.78 3.90 add J9xxx 38607 7.87 3.91 5.09 5.88 7.87 3.94 add JTxxx 38886 7.89 3.91 5.09 5.90 7.88 3.94 add JT9xx 23432 7.93 3.93 5.14 5.94 7.92 3.96 add Qxxxx 39018 7.99 4.01 5.26 6.07 7.98 4.03 add Q9xxx 38439 8.06 4.06 5.35 6.17 8.05 4.09 add QTxxx 39015 8.08 4.08 5.40 6.22 8.07 4.10 add QT9xx 23360 8.14 4.13 5.46 6.30 8.13 4.14 add QJxxx 38915 8.21 4.20 5.57 6.41 8.20 4.21 add QJ9xx 23083 8.23 4.18 5.57 6.42 8.21 4.19 add QJTxx 23391 8.27 4.23 5.64 6.51 8.26 4.24 add Kxxxx 38921 8.30 4.33 5.66 6.49 8.29 4.35 add QJT9x 7792 8.32 4.26 5.68 6.56 8.31 4.28 add K9xxx 38740 8.37 4.36 5.74 6.57 8.37 4.38 add KTxxx 39207 8.45 4.42 5.86 6.69 8.43 4.44 add KT9xx 23135 8.50 4.46 5.92 6.76 8.49 4.48 add KJxxx 39145 8.56 4.52 6.01 6.88 8.55 4.53 add KJ9xx 23249 8.62 4.55 6.06 6.96 8.60 4.56 add KJTxx 23266 8.65 4.58 6.12 7.03 8.64 4.59 add Axxxx 39445 8.67 4.74 6.11 6.95 8.67 4.78 add KJT9x 7718 8.69 4.60 6.17 7.09 8.68 4.60 add A9xxx 38952 8.71 4.77 6.18 7.01 8.70 4.80 add KQxxx 38979 8.71 4.65 6.21 7.12 8.70 4.66 add KQ9xx 23514 8.76 4.68 6.25 7.18 8.74 4.69 add ATxxx 38910 8.80 4.84 6.31 7.16 8.79 4.86 add KQTxx 23299 8.82 4.73 6.36 7.31 8.80 4.74 add KQT9x 7934 8.83 4.74 6.34 7.33 8.81 4.75 add AT9xx 23167 8.85 4.91 6.41 7.25 8.84 4.94 add KQJxx 23100 8.87 4.77 6.41 7.42 8.85 4.78 add KQJ9x 7677 8.91 4.78 6.44 7.50 8.89 4.78 add KQJTx 7650 8.93 4.81 6.49 7.56 8.91 4.82 add KQJT9 1137 8.94 4.78 6.46 7.60 8.91 4.78 add AJxxx 38828 8.96 4.96 6.53 7.40 8.95 4.98 add AJ9xx 23184 9.01 4.99 6.62 7.51 8.99 5.01 add AJTxx 23230 9.07 5.03 6.71 7.63 9.06 5.05 add AJT9x 7762 9.11 5.05 6.72 7.66 9.10 5.06 add AQxxx 39193 9.15 5.13 6.77 7.67 9.13 5.15 add AQ9xx 23417 9.22 5.19 6.89 7.80 9.20 5.20 add AQTxx 23262 9.29 5.22 6.98 7.92 9.27 5.24 add AQT9x 7794 9.29 5.24 6.97 7.92 9.28 5.25 add AKxxx 38890 9.35 5.39 7.02 7.96 9.34 5.41 add AQJxx 23241 9.37 5.27 7.05 8.05 9.35 5.28 add AQJ9x 7730 9.40 5.31 7.12 8.13 9.38 5.32 add AK9xx 23241 9.41 5.41 7.10 8.06 9.40 5.43 add AQJTx 7670 9.44 5.33 7.18 8.20 9.42 5.33 add AQJT9 1099 9.44 5.34 7.16 8.19 9.42 5.35 add AKTxx 23269 9.47 5.46 7.21 8.19 9.46 5.48 add AKT9x 7676 9.51 5.46 7.26 8.25 9.49 5.48 add AKJT9 1100 9.58 5.47 7.37 8.39 9.56 5.48 add AKJ9x 7934 9.58 5.50 7.36 8.42 9.56 5.51 add AKJxx 23406 9.60 5.56 7.41 8.43 9.58 5.57 add AKJTx 7876 9.65 5.57 7.44 8.54 9.63 5.58 add AKQxx 23248 9.69 5.60 7.55 8.65 9.67 5.61 add AKQ9x 7710 9.73 5.63 7.59 8.74 9.72 5.63 add AKQT9 1156 9.79 5.66 7.75 8.86 9.76 5.66 add AKQTx 7814 9.79 5.65 7.70 8.86 9.77 5.66 add AKQJx 7910 9.84 5.68 7.82 9.02 9.81 5.69 add AKQJT 1142 9.85 5.67 7.86 9.04 9.82 5.67 add AKQJ9 1078 9.90 5.79 7.99 9.12 9.87 5.79 add xxxxxx 7826 7.82 3.54 4.41 5.31 7.82 3.60 add Txxxxx 15523 7.92 3.58 4.54 5.44 7.91 3.64 add Jxxxxx 15505 8.00 3.63 4.68 5.60 8.00 3.68 add JTxxxx 19384 8.10 3.67 4.77 5.70 8.10 3.72 add Qxxxxx 15529 8.16 3.77 4.97 5.92 8.16 3.81 add QTxxxx 19569 8.28 3.81 5.06 6.05 8.27 3.85 add QJxxxx 19400 8.40 3.87 5.21 6.23 8.40 3.90 add QJTxxx 15478 8.45 3.86 5.19 6.25 8.45 3.89 add Kxxxxx 15645 8.49 4.02 5.38 6.38 8.48 4.05 add KTxxxx 19433 8.59 4.07 5.54 6.57 8.58 4.10 add KJxxxx 19269 8.69 4.13 5.71 6.80 8.68 4.15 add KJTxxx 15640 8.80 4.17 5.79 6.95 8.79 4.19 add Axxxxx 15508 8.83 4.49 5.85 6.90 8.83 4.56 add KQxxxx 19400 8.85 4.26 5.91 7.08 8.84 4.28 add KQTxxx 15623 8.94 4.32 6.01 7.26 8.93 4.33 add ATxxxx 19345 8.96 4.57 6.07 7.13 8.96 4.62 add KQJxxx 15574 9.06 4.33 6.14 7.47 9.04 4.34 add AJxxxx 19209 9.10 4.64 6.28 7.42 9.10 4.69 add KQJTxx 7917 9.11 4.37 6.16 7.51 9.10 4.38 add AJTxxx 15500 9.19 4.69 6.41 7.59 9.18 4.73 add AQxxxx 19364 9.24 4.77 6.52 7.71 9.23 4.80 add AQTxxx 15428 9.38 4.82 6.71 7.95 9.37 4.85 add AQJxxx 15605 9.47 4.90 6.86 8.16 9.46 4.92 add AQJTxx 7712 9.48 4.86 6.85 8.19 9.47 4.87 add AKxxxx 19384 9.54 5.05 6.93 8.20 9.53 5.07 add AKTxxx 15645 9.61 5.05 7.06 8.38 9.60 5.07 add AKJxxx 15651 9.73 5.14 7.28 8.67 9.72 5.15 add AKJTxx 7758 9.77 5.10 7.34 8.79 9.76 5.11 add AKQxxx 15573 9.85 5.16 7.50 9.04 9.83 5.17 add AKQTxx 7698 9.92 5.21 7.65 9.23 9.90 5.21 add AKQJxx 7773 9.95 5.17 7.70 9.36 9.93 5.18 add AKQJTx 2265 9.96 5.18 7.79 9.42 9.94 5.19 add xxxxxxx 2129 8.19 3.35 4.22 5.22 8.19 3.45 add Jxxxxxx 4858 8.38 3.38 4.39 5.48 8.37 3.46 add Qxxxxxx 4977 8.55 3.51 4.63 5.81 8.55 3.57 add QJxxxxx 7351 8.70 3.57 4.80 6.03 8.70 3.63 add Kxxxxxx 4986 8.75 3.65 5.11 6.38 8.75 3.69 add KJxxxxx 7326 8.98 3.75 5.36 6.77 8.98 3.78 add Axxxxxx 5010 9.16 4.21 5.69 7.10 9.16 4.29 add KQxxxxx 7467 9.17 3.87 5.57 7.12 9.17 3.89 add KQJxxxx 7402 9.31 3.89 5.71 7.38 9.30 3.91 add AJxxxxx 7563 9.38 4.31 6.11 7.61 9.37 4.36 add AQxxxxx 7440 9.54 4.42 6.38 8.00 9.53 4.46 add AQJxxxx 7422 9.74 4.50 6.71 8.43 9.73 4.52 add AKxxxxx 7277 9.79 4.61 6.81 8.62 9.78 4.64 add AKJxxxx 7284 9.94 4.63 7.12 9.09 9.93 4.64 add AKQxxxx 7443 10.10 4.69 7.45 9.59 10.09 4.69 add AKQJxxx 5014 10.17 4.70 7.60 9.78 10.15 4.70 add xxxxxxxx 460 8.71 3.09 3.90 5.11 8.71 3.20 add Qxxxxxxx 1275 9.05 3.18 4.33 5.72 9.05 3.28 add Kxxxxxxx 1257 9.39 3.42 5.07 6.69 9.39 3.47 add KQxxxxxx 2165 9.61 3.42 5.12 6.98 9.61 3.45 add Axxxxxxx 1258 9.72 3.99 5.69 7.57 9.72 4.08 add AQxxxxxx 2209 10.05 4.10 6.40 8.47 10.04 4.15 add AKxxxxxx 2207 10.18 4.14 6.73 9.22 10.18 4.16 add AKQxxxxx 2657 10.41 4.17 7.32 10.07 10.40 4.18 add xxxxxxxxx 6 8.50 1.83 2.50 2.83 8.50 2.50 add Qxxxxxxxx 55 9.31 2.71 3.58 4.91 9.31 2.85 add Kxxxxxxxx 58 9.84 3.07 4.79 6.26 9.84 3.16 add Axxxxxxxx 70 10.00 3.17 4.74 7.30 10.00 3.31 add KQxxxxxxx 159 10.07 2.97 4.35 6.26 10.07 3.04 add AQxxxxxxx 171 10.39 3.64 6.07 8.58 10.38 3.67 add AKxxxxxxx 173 10.66 3.56 6.68 9.75 10.66 3.57 add AKQxxxxxx 301 10.88 3.62 6.54 10.16 10.88 3.65 add Kxxxxxxxxx 2 9.50 2.50 3.50 6.00 9.50 2.50 add Axxxxxxxxx 2 10.00 2.50 3.00 9.00 10.00 2.50 add KQxxxxxxxx 10 10.60 2.90 3.80 5.50 10.60 3.20 add Qxxxxxxxxx 1 11.00 4.00 5.00 5.00 11.00 4.00 add AKxxxxxxxx 6 11.00 3.67 7.83 10.33 11.00 3.67 add AQxxxxxxxx 7 11.29 4.14 7.00 11.71 11.29 4.14 add AKQxxxxxxx 20 11.35 3.20 6.55 10.60 11.35 3.20 add AKQxxxxxxxx 1 12.00 4.00 6.00 6.00 12.00 4.00 initialize handProc ::ddeval::all { set result [list] foreach evaluator {offense.suit offense.nt defense.suit defense.nt} { lappend list [list $evaluator [$evaluator %h]] } set list } } package provide DDEval 0.5 deal319/lib/bid.tcl0000644000175200017520000000274211063454127012310 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: bid.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # set bidlist "" proc describebid {bid shapecond evaluator rangemin rangemax} { global handevaluator global brmin global brmax global bidlist lappend bidlist $bid shapecond bidshape$bid $shapecond set handevaluator($bid) $evaluator set brmin($bid) $rangemin set brmax($bid) $rangemax } proc checkcondition {bid hand} { global handevaluator global brmin global brmax if {![bidshape$bid $hand]} { return 0 } set val [eval $handevaluator($bid) $hand] if {$val>=$brmin($bid) && $val<=$brmax($bid)} { return 1 } return 0 } shapefunc getbidlist { global bidlist set res "" foreach bid $bidlist { if {[bidshape$bid eval $s $h $d $c]} { lappend res $bid } } return $res } deal319/lib/features.tcl0000644000175200017520000001260311341064466013367 0ustar cbecbe# # deal.tcl - this file is sourced at startup by Deal 3.0 or later # # Copyright (C) 1996-2001, Thomas Andrews # # $Id: features.tcl 328 2010-02-23 23:48:06Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # proc dds_reset_command {} { dds_reset deal_reset_cmds [list dds_reset_command] } namespace eval deal { variable metadata variable unicode 1 # # Put data in the cache, to be unset at next call # to deal_deck # proc metadata {name code} { variable metadata if {![info exists metadata($name)]} { if {[catch {set metadata($name) [uplevel $code]}]} { global errorInfo puts stderr "Error: $errorInfo" } else { deal_reset_cmds [list unset ::deal::metadata($name)] } } return $metadata($name) } proc loop {} { next write } proc input {format args} { uplevel #0 [list source "input/$format.tcl" ] set command [list "${format}::set_input"] foreach arg $args { lappend command $arg } uplevel #0 $command } proc debug {args} { puts stderr $args } # Cause an error if any hand stacking has occured proc nostacking {} { set format [uplevel {namespace current}] proc ::stack_hand {args} \ "error \"No hand stacking with input format $format\"" proc ::stack_cards {args} \ "error \"No card stacking with input format $format\"" foreach hand {south north east west} { foreach holding [stacked $hand] { if {[holding length $holding]!=0} { error "Stacking cards is not consistent with input format $format" } } } } } # These two routines used to be defined in C, but it's better for them # to fit the pattern of shape functions. if {[string equal [info commands dds_reset] "dds_reset"]} { dds_reset_command } shapecond balanced {($h<5)&&($s<5)&&($s*$s+$h*$h+$d*$d+$c*$c)<=47} shapecond semibalanced {$h<=5&&$s<=5&&$d<=6&&$c<=6&&$c>=2&&$d>=2&&$h>=2&&$s>=2} shapecond AnyShape {1} # # The three routines, joinclass, negateclass, intersectclass, used to be # implemented in C, but were never documented and recently crashed Deal 3.0.x # when called. I've reimplemented them here in pure Tcl. # proc joinclass {newclass args} { set values [list 0] foreach class $args { lappend values "\[$class eval \$s \$h \$d \$c\]" } shapecond ___tempclass [join $values "||"] # make sure it is compiled first - use temporary name # in case we are re-using an old name for a class ___tempclass eval 13 0 0 0 rename ___tempclass $newclass } proc negateclass {newclass class} { shapecond ___tempclass "!\[$class eval \$s \$h \$d \$c\]" ___tempclass eval 13 0 0 0 rename ___tempclass $newclass } proc intersectclass {newclass args} { set values [list 1] foreach class $args { lappend values "\[$class eval \$s \$h \$d \$c\]" } shapecond ___tempclass [join $values "&&"] ___tempclass eval 13 0 0 0 rename ___tempclass $newclass } namespace eval deal { variable tricksCmd ::tricks variable tricksCache "tricks" # # "tricks" - Determine the number of tricks declarer can # make in the denomination given. # proc tricks {declarer denom} { variable tricksCmd variable tricksCache ::deal::metadata "$tricksCache.$declarer.$denom" [list $tricksCmd $declarer $denom] } } # # Returns all of the hands in a list # proc full_deal {} { return [list [north] [east] [south] [west]] } # # This is based on a contribution from Rex Livingston, who supplied # me with a C version of this routine. # It implements the New Losing Trick Count, which can be seen described on # Wikipedia at: # # http://en.wikipedia.org/wiki/Losing_trick_count#New_Losing_Trick_Count # # This is much like a 321-count in many ways. # As with the 'losers' function, it actually returns integer values, so # it returns 'half losers.' # holdingProc newLTC {A K Q J T length} { if {$length==0} { return 0 } set halflosers 0 if {!$A} { incr halflosers 3 } if {$length>1 && !$K} { incr halflosers 2} if {$length>2} { if {!$Q} { incr halflosers 1 } } return $halflosers } holdingProc zero {length} { return 0 } proc patternclass {name code} { namespace eval ::pattern "proc $name {l1 l2 l3 l4} {$code}" set shapecode { set sorted [lsort -integer -decreasing [list $s $h $d $c]] } shapeclass $name "$shapecode\n eval ::pattern::$name \$sorted" } proc patternfunc {name code} { namespace eval ::pattern "proc $name {l1 l2 l3 l4} {$code}" set shapecode { set sorted [lsort -integer -decreasing [list $s $h $d $c]] } shapefunc $name "$shapecode\n eval ::pattern::$name \$sorted" } proc patterncond {name expr} { patternclass $name "if {$expr} { return 1} else {return 0}" } deal319/lib/parscore.tcl0000644000175200017520000000770611063454130013367 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: parscore.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/score.tcl proc rlist {A B C D} {list $D $C $B $A} set parscore(order:south) [rlist south west north east] set parscore(order:west) [rlist west north east south] set parscore(order:north) [rlist north east south west] set parscore(order:east) [rlist east south west north] set parscore(mult:east) -1 set parscore(mult:west) -1 set parscore(mult:north) 1 set parscore(mult:south) 1 set parscore(pair:south) NS set parscore(pair:north) NS set parscore(pair:east) EW set parscore(pair:west) EW proc par_first_upper {word} { string toupper [string range $word 0 0] } proc par_upcase {word} { set first par_first_upper set rest [string range $word 1 end] append first $rest } proc parscore {dealer whovul} { deal::metadata parscore.$dealer.$whovul [list parscore_uncached $dealer $whovul] } proc parscore_uncached {dealer whovul} { if {"$whovul"=="EW"} { set vul(EW) vul set vul(NS) nonvul } elseif {"$whovul"=="NS"} { set vul(EW) nonvul set vul(NS) vul } elseif {"$whovul"=="All"} { set vul(EW) vul set vul(NS) vul } else { set vul(EW) nonvul set vul(NS) nonvul } global parscore # Quick call to precompute tricks foreach denom {notrump spades hearts diamonds clubs} { foreach hand {north east south west} { set tricks($hand:$denom) [deal::tricks $hand $denom] } } set hands $parscore(order:$dealer) set bestcontract {Pass} set bestdeclarer {} set bestscore 0 set besttricks "" set bestauction "Pass Pass Pass Pass" set passes(3) "Pass Pass Pass" set passes(2) "Pass Pass" set passes(1) "Pass" set passes(0) "" set biggestfit 0 for {set level 1} {$level<=7} {incr level} { set anymake 0 foreach denom {clubs diamonds hearts spades notrump} { set passcount 4 foreach declarer $hands { if {$denom == "notrump"} { set fit 14 } else { set fit [expr {[$denom $declarer]+[$denom [partner $declarer]]}] } incr passcount -1 set pair $parscore(pair:$declarer) if {$tricks($declarer:$denom)<6+$level} { set makes 0 set contract [list $level $denom doubled] } else { set makes 1 set anymake 1 set contract [list $level $denom] } set mult $parscore(mult:$declarer) set newscore [score $contract $vul($pair) $tricks($declarer:$denom)] #puts "Comparing [expr {$mult*$newscore}] in $contract by $declarer to $bestscore in $bestcontract by $bestdeclarer" if {$newscore>$mult*$bestscore || (($newscore==$mult*$bestscore) && $fit>$biggestfit) } { set biggestfit $fit set bestcontract $contract set bestdeclarer $declarer set bestscore [expr {$mult*$newscore}] set besttricks $tricks($declarer:$denom) set level [lindex $contract 0] set suit [par_first_upper [lindex $contract 1]] set auction $passes($passcount) lappend auction "$level$suit" if {!$makes} { lappend auction "X" } lappend auction set bestauction $auction } } } } list $bestcontract $bestdeclarer $bestscore $besttricks $bestauction } deal319/lib/gib.tcl0000644000175200017520000002046411063454127012314 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: gib.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # Package gib::* # # Provide an interface for the GIB double-dummy solver. # # gib::tricks # # Returns the double-dummy number of tricks in the given denomination # # gib::directory # # Tells the package where to find the GIB binaries. If this # isn't called before calling gib::tricks, it defaults to # "C:\Program Files\GIB" # namespace eval gib { variable executable {c:\Program Files\GIB\bridge.exe} variable infile {c:\temp\gibinfoo.txt} variable outfile {c:\temp\giboutfoo.txt} variable tmpfile {c:\temp\gibtempfoo.txt} proc infile {} { variable infile ; return $infile } proc outfile {} { variable outfile ; return $outfile } proc tempfile {} { variable tmpfile ; return $tmpfile } set leader(south) w set leader(west) n set leader(north) e set leader(east) s proc format_deal_gib {} { set result [list] foreach hand {north east south west} { set h [join [$hand] "."] lappend result "[string index $hand 0] $h" } join $result "\r\n" } proc directory {path} { variable executable set executable "$path/bridge.exe" } proc head_gib {declarer denom} { global gib::leader set lead $leader($declarer) set denom [string index $denom 0] return "[format_deal_gib]\n$lead $denom" } # gib always returns the count of north's tricks. This returns declarers # tricks, given # # This routine is its own inverse, so we can also use it to return # N/S tricks by passing in declarer and declarers tricks. # proc rectify_tricks {declarer nstricks} { if {"$declarer"=="north" || "$declarer"=="south"} { return $nstricks } expr {13-$nstricks} } proc execute {arguments input cards} { variable executable if {![file exists $executable]} { error "Could not find executable $executable" } set tmpfile [tempfile] set tmp [open $tmpfile w] puts $tmp $input foreach card $cards { puts $tmp $card } close $tmp #set infile [infile] #set in [open $infile w] lappend arguments -q $tmpfile set outfile [outfile] if {[file exists $outfile]} { file delete $outfile } # # If you have GIB version 3.3.x, you need to uncomment these line # Not require for previous version or later versions # #if {![file exists eval.dat]} { # file copy {c:\Games\GIB\eval.dat} eval.dat #} set exec [linsert $arguments 0 exec $executable] set output [eval $exec] return $output } # # This uses the public domain gib.exe available on Matt Ginsberg's site. # proc nstricks {declarer denom {cards {}}} { global gib::executable set arguments [list -d -v] set input [head_gib $declarer $denom] set output [execute $arguments $input $cards] set tricks "" if {![regexp {South can take ([0-9]+) trick} $output dummy tricks]} { error "Bad GIB output:\n\n$output" } return $tricks } # # "tricks" - Determine the number of tricks declarer can # make in the denomination given. # proc tricks {declarer denom} { ::deal::metadata "gib.$declarer.$denom" { rectify_tricks $declarer [nstricks $declarer $denom] } } proc tricksCmd {declarer denom} { rectify_tricks $declarer [nstricks $declarer $denom] } # # determine which leads hold declarer to his tricks # proc holdingLeads {declarer denom} { global gib::executable set tricks [tricks $declarer $denom] if {$tricks==13} { return "No lead gives up a 14th trick" } set nstricks [rectify_tricks $declarer $tricks] if {$nstricks==$tricks} { incr nstricks set search "-" } else { set search "+" } set hndl [open gibtest.txt w] puts $hndl "-d -w" puts $hndl [head_gib $declarer $denom] puts $hndl "" puts $hndl "." puts $hndl "g $nstricks" puts $hndl "p" puts $hndl "quit" close $hndl catch {set output [exec $executable "giblead.txt"]} set leads [list] set regexp "" set fh [open "giblead.txt" "r"] append regexp {([SHDC][AKQJ2-9])} "\\" $search while {![eof $fh]} { set line [gets $fh] if {[regexp $regexp $line dummy card]} { lappend leads $card } } return $leads } } # # The gib::library implements the ability to read files of the # format of Matt Ginsberg's 'library.dat' file. The file contains # deals along with the double dummy results of all possible contracts # played from all directions. # namespace eval gib::library { variable file "c:/Program Files/GIB/library.dat" variable trial 0 variable filehandle {} proc readNextData {} { variable filehandle set haveRead 0 set data "" while {$haveRead<26} { if {[eof $filehandle]} { return "" } append data [read $filehandle [expr 26-$haveRead]] set haveRead [string length $data] } return $data } set who(00) west set who(01) north set who(10) east set who(11) south set binary(0000) 0 set binary(0001) 1 set binary(0010) 2 set binary(0011) 3 set binary(0100) 4 set binary(0101) 5 set binary(0110) 6 set binary(0111) 7 set binary(1000) 8 set binary(1001) 9 set binary(1010) 10 set binary(1011) 11 set binary(1100) 12 set binary(1101) 13 set binary(1110) 14 set binary(1111) 15 variable cardNames [list A K Q J T 9 8 7 6 5 4 3 2] variable trial 1 variable deal variable suitOrder [list spades hearts diamonds clubs] proc parseData {data} { set count [binary scan $data "B32B32B32B32SSSSS" \ cards(spades) cards(hearts) cards(diamonds) cards(clubs) \ tricks(notrump) tricks(spades) tricks(hearts) tricks(diamonds) tricks(clubs) ] set suitno 0 variable cardNames variable who variable suitOrder set decoded [list] foreach hand {north east south west} { foreach suit $suitOrder { set holding($hand-$suit) "" } } foreach suit $suitOrder { binary scan $cards($suit) a6a2a2a2a2a2a2a2a2a2a2a2a2a2 dummy c(2) c(3) c(4) c(5) \ c(6) c(7) c(8) c(9) c(T) c(J) c(Q) c(K) c(A) foreach card $cardNames { set whom $who($c($card)) append holding($whom-$suit) $card } } reset_deck foreach hand {north east south west} { $hand is $holding($hand-spades) $holding($hand-hearts) \ $holding($hand-diamonds) $holding($hand-clubs) } set ddresults [list] foreach contract "notrump $suitOrder" { # trick to turning small into unsigned int set trickvalue [expr {( $tricks($contract) + 0x10000 ) % 0x10000} ] set results [list $contract] foreach hand {south west north east} { set tr [expr {15&$trickvalue}] ::deal::metadata gib.$hand.$contract { gib::rectify_tricks $hand $tr } set trickvalue [expr {$trickvalue/16}] } } } proc openlib {} { variable file set fh [open $file r] fconfigure $fh -translation binary return $fh } proc initialize {{filename unset}} { variable filehandle variable trial if {"$filehandle"!=""} { finalize } if {"$filename"!="unset"} { variable file set file $filename } set filehandle [openlib] set trial 0 } proc get_next_deal {} { variable trial set data [readNextData] if {[string length $data]!=26} { return 0 } parseData $data incr trial } proc finalize {} { variable filehandle close $filehandle set filehandle {} } proc stackhand {name hand} { error "Can't stack hands when reading deals from files" } proc stackcards {name args} { error "Can't stack cards when reading deals from files" } namespace export get_next_deal initialize finalize } set deal::tricksCmd ::gib::tricksCmd set deal::tricksCache gib #gib::directory "c:/games/gib" deal319/lib/evaluators.tcl0000644000175200017520000001155511063454127013741 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: evaluators.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # A set of routines to compute (quickly) the "offensive potential" # of a hand. # # uses new 'holdingProc' declaration # set Losers(0) 0 set Losers(1) 1 set Losers(2) 2 set Losers(3) 3 set Losers(4) 4 set Losers(5) 4 set Losers(6) 3 set Losers(7) 3 set Losers(8) 2 set Losers(9) 2 set Losers(10) 2 set Losers(11) 1 set Losers(12) 1 set Losers(13) 0 # # This returns 2X the number of expected defensive tricks # from a suit. This is a crude estimate. # holdingProc -double defense {len A K Q J} { set defense 0 if {$A} { incr defense 2 } if {$K && $len < 7} { incr defense 2 } if {$K && ($len==7)} { incr defense 1 } if {$Q && $len < 6} { if {$A||$K} { incr defense 2 } else { incr defense 1 } } if {$Q && $len==6} { if {$A||$K} { incr defense 1 } } if {$len<=4 && $A && $K && !$Q && $J} { incr defense 1; } return [expr $defense/2.0] } holdingProc offense {len A K Q J T x9 x8} { global Losers set baselose $Losers($len) if {$baselose == 0} { return $len } if {$baselose == 1} { return [expr $len+$A] } if {$baselose == 2} { if {$A && $K} { return $len; } if {$A || ($K && $Q)} { return [expr $len-1] } return [expr $len-2] } if {$baselose == 3} { if {$A&&$K&&$Q} { return $len } if {($A&&$K)||(($A||$K)&&$Q&&$J)} { return [expr $len-1] } if {$A||($K&&$Q)} { return [expr $len-2] } if {($Q||$K)&&$J&&($T||$x9)} { return [expr $len-2] } return [expr $len-3] } if {$A&&$K&&$Q&&($J||$T)} { return $len } if {3*($A+$K+$Q+$J)+$T+$x9>=10} { return [expr $len-1] } if {4*($A+$K+$Q+$J)+$T+$x9+$x8>=10} { return [expr $len-2]} if {20*$A+12*$K+12*$Q+6*$J+2*$T+$x9+$x8>20} { return [expr $len-3]} return [expr $len-4] } holdingProc -double OP {len A K Q J T x9 x8} { set defense [defense $len $A $K $Q $J] set offense [offense $len $A $K $Q $J $T $x9 $x8] return [expr $offense-2*$defense] } holdingProc Controls {A K} {expr {$A*2+$K}} holdingProc HCP {A K Q J} {expr {$A*4+$K*3+$Q*2+$J}} holdingProc HC321 {A K Q} {expr {$A*3+$K*2+$Q}} # # I've modeled this Tcl code against Danil Suits implementation # of 'quality' and 'CCCC' from 'dealer.' # shapefunc CCCC.shapepoints { set pts 0 # Add one point per singleton, two per doubleton, three per void foreach len [list $s $h $d $c] { if {$len<=2} { incr pts [expr {(3-$len)*100}] } } if {$pts==0} { # If flat, return -1/2. return -50 } # Ignore first doubleton. expr {$pts-100} } holdingProc Quality {len A K Q J T x9 x8} { set SuitFactor [expr {10*$len}] set Quality [expr {$SuitFactor*[HCP $A $K $Q $J]}] set HigherHonors [expr {$A+$K+$Q+$J}] if {$len>6} { set ReplaceCount 3 if {$Q} { incr ReplaceCount -2 } if {$J} { incr ReplaceCount -1 } if {$ReplaceCount > ($len-6)} { set ReplaceCount [expr {$len-6}] } incr Quality [expr {$ReplaceCount*$SuitFactor}] } else { if {$T} { if {$HigherHonors>1 || $J} { incr Quality $SuitFactor } else { incr Quality [expr {$SuitFactor/2}] } } if {$x9} { if {$HigherHonors==2 || $T || $x8} { incr Quality [expr {$SuitFactor/2}] } } } return $Quality } holdingProc CCCC.holding {len A K Q J T x9 x8} { set HigherHonors 0 set eval 0 if {$A} { incr eval 300 incr HigherHonors } if {$K} { if {$len==1} { incr eval 50 } else { incr eval 200 } incr HigherHonors } if {$Q} { if {$len<=2} { if {$HigherHonors==1} { incr eval 50 } } else { if {$HigherHonors==0} { incr eval 75 } { incr eval 100 } } incr HigherHonors } if {$J} { if {$len>2} { if {$HigherHonors == 2} { incr eval 50 } if {$HigherHonors==1} { incr eval 25 } } incr HigherHonors } if {$T} { if {$HigherHonors==2 || ($HigherHonors==1 && $x9)} { incr eval 25 } } incr eval [Quality $len $A $K $Q $J $T $x9 $x8] return $eval } proc CCCC {hand} { set p [CCCC.holding $hand] set dist [CCCC.shapepoints $hand] expr {$p+$dist} } deal319/html/0000755000175200017520000000000011341325567011243 5ustar cbecbedeal319/html/advanced.html0000644000175200017520000004630211341325566013702 0ustar cbecbe Deal - An Advanced User Guide
Plane Dealing image

Deal 3.1

An Advanced User Guide

Covering:
  • Vector additive functions
  • Shape functions
  • Pattern functions
  • Customizable output formats
  • Statistical analysis
  • Hints for fast scripts

Prologue

First things first, you will need to download Deal and build it. The rest of this guide assumes you have already done this.

This guide also assumes you know everything in the Introductory Tutorial. Some sections in this guide will require more knowledge of Tcl than others.

**Warning** It takes careful eyes, at least on the version of Netscape I am using, to distinguish between normal parentheses, (), and curly parentheses, {}. Almost all of the parentheses in the script listings below are curly parentheses.


Contents

Vector additive functions

In the Introductory Tutorial, we mentioned three functions which we called "additive functions." They were hcp, controls, and losers. We called them additive because we could compute them for a single suit holding in a hand or across the entire hand by summing over all the suits.

In this section, we will show how a user can create a large class of fast additive functions, and show how they can be used.

The most common additive function is hcp. How is it computed? Given a suit holding, we count 4 for the ace, 3 for the king, 2 for the queen, and 1 for the jack. Here is how we would define this with a "vector":

defvector Hcp 4 3 2 1
That's pretty simply. Similarly, we can define a Controls vector:
defvector Controls 2 1

Once these vectors are defined, we can use them as functions anywhere we used hcp and controls.

Now, considering the following case: Your partner, north, opens a weak two spades, and you have the agreement that partner always has a 6-card suit with at least two of the top three honors. You can define a vector:

defvector Top3 1 1 1
Now, to test the quality of the spade suit, you could say:
if {[Top3 north spades]>=2} { ... }
Pretty simple.

So you decide to write a "weak2" procedure:

defvector Top3 1 1 1

proc weak2 {hand suit} {
  if {[$suit $hand]==6 && [Top3 $hand $suit]>=2} { return 1 }
  return 0
}
You can call this by saying:
#... 
main {
	if {[weak2 north spades]} { accept }
}
This will deal out hands where north has exactly six spades and two of the top three spades.

This works okay (although you have forgotten to restrict the other suit lengths, so you could end up with voids and side 5-card or 6-card suits.)

Two weeks later, you and your partner decide that you will also consider a suit worth a weak 2 if it contains three of the top five cards, which, specifically, really means you've now allowed suits led by QJT, KJT, and AJT. This is not an uncommon agreement.

We could, of course, write a routine called "Top5" and check both Top3 and Top5, but a little cleverness allows us to roll this all up into one vector.

defvector weak2quality 2 2 2 1 1
You will see, if you think about it, that this vector evaluates to 4 or more precisely when the suit has the right quality for a weak two. You then rewrite the weak2 function:

defvector weak2quality 2 2 2 1 1

proc weak2 {hand suit} {
  if {[$suit $hand]==6 && [weak2quality $hand $suit]>=4} { return 1 }
  return 0
}
The advantage of the vector functions is that they can be computed quickly, using table lookups.

However, vectors don't compute many additive functions, like "losers" and "quick tricks," or even high card points with distribution adjustments. For this, you will need to use the Deal 3.1 feature, holding functions. It pretty much covers *all* such procedures, but still allows for a fast lookup.

Shape functions and classes

In the Introductory Tutorial, we mentioned the two functions, balanced, and semi_balance, and called them "shape functions" because they take a hand name as an argument, the return value depends only on the "shape" of the hand - that is, on how many cards are in each suit.

In fact, balanced and semi_balanced are a special sort of shape function, which we will call a "shape class." A "shape class" is a shape function which returns only the values 0 and 1, and therefore defines a class of shapes, namely those shapes which evaluate as 1.

Deal allows for extremely fast shape class and shape function computations.

A basic shape class

For example, lets say that we want to write a shapeclass which returns 1 if our hand is right shape for a one spade opening. We would do so with the following definition:
shapeclass spadeshape {
    if {$s>=5 && $s>=$h && $s>=$d && $s>=$c} { return 1}
    return 0
}
This defines a routine, spadeshape, which returns true precisely when the hand has 5 or more spades and at least as many spades as any other suit.

Notice, the variables $s, $h, $d, and $c. Consider it this way - when you pass a hand name to a shape function, it sets these variables to the suit lengths, and then evaluates the code. [ That is not how it works in reality, because that would be too slow. ]

The idiom, if {expr} {return 1} return 0 is so common in shape classes, Deal has a shorthand, shapecond, and we could have defined spadeshape as:

shapecond spadeshape {$s>=5 && $s>=$h && $s>=$d && $s>=$c}

A sample shape function

Shape functions can return any string. They can be extremely powerful.

For example, we can define a function, opening_suit:

shapefunc opening_suit {
	if {$c>$s && $c>$h && $c>$d} { return clubs }
	if {$d>$s && $d>$h && $d>$c} { return diamonds }
	if {$s>=5 && $s>=$h} { return spades }
	if {$h>=5} { return hearts }
	if {$d>=5 && $d>=$c} { return diamonds }
	if {$d>$c} { return diamonds }
	return clubs
}
This function returns the name of the suit in which you should open open the hand (at least according to some people) in Standard American bidding.

Recently, a number of people have mentioned to me Bergen's "rule of 20" for determining whether a hand is worth an opening bid. According to the rule, add your high card points to the sum of the lengths of your longest two suits. If that adds up to 20, open the hand. We can write this as follows:

shapefunc bergen::shapeval {
    set p [lsort -integer -decreasing "$s $h $d $c"]
    set first [lindex "$p" 0]
    set second [lindex "$p" 1]
    expr $first+$second
}

proc bergen::opening {hand} {
    expr { [hcp $hand] + [bergen::shapeval $hand] >= 20}
}
We can now use Bergen's rule in our simulations.

Calling shape functions explicitly

A shape function (or shape class) can be called with 4 numeric arguments:
set open3343 [openingsuit eval 3 3 4 3]
This is most useful in defining shape classes and functions from other shape classes and functions. Assume you have shape classes spadeshape and heartshape and you want to define a new shape class, majorshape. You can do so as follows:
shapecond majorshape \
	{[spadeshape eval $s $h $d $c] || [heartshape eval $s $h $d $c]}

Pattern functions and classes

In Deal 3.1.8, you have access to pattern functions and classes, as well as shape functions and classes.

The pattern of a hand is the lengths of the suits in the hand, sorted in descending order.

You could define the pattern class, "balanced," as:

patterncond balanced {$l1>3 && $l2>=3 && $l3>=3 && $l4>=2}

The variables l1, l2, l3, and l4 are set to the lengths of the suits, l1 being the longest, l4 the shortest.

[For clarification, the first characters of each of those variables is the lowercase letter L.]

There are similar patternfunc and patternclass functions.

The pattern functions are implemented as shape functions. Note that this means you can call it with:

balanced eval 4 2 4 3

and it runs properly and returns 1 (true.)

Customizable output formats

With verson 2.0 of Deal, it is finally possible to write your own customizable format routines.

It is really fairly simple. When Deal accepts a hand, it calls the procedure named write_deal. When it is finished dealing the number of hands requested, it calls a procedure named flush_deal.

To change the output format, we simply redefine these procedures. Tcl does not mind such redefinitions.

For example, the formatter, format/none, is just the code:

proc write_deal {} {
	# empty function
}
By default, the flush_deal procedure is already empty, so we do not have to redefine it here.

Why might we need flush_deal at all? Some formatters only write to output periodically. For example, format/practice writes files out.north, out.east, out.south, and out.west. The output in out.north looks like:

                              north hands
============================================================================
     *1*                 *2*                 *3*                 *4*
  S 84                S T7                S QT3               S AJ9654
  H J8642             H Q65               H Q983              H K8
  D Q843              D KJ42              D 865               D J
  C 73                C T842              C AJ9               C K532

=============================================================================
Clearly, therefore, write_deal is buffering output internally and only printing every fourth hand. What happens when the user requests 10 deals? write_deal will be called on the tenth deal, but because the deal number is not a multiple of four, write_deal will not know to print the output. The last two hands will be lost.

The solution is to make Deal call flush_deal on completion of dealing.

A most basic formatter - printing one hand

Here is a new formatter, which we will place in a file call NorthFmt.
proc write_deal {} {
	puts "S: [north -void --- spades]"
	puts "H: [north -void --- hearts]"
	puts "D: [north -void --- diamonds]"
	puts "C: [north -void --- clubs]"
	puts "============================="
}
Okay, what does this expression, [north -void --- spades], do? The expression [north spades] returns the spade holding of the north hand in a simple string form. If the suit is void, it returns the empty string. The "-void ---" in the example above tells the formatter to use the string "---" for voids.

We could do this a little more easily:

proc write_deal {} {
    foreach char {S H D C} suit {spades hearts diamonds clubs} {
	puts "$char: [north -void --- $suit]"
    }
    puts "============================="
}
This uses the interesting feature of the Tcl foreach which lets two variables move through two lists.

The north routine, without arguments, returns all four suits, in a Tcl list format. Here is a simple formatter for the north and south hands:

proc write_deal {} {
    puts "{[north]} {[south]}"
}
Yielding ugly output like:
{{J9654} {KQT832} {} {42}} {{7} {A74} {T763} {J9865}}
{{KT852} {Q} {KT83} {A83}} {{96} {AK7543} {Q96} {52}}
Not pretty, but useful if piping to another Tcl program, because Tcl programs will find this fairly easy to parse.

String boxes

For more complicated formats, I have added to Tcl an invention of my own for string "drawings." Tcl does not have any decent formatting routines, other than the format command, which is based on the printf class of functions in C. I've always found printf a pain, even back in Fortran.

So I invented "string boxes." A string box is a like a drawable canvas, but for characters rather than pixels. For example, here is a slightly simpler version of the file format/okb:

stringbox okbox 14 70
okbox write 4 15 "West"
okbox write 4 50 "East"
okbox write 0 30 "North"
okbox write 10 30 "South"
	...
This code creates a string box named okbox with 14 rows of 70 columns of text (initially all blank), and then writes the words "West", "East", "North", and "South" in different locations in that box.

Next we define the sub-boxes, one for each hand:

	...
okbox subbox okbox.north 0 36 4 15
okbox subbox okbox.south 10 36 4 15
okbox subbox okbox.east 5 50 4 15
okbox subbox okbox.west 5 15 4 15
	...
A "subbox" is created from a parent box, and has both a row and column location, and a row and column width. In the above instance, all of our sub-boxes are 4 rows and 15 columns, and placed in the location where the hands will eventually be printed.

Our write_deal procedure would look like:

proc write_deal {} {
  foreach hand {west south north east} {
    okputhand $hand
  }

  puts "[okbox]"
  puts "                       -----------------------------"
}

proc okputhand {hand} {

  okbox.$hand clear

  set rowhand 0
  foreach char {S H D C} suit {spades hearts diamonds clubs} {
    okbox.$hand write $rowhand 0 "$char [$hand -void --- $suit]"
    incr rowhand
  }
}
write_deal just calls the routine okputhand for each hand, then writes out the contents of the entire string box, okbox, followed by the seperator string of hyphens. Note that we convert a string box to a normal string just by using its name alone, without arguments, as in [okbox]. We can also convert a string with trailing whitespace removed from lines, by saying [okbox compact]. In fact, we probably should have used the compact modifier, since there is so much trailing white space in this format.

The okputhand procedure first clears the sub-box associated that hand, then writes out the contents of the hand one suit at a time to that same sub-box.

The output looks like:

                              North S KT6                             
                                    H J97                             
                                    D T8543                           
                                    C T5                              
               West                               East                
               S J75                              S Q983              
               H T86                              H A52               
               D AKJ7                             D Q9                
               C AQ8                              C KJ64              
                                                                      
                              South S A42                             
                                    H KQ43                            
                                    D 62                              
                                    C 9732                            
-----------------------------
I have yet to put together complete documentation for string boxes, but I intend to do so. They have some remarkable features, and perhaps some surprises for the unwary.

Statistical analysis

Go here.

Hints for fast scripts

Documentation not yet written.
Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

Plane Dealing graphic above created using POV-Ray.

deal319/html/statistics.html0000644000175200017520000000600511341325567014324 0ustar cbecbe Statistics in Deal and iDeal

Statistics in Deal

One can, of course, implement statistical functions in pure Tcl, but the number crunching of Tcl is not particularly fast, so I've implemented two methods in C which do some rudimentary statistics.

The two procedures are sdev and correlate.

The sdev declaration

The call:
sdev fitstats
defines a new procedure, fitstats, which is used to accumulate data. After it is defined, we can add data to it:
fitstats add 4
fitstats add 5
fitstats add 6
Then we can dump the data with:
set average [fitstats average]
set deviation [fitstats sdev]
In Deal 3.1 you might write:
# Determine the avearge spade length of north if south has
# five spades.

#
# Use "format/none" because we are not interested in specific
# deals.
#
source format/none

#
# Declare the statistical collector
#
sdev fitstats

main {
  reject unless {[spades south]==5}

  fitstats add [spades north]

  accept
}
     
deal_finished {
  puts "Count=[fitstats count]"
  puts "Average=[fitstats average]"
  puts "Deviation=[fitstats sdev]"
}
The code in deal_finished is executed once, after the appropriate set of deals are generated. Saving this code to the file "fit.tcl" we can run it:
\deal30> deal -i fit.tcl 100000
Count=100000
Average=2.67254
Deviation=1.20679325006

The correlation declaration

The correlation declaration defines a routine much like the sdev correlation. It computes the linear correlation between two data bits. In tclsh, with iDeal:
% correlation baz
% baz add 10 20
% baz add 20 30
% baz add 30 40
% baz add 40 50
% baz correlate
1.0
%

Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

Plane Dealing graphic above created using POV-Ray.

deal319/html/commtop.html0000644000175200017520000000060711341325566013611 0ustar cbecbe Index of Deal Commands deal319/html/version.js0000644000175200017520000000170711341325567013273 0ustar cbecbecurrentDealVersion = "3.1.9"; function noteOldVersion(version) { if (version != currentDealVersion) { element = document.getElementById("versionWarning"); if (element != null) { element.innerHTML = "This is not the current version of Deal. " + "The current version of Deal is " + currentDealVersion + " which can be found at " + "the main Deal site."; element.style.display = "block"; } } } function noteOldVersion(version) { if (version != currentDealVersion) { element = document.getElementByID("versionWarning"); if (element != null) { element.innerHTML = "This is not the current version of Deal. The current version of Deal is Deal " + currentDealVersion + " which can be found at the make Deal site."; } } } deal319/html/graphics/0000755000175200017520000000000011341325566013042 5ustar cbecbedeal319/html/graphics/falling_small.jpg0000644000175200017520000007504211341325566016360 0ustar cbecbeÿØÿàJFIFHHÿí)TPhotoshop 3.08BIMíHH8BIMó8BIM 8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIMøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM@@8BIM 'ä€z€·'ÈÿØÿàJFIFHHÿþ'File written by Adobe Photoshop¨ 4.0ÿîAdobed€ÿÛ„            ÿÀz€"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?ôgtœqÓ¯ÁÆsñ}zÝYÈ¨íµ¥À·Öm¿KÕdû0þ©ÿ5º×KéÙØ¶u së§ÝoÔ‡:×»Ðý&›ý7¿Ñ¥Ù·©’ʪõ}³+?]ú'ÖLæÑŸõo2ì|Üq´ÐËÍuØ×=žçRÿÕßéµÖXýÿ˜ÏOô¿£]6F..O§öšk»Ñ±·Sê4?eŒþnê÷ƒ²ÚçÙcQZãgô|\\´bcÅ™5înãô7zT¶±ìª¦ïµþÆ,«z–Îý›‚ÌŒî¢FüGŠßíý/«iôj®¶¿ßeõYùŸé}j¯®T_ŸÕºGQÁ»à1î6±í±–Ô^Üj};麼œ§Yúð_Ñ©bõŽ“ÒNUX¸v7¹Uá×epë2rÝú;±éªÂÏføKì·Óþ{é¿ùÉ1òùraF×þ/ýúx€ß_«#^ÞŸ]dæ×KnÉ5{¨£yž7¨v9–]üíUú^ú¿Iú*Ðú®C^M5‡¿ `½­4îg«½ûß wý§g§mO³{ÿBúÿ£ú·:ngKÊ»7öxi}7šó,c C®k[»u»ZÛì­»Xÿw±qÝIù–ýv°ã]ö[µÕUîíh­Œ°:¹ý%V;éýý†`#!B„x„þn.”¿ÂýâFFêÕF£'íÌÉ©ã"º˜cõºë\*§}[ê½ßgþ›“üß§Uý%u+s—ô·f4 bÀÊ%ÍÜ õë¡À~•š¾ºýŸÈZ}S§Qƒê‘•mvõnKA65s\ú§gØ\ÿUìµøÿéÒþ‘C ‘öz,«1 0·Óc=0]•:ÂݾÆ7Ôþ§«ü穽št]ÆI'Q^‘·ò“SêïÔª«ÛÔúÓ@ÛúJ°ìÛ¶°ú™˜ç·ýóu„õ?ÀëGÖ¼»,~ VS‡Q-Éɶ§Píwè™ê5¾…-šÞËÞË>Ñþ‹ìŸ¤ÉÚëLËê 3ßC>¦:·‚ó[Yi ôòžúÚë6×ý"¯Ìüÿç*«gÕrì~Kr3…UgeRß¶YUÞ£‘ŽÍ6:¿Õ¿MŒÆ}Y”ÿ1¿ÕõñDE^…‡˜Ë#ÂLÄ.@ +æ”Gîÿ}ôOª÷áäôz¯Â?¢¸¹îÜíï?ßwÚ_?Ò½G~±·Ù]¿¢¯è(ãýbÄÉÁfQq¯_NêYî°ZçSù¬­»HË]üí_è×õ'4õ,lO^Újm§)´¹àUcn®ÚòiÛYw­evú Üïcý[Â#Ó™n[ØãU¯°Zé{Yc½îs=Ì©ý'üGýu7&’;ÕõeåñŒ5V+‡„ÜtýÅWõÓäåbÖü¶:Êñi¢Ç?Ùê×NCÜçÒë}Þ¦ý›îÿµ?¦V0úÖÍ¿ôW}«­{°Ÿú+.eNªÝÞÆ>Úþ‡½£tÆàcÕMÖfTíöÕ{È%Áî%á­g¶¿Mû˜ú?ÁX´E"纣¥µY@yäooµ»¾—ó¬«Úš˜ðƒR\쿬.¶Ù~5¶6ÜæŒ‹›¯¥»¶ûIêlToêÙÄÕ~M—±æ K‹DþmlÓô¿›ÿ ²ú¥Žeõœa´¹¡Òvîn»¬Ý¿õø#30[{®uGòа6îfž®ÇFÿðŸñ^Ê“l·Ä1Ž•£ÿÐôL~£ÓiËgCûX³>Šó]Ž›\ÏæÙcß¶Zý›¬ÿ þü"Ç·¦ýh£ë®>n6U¶ô,½ÿmÇus*ÙNÚ}:mk]O­‘·ú6ÿøgþ‘®ô>‡O\Æú×~vV5û«ÒˆuN®¦º×ºæúV:¼fÑ[ìɱöz^Ÿü6ůgát쌬ÔW…‘]Ö·š×›é`kª¶–z÷;v×úfÏçmôŠ$ÐK{©bÒ^ÌǾ¼jñËm˽Ìi{ªÇß}U¬Ò¦«\ë·~gé}JË=UK¬t>¯wNµõ9™ÙÝoOe¬"æÒEnH}[þÉVUmý¶>¯[ü¹™‘„z;¯ëM®œK+oÚYiÝ[}M­½Ñî÷½¬þº«Õ~¬ãeÕœq­8Y=Bºè¿$ å¸õÀ~>;\æ³»kú{=Ÿá¬ ñÙ1†XDoçâáõOùÎ<ŸÔýWùV3vU‡^?J=/¤tvÒ̶Ël±Î/q­£èv};2-³ÔûE–zL®¯øµ“‘Õú5™_N—Ùd±Î¹þŸÔØÝž£þ›¾…ˆÿäþ™˜Û:]{TW‹SžÆQYÝèÑ õ®õßï¶ë¬³þéÚ¹ÌË)ÛKf“Cœ*¥Òá°Mµ†loé>›ìe[?Á7j‡™œe bLô&sŸÏ’r‘Ÿ¿­êálòØã"Dü)Ø¿ëVmŽ.SdAôÚ öøz—ïúû‹*ìë3^ÖäÛfH:¼:ÍÛ\e³éÎÆ3üó~Ÿ«üç½Tìݓ²ÆY`Ù¼8 ±-m¦ûÞÏÑz¾“ßüÝVY‘³ô6×J±…†ã‘[În@’Â[C6¶û²éìel?N¼|/çíý-–(5opc…ÐÕ½wE§˜ç® ͽô²œÁ»ìÓNûûÍk7×þþ¸¹î¹Ñ±ºV'RÅ®¶;§ç™Ó½&é9Ÿ§Ée—ûªn&+öåâc¶¿ÓzöQýí èËÇwC꘶kcß{=,{½;þÏ¢fÁú7\÷ß“êz–ÿƒYÕõÆYѯÂê[UXÇõfcAe¬q˜;cÝú·ú MyT~Žæ_K-OŒèÐîÐÉ„™¢Zi¯«²Oª7 l¿&Ó.¾±ìk×Ìm_¶·{}K7~›þ)gu“S2l­Àn ‡Fƒ¾Í–£û›ßîúš·õ{©aÝÕpk}gª ãŠElŸÑ×UÕYì}[]³Ôúu u ß¶fV64Œ«¶¶"l}–?ÞÛç¿ô¿M¾ÄÙñlr°0™V‹ôÞ¡·{/±ìkÎçXÀàæ9°Ï´6v»vÍŸhgølðž½.“%Ù\÷W_«u/0»l–þÿÕ\uWz¶;ôŸZ·7qkw4{ìÙ.ôsžÛ­ý/Óý±t_Z:“i¨à.ÍmndvšÚmpoç~æÏÏH+š‡ª47¶§Qèøùw‹éËc±^ú@µ–9ÛXmèÚÿúßòèè¸î-5§P×ädc?žö5ÔÒ…“‹ˆÎ™„üꀲ¡]¸ØÖîkC£úFU.úTÖãúµVÿ=‘ÿUêŽFOVÉÈko{¬c¿›¥º}#°:¦þ÷±µobV!&ML¸b6ñ§ÿÑìñéÂ~=™™¸õdŽ—9Þ£X][ƒM®uÝ §Ý[]ôÿœý"n›õË¥u:±ZÚìn^]‚“„ðßQ„‡=ÖY½Íý_eo¨ßç?Ñoõ6,Rî“Ðóz‹žlµòk6¼¿ÐÒײk¥¿¦wº¼N¿ëÿ:¡Óúõ•щOí pÌFÊÉ–?ǵ¬õ}'¿Ñ¢ï³z•¿ùßAþº’5Àb ‰Òf\?à~Œ?ÂO·#0 ˆÓOÍ¿Ö0:~Uý>ìûF.G©Š ºý§ÑÜÂ7Øú=ö×¶Æ3ùÏ_ô+?ëGPê¶ôü{q߈è̪·¹Î—¹þ›+»ÒTÏæ®ýø/Yj¾Þ““Õp7âY“—K‰fU€5Ô=ì/Ûc^êŸîoø*ëôëµsøutLŒÎ©•Ð+°ÔËZÜ×ísY¹ÛŽúãîc_êz®ôª±ŸË«ôÊj2ÂI˜Å•í`–L¼>¾~ŸøüêØÆ‡Í-9­ê&æ3e’jÑѵç±Þ÷þßú'úŸôÖ^WOvFMêÚ˜ÐÌ«œ u&*}›œû¹ž“+ý#íÿƒõ}= 2:JÛIq/­›ZÖ4 ?Òǧü6eÿOkìÿ…Ⱥ¿ð€ÈÆËêb›:TØI§ Î/yã}lkXÛ_ó¶¿þÛô•Mü[X´•“Á ìüßF­4]Õ^Ì𨭝³Ôiæ??+#è;lY^Í¿«ÿ5_óŸ¤è_ÑúF¡ö’0Ä7!ØÕo}– m÷µ¶ÒÊënßKoÓý/ÓU0,oO½˜"–[ ™ ¸žX&»îcK¿@ë]^5X¿ÍÕ¿ÔõnUªêB¬‹nmÍe××Q¥®Ý«·ãÜñ[ÿœØÏä$Ë)JgÑ!Eþ—÷›E(b[‰€ÖU~c VdZãq-–:ÊZçWê9Õþ‘Ôûÿ¹¼ÞÕ:c¾Õs l1éäµÁõAÿëUô}ÿàò}[£öW­öËë8ÖWîsª›q‰`uýç¿ݳú;½ôŠð²¬š齯e ’'ÚO‹ƒ}½Ò«b3”73rGÚl©ì¢Mµ±ÆÝY1oº¿S¦zgóöúÖÿ5éì\ózžGPÌß~Cìnýøì{˃—²§TDͲÖz¢ºÿÂzõ-Ÿ«ÙeæcÎõ š´šõjt唣Ò@‡èý_ÿÒë~³ºÊ:vNnÇ9Ñê¹Àmö·c_±ÞßvKØåËY‘MmØ^ÖV÷G-ÔoÝ~׿ÛVßçlþsýÎl}d±¹fÀAuxíOæ‚ßÒ¸û½Ÿ£y©ùëžÈ´ÚXZj7<²¦:Ò[}F¾ýÍcÚæ>ÇÕ]5cz¿£÷¦Ý^ƒÛˆý]Ülº²,mLz—4zTçÒ]ëTÒàöcÙ¸1ù¬¥ÿ¥÷oº¯}µzŸÏ­¶e×Qº¬jl·;ùþ¡ eÁ ²«¬iÝo¹ÿ¡³ù¿Òl\>.s u{€$Sú0ͬ¥ÖY[V}«} 2XÊýø¥©Òú®NŸf#å»Ç©‹fçwkMLþnúØ}›?IúðéÃ$ª¬Ñ¿O™7*±ýÓ»£fäۂǵïvÛžCX6Ÿw©½ás?Òúvoþmš±},WŒšðe¾¡s^æîö×6Æ¿³þ WúÑ‘“Ò[Ôê·!ØYº‹èqÖ¿¤Ó[kc}Š.±¾•y>ŸªÊÿã?E‘Ðío«f;,u#&£éXØ;^ѻԯsvîØï¢ô×µ°Ëö÷ž€uëÄïQÓÄôi½¯ÍµÌe¯È!–_]zãÖ×´2—Ýê;ù[èQêÿ7ïË¿Ú-Üú ¶“¹ÔÛì06ƒ¸„fßô_õ»VŸjx4²£e­­m­ö´Xwl}•9—;ìï}mežŸ¨ÿO'þô†¢ã^%XV¸åPÓô­pºÚ§Üçãäd8[ìw²­ÛÿFŒ£vINß󭳘 «âó®m»Ÿ[Ú×za€—9 ´¿Ó®½Û¾—³ÿ>+XX9ô?–Òø{…ù o¹î3¶šYUr÷UK?žÝì®Ë?MgèÖó:Ž lº¬ +­Ø»›UíôŒ< ÿV†VÌÛ6¿ÜÏ´2škþsd×gÖ|‹ ÝBë 5Ææ« 쮺+ôšö7ví÷þbF"5vN‡ON’õ~’ùå9Šˆôµ2.¶ º…9½9ø£Ûsqßs-0àïJ¼–Ñê¹–ý7ÓU.õ7ÿ…ôýD³3²3l\í!Œh†ã²_ïwç{–v ê‹ªc÷XCÅmh&Á>óé5»ì¨÷·Ù¿ô«s åß¿õzü¶ì}ÿ·ÿm¥¾ÂšÄQ ôcЀwQ téYí:ƒ;¿Õ>­áuÍï¯ú=¬Ê¾·ŒÜœV>æcú¶ÔXÆÚÚÇó£eÍeÙ·mnN5­«ù»ÿGf'óÚx Ñ®ìc0ጽ[Pïýdý{ê¿@Âéê©8çìß}n>«Úãé¹—^íÏ{÷îY8öôü:êñv8Ék†÷ë±ß£s]“oükŸ] ²ëô?#¢æÕX.³Ñs« ç{©^ßåobò§“]À¼¼9޵ÞnsÉwý$ãk®$I¾ïÿÓ¶ü«_e–»c®u»ý-ÿžïk^ö¹ž—èý]ÿð–Áÿ=Ì–zöÚÇ4¼9¶8n­…¡ÌDzønæÓé:ʬÿºö¿Óþn¥vûcÎ`uR7‚á.°zmÓÛ²×Û«ôoøåÛRÛžÛ¬e6ZÛŸ‰cªu^‹´~–l·×c=Ko±¿ÎÐauàºx"}gí§#×cªaÛ‡·kË®–\Ì;ªýE;¿IKê3ÒZT1àY»c_ô/&H/­ŒmêÇ¿ôÔ¿ÔÿϪ½ù™y»$Ýx`t^Xm­Žm6}¥wè¯Ç{¿Moý©Åý-ÿ¥õ}K8ø¦¼65»Ü+ú@±Û·3Ô sî¿ùI*gAz¿ï޽Œ>£áÖû}i”Ç¿Ž{+°mÞç[ë6¶ìg¯ë~“ùÅÈâ产µá±e.k¬y¯³wòœßjê¾½×}¹½;¦ã‡¼ãÐç†0 žæQKžÿ Ïæ¬úKô7ÐÂìûYƒKµÁÞçŽÅŽs6±¾ôê7£F3ˆ‰2?12×ſԾ³ýŸ=Þ³e…à›ÛfØkšÛ1¯ú>ÖXÂÖÁX¯ÿ΋sÛŠÚF=9L±ÂÜ{…s’ÂÒÚœÛ=›mØûk¥ž¥ßéq¾‚亽ØÏɤâú–zE.²Ã±ï vààÍŽöV×mþkþ·ú47]"·Šg+aaÊ­Ïs›îÛ]Xô»mžÛ÷úTã[üÅÖ¾ßÐØ„á1ˆ"¨O_Òôzþ_ðdËMqŽ¿½ýx)½~>gQe_h°WmŽ,-e ;7CÖm·v÷ïoÐÿJ­¡ˆüZó þ•V€öØé˜pßÃÚ÷}äoY]C-Ø5b5­–íp.-wµµÿ7k~‹”±ìÀêV\fË2«mvoißî{éUú,‡1ÏöYCwþgój oJ=+o±° hKô]6cþÎÅvgI÷u †UêTÍÖz>•–ÙöAhôi¿sm±º¿CüÞ•_¥§+ëÖ®½nU}¥Rö;&¶7Ðù{‰wÓõÚûjÉôécªÌ»Öû=vý¢ÏÒz>²×éýu~‡HÎȱ”S’×1Ø×4î`­‡Ò±»eu»»%ž§©ïÿF±º÷[ºœ›z58moOé¶<Õ¿BÇzõ1³qÞkÿ%·6ª­ô¿š»ôûGæ^åraŒ`Nçœ8å(OÑüžÖYËü¬Ô±e"2›†üŠÅ{}L'1–fležƒ22¿AEY6Qrçºý´·ëKÆ5nF AÙW;ôÝFÛLÖæ}ššÙO¿ÐeŸ¤õÿEé¿b±_H»«7ÕÕ‹Ÿm<á›­s\.ÛÓ²]ú|w1¬¹Ö׋uoÇ«ùëY‡sÕ pñ0íÉéýUÍ¢ë¬qê Üß[Ü×åû,sòÿCUž¥U—däæäú_l¶Oìɸc3ê3–Lráý_õ}^¯Ñá—¡«›4ã„ #.û~²4÷'9éÇü±û[Û½®lÆàD0¼×¦tZÆÙ™g¬×´89ŸAû¿{vë~üZô’rúNQæüzm?Ûc_üVfOsC­kߺÂÌköpXÓùŒ{}LÆÓ½¾§£uj™ ØLÄH»ÿÔ•ìvF=dÙì± ˜—m!Îõ6<cßOøO´o¦Û1þÏúK=&*öãdX]¸Ûsiq}ÕS­¬½‚—PþwmŸO&­¾§¯úo~2éò±ú&FÙ}}/,‰¼‘Žâò[®ÇTê=[>¹žÿôª†WOËÃe4çW´1¬®»75ÐÇT×W“í³ÛéSwýu4‡GxËm<ÿGŠÀñSˆ-©“k nu×·Ñv½¬õÝê?Öö?ôT3ûk{¥Ô,êX¸û¸=ͶE¿¤g±ßE¾íÞÏø?ôy¯©®¹¯kÞçÔ\G©íÙìÚÚûm­žïUþ³géýMo}TÆ.ë sCMxì°ïåÆ@mm—{›±¶}øDìÓô“à].­k¿j^çm%Œc(Ü75®‚ÿT·Ü׺·Ùìk—4Xú³kuPÙo¬“QÑö:ÊÁ©Žý(ô·zoɱû¿âý5³Ÿ™‹Õ>ØÆÖö3Ö³ëÁk¶VêOÓký¿¤ÿÿ²›õ~Œz±ºŸPtàͧ¨e¹¯q7Øï±Ñ²§—lªÖú_hvÿÒÙë[zµËÄJã~©ÃÈÎ\:pñÿ‰_—/Ný£¥t\šëÊÇ­¥€Ý]­±Í`hšÞÿÒ?fßw§±êwôžêêUc;Õcšæ‚Ââ¿Ô¤ý+öÆ+}3+§»;§W~C,´ã`aµtÓŽî§fÐïÒ:».û=7»ô×ÿ„³+2ñ7·§^C›“é»k¡õÝ®o¦¶ØßY¿Aû?Â~–ºêG6,¸H‘âˆ?Í’Le—øÊ{ª€‰Ò#Ï„Œãu³öû©ÂÂkrr×Ùf×6+cvï}°¶š™þ’ë,«gÐõ?MéÚt¥Y—ÓëßÕ¿ Øàu>Æa×wæ·÷Ö†cp0+·j÷–ààw½…LûŸ‡kÿ{ôÙ?ð+9Ù–Ø,¡¿BÆl×A­Ï?è~ŽÆ{þU;ºñžZ®¿3ÝýQv0ºªsu•=¢ûx‡ìiÙºæµÎÿ¾}ÀýwËÊÆëùuT ¹VÞ4ie7>Ç{XwÚÞÿ³2ßSì÷z×ÿ;ö_Kªÿ¬xÀÏsµ.Ènç s…lÞæþòÂúÉ›‹õåÝD1ßduͨñ¾¦¹¸ÔµÎÇÆe»îÎÙE­gêþ§ú*îô«VyYÌ“û²ëÃü¥û®_7Š2•1Œ„Ï÷eü¿¸æåý_ê5¸ÓMÎÊêtí¥¹N.ªºÛGèmcÞòßRëó,¶ªlÈõëô}èßhÇW:{ºoéÿ·qÇJÅÉkon&êŬ²iêÏ—]Òð³?›Ùô2+þsô4Õ™“jÞ¹[1nn§U®q²œ¶Öè±ÖÖüWcìû&´1ùþÐþ£vÌÑU‰”„ϨÙw3/:Ç[^>C™ö¹¦¢)h²¼¶e×^FöbVÊkô1îg­úOSÑþrß*qHŸ½Ìòø£#6I|‘Œ?zþwäô“ÿ*³ˆ û²â¹GêÄ¿C‡ô#ú.ÛºÇ_ÂÏÃÆÁ¦ªúý ¬ŒµRö¾ë)¯ì–½ÌÝöJ)ôê¯ü%ŸÑìýµõ«‹ú®>N]v[…hnÆn`²÷5›¬·×£môªô¨ÿµ¢Púµun¢Ž•K¾ß[ks²æc )½™8˜}ï·sÛu~§­Oë¢õ,þz¼w—ë7'¬3íµ‹«c)6úm®úfE¦­õv2Ýì£ÓõvYþCžXÆ,Æ#ʡÒ_×ËêŸÏÅ“‡úŒœ<|Q;xú£ÿ9ÿÕì1þ°ô>ŸÓñªê™5Rëj¨?Ý#vêßíköQîgé¬ýòÕ~§Ôz—LÊÉ£*Þži¾Æ~ÎÁsƒeDZÛYe‘ê\ûþÍ[]êVÏç?ðµ•:§@é3Ü·1mkº~-7ŒgÛéÿ1êmwè÷·ùÖ²¿JÏÐÕ‘Zǧ+¬äÕ×:µ¨²Ðò*fÏUÑnMW:ý¾ó,²ïGùÏ̵hãÅËÇ—e~¨Ê2}Yx¿SìGùÏoÑúÜ¿õ6;ìlú«sö+jýn’f··s¾Nö9ûêÈúÅn>VY6ÒÒ ^…ƒÕcø½9>ûi¯ìþÿ³îüöz^šÍÒïfçICƒæãõù’tÛè4Ú+a°á³o¨Ïu–ºËÖýRËÙcšÍ¿èÿâÕîÔk= ñûC_´Pü½,¶zÕ}¦¦—>ÛqoÛU¶~zÆèý#5÷ŠñkÈ{ë¯vEÕ=¬ev[ë_W¢ÿN·3×fïSþkdYÒÛ’Ü–Òüüìzý7YŒà1ØÒí¹RæQC½]û쯻í¯ôŸ£­IŽF¨X6$$:pß¿£ó~óh€nÁíó¦¶3sèÀi¼³+ªÒ-³ô5û‹òßê_±”7u¾£Çé6·ó>‡¤ƒF-Ý3ÔÌÌ{™Ôòµ¤øÕ?ØlöÏ¥Ô2Ùì¯g¿ýª®tî¯ÔE/Ì4Õ‹€×4`UŽ÷<å¸u¶åÛéædbáý;ßú*²ÿ£ÿ7üî6U¹^£¢ÇÙaºÇ°jò?œ5Úê¿Gkµ¯ôLô=?æRÎeÆLË[­£ÅêáfäãÆ «†Ïéÿè(škË¥Åàèé¡‘ s«úXön«"š=»Ý_ïÿ1þhô>•vm¬¡­5Y`ÑÄéÒßð¯žýþÏøßøÏQQÀÆßpµŒ6< w:Ò=7zoqw«ÿÿüçéM}Oé}—ó}¥ôôW.ïçO<þw?4 1â÷:Îù[ý©ãu|gâu<–d_u©iØ×>–Vì±Ù_¦ÿRŸ_ùÊÝüºV+:v}A˜Ïê7ÓP.³Ð÷;ký[~Û‰‚-m¾«-·úMµþ›þÑ݉úªÃëò7OþkùìÏæ›útÿ5ÿ ÿ¢þ¯68ú-þÿüßòÓÿÀïV9owÕíðñWéÿÜqz}Ïåûë%íquâ£û¿-÷ýפ¿Ž¢çåý¿m§ÐǨWc+­­~ÆQ^êþ›lö;ô¥¶Ë¿Òzl½:ŸRºhãâØ/Þ×¹ßÍûEí±ÿé+©ìWò>ˆçžÜqùÿË@wÐwÀü8U´m~‡ ~ŽÉ1pjèNý¥Ö-©Ù †a4nm,{â‡Ü÷¾š½6n{ê?èzŸÎYe•ªK'"ñVN6ÛÜëKÜÚ'{l¶·5Ã÷½?ø6*ùòæGóÿÐÙý/ú?ÒÆþcþè ÿÍ‚Bþs#èÿJKùŸçô¿ôrw§‡Kâ³}«ôX²qû£Ž¶ݯêºqÝ¢[:ù=©çahcœ¶VMd{g]ï×s*sâß³ù¯zÁë_ò·Tþ—üØþcùßç(ÿ¿îŸýÎ^ƒýùÏèíçèñWó¿ð¿¹ÿ]NÍr±V]>fŽOÕ/ªíè]6ªr\Ëó^ãc74¼îý«üŸÏÚ·Ç)&wÑ?›‹ÝŸÏÅ.?ï_©]:Çê¹·æ×i.»ío{EGy-÷’Ó[_½Õ»ÓuMö}7ÿƒ[½Ù=E¿Ö­Ø YcK¶‡=Û›] ¨úvìuiÙùŸ«*™ŸB¿æÿ 7ùŸ§ô]ô¿á¿ï‹sêŸü‹ô¾ƒœþsè³ùßýÖÿº_fQ6'¶•Å]ÿÙ8BIMÿþ'File written by Adobe Photoshop¨ 4.0ÿîAdobed€ÿÛ„            ÿÀØá"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?ïz_ÕÜ\ Û-kl¼qØßê5dý}³ëf=xÙŸW ¤Ðëë­­±®úépõùûv.­ïem/±ÁŒn¥Î0Ì¥]•ÚÀúÜÃÚAælÝ”¼Í8=œüL®£œ1²¬,ôרÊëûMŒôò2}#úOé?E¿ÒÞ·:—N§¨ã†˜õî¢Îv’?ê^¸ßñ™õIýM£ªâã—ßCýW°Ëˆ¯ôŒc©ÿ »ÞÝíþm^ÿl½¿T«uÛý÷ZêËÉ2É nÝß™íKÅÕü^][.}öÜómÛ¢ˆìQ©¢ËÜ[_a%Çè7»óVçV鮼¶êkø²x#÷ÿ°¹o¬=rîŸGìì¶Àýl¨$þu›§è[Þˆ³ ßÅN¥];-˜öeáeRo©Å€^Ïh-põª—ŸÑïhújÈéte܇`û9þsiÜïÎeoÇ®w ýPê}VÁ›×í·ìÓ¹”=ľÉýÿôu;üõ³õŸ7&‘‹õ{£3ÒÈËÐ:±´WP?›·èÿ+ù ™d1þ—ðü™ùn^YòÇHÙ”¥òã„}Sœ¿»¤¦–QSj¬CX JÎêÔ¬ÞŸKm`5]ë¾’aÏcAnæŽêö;±±*Çu޹Õ05Ö<Ëœ@ÕÎrå¾³uŒJzí¹ VÊëe6E•½û¶=®iúûéþz8¸Œ¬oEŠ@@6/CÝÎú÷}¿µÁ6i¢¦·s@Ü\I~Úìù¬>ÌΩÖ1é.%›¹»‰¤ö9ÇÞç5ŸžºŸ¬=;*–Õ”ïò–=Ìcm°»xzßnË~—µPè½!®ne½9e†!Ì­Æ{œgs[é}?ó°Ï§ª#EpìIzöu­¯¦çÝfV+^Ça°Ñcv’ÚÄc\Ú§ßK·®cëE$:»Ù:û]ó÷k÷9tÙ9˜å?]SC32A1'üu-oú-fuŒ'fáš{ˆ Ý Ý>ÝÅ7 ÄÈWªÒñMÃɾöÑY²Ç¸6¶¶wIìØ^•õGêE ÌàÛs¹åµiÚ~ßðŸöÚÐúµõ[¡P úùŽeîÔø:§è±hfuÓc1h ·6ïæê&émwæÖßûrÏðiùs™zc·~êGÖ:Î'HÅ7ß6XA4ã×­–'mlÿ«æ.3 ¨¬yÛfÜfYXvYÙï­¡Û{csÚèÛ¿ß½Qê˜ùyg&Ž¥Ôhv}N5à×ìû6çÿ4ÚÝþûk%¶Û‡™Ns¶æ·—=¡Æ,iý ÷°}[[ô?Â,ÿ~œñÊâ#]%èIž‰áù޾¯O¯à×]xt×VïMŒ nðC i«]îj#o©×>€áê°9ö»è»þŠ«ÒòÛgJÄȱÚÝS fI24þS—3õ³?+¦}`ÇÍ oš=#^Ÿ¤—9ޖߥï•o?pÐ;‹‹ Ö›Ýa,ÇÄhëÐoþ”râz×Ö”z¦_@ȳ$Û|4e²Æís¡Ì~¬³mTçÅ©Ô:ÎFF-VbV­ˆfŽk£ßM¿èö®jš:UFüŠƒ,ήq™sLGÑ?EСԧ0¶ºp®É‘[vã²× Å£ùgný¿EZ®›,µ´´{Þ`§+;¢×Ԙחšì®Cm|U*.úÃÑ.a$ÝŒ×4“;Ú5÷:½ÞêÔ‚ «±SÜUU]9ÓwPe$jkiïaÿÈ,Þ¡Ö¾©d\q>Ùw%Á»AóÞõÎkâÖ[Å«¨äÖciy5û¯ý'ùÏõ>ŠÆûUmµÖ7uvíl8ƒ;Gµ›C7~÷ÕŒ|´Hâ⑱ÓÒ—¬»ë^N; }?Œ&$€8ýßnßÒ¬Ž¡Õz—Pa¯'&ǵþáXÒ Ç³ÓÛü¥‘vVYcCà1œ8wi;c{ýÛw¥E¦Ëv=¬s·iéî.‰|ûlgòÔÑÁ‹áš›_²ÿîÅyÿȤ§¶¿Ýü?óá ÿÐïþ´ô–uŽƒ—€æ½æÆnckpk‹˜w³iw³é7óý‹Ë~¤ãõ.—õï¥z—2¶—:êIsAa¨ÚÏZ¯¡íÜÍÿð‹Øpò©Ìħ*‡¶Ê¯c^ǰËHpŸiOö\_´ý¯ÑgÚKvzÛFý¿¹ê}=‰ ôRUŸÖº×Nè8;=Ƽv¹¬\w;赬jüëú·öçôóÔhnUn-}nxl8}&nt3wö•ޝÓêêý*ü9anC=ŽsEŒŸ¤Ç¦ÔÖè¿Zº^–tܦÛhnçÐà[`oêÞ<Ðòp:O®þ£Öªy±ãé ãÚÆlüçWþµË}Yú£Ÿõs3­e¹Ži!¸Ý>ÆA®Ç>ßvÏæýŸObè2¾«[™ƒ‹mín%/uÙt´A±Î%ÿI¿ÖØ£É#¨ˆ½<¶,G†y²{pâá48§ÁñχÿIÁØÆêxytæoôiÈKÖ†OÑl9ZÚ #ƒßUÊetܾ©õ€ÚN?Eé :–8 ¶Ž[›íÿ¶Ð:³>°ýa³¬½Ï«YŽÀKA?˜Í>—úK”bfÀ­Í§Ï&̹ |Ê2ˆÆýÜŸå=¹eÿsrÜCçÍ8ÿ9ûf¼“ënK®úËšâÐàéê±»­ R¼¿ªô‹íêfÊA-ÈyyqüÙ;œ ·Ë$Iìæ—_êž[¿È6ý† ©-°¸7èÖÆì÷6õz΃GÄyée«%Ľ·;kƒœ5vï{\õ{ê—«N+ðžYVµ¼ƒý6ƒýdn¯Ósº†@—2œj‡´¸É$ý'í JW2hn‡ÇÃÄÇÆ··oëžN®páã÷TñůӸ‡¹šþðì®ÕzÌ?«ø-ݼè6×âxúÐ,úËÐ0Þ+ÂÂ7<ÌXøÛ#Çv÷'pd™±|Rô=;í8þ›ÌÛV‡Ì~k—ŸŒC—Ó2:VN;,}¸WÙ}÷Çy>Ÿ¡u¶³èï¬YWò=õýÐu¯~/ìÞ³‹ŒHÊödÐÉêð>—î-î¢ëîéÿ´:c[vCk/ª·ÎÛXFçPñü¯Ìÿ…Q‘ÂuPióŽ©Ôqz Âêíkžr)ª»n±¡¤ßYv®‚ý»[îýó–,ŒÒqï“À×£Z'鱿Èó‹r§dýe¦é-©Æ¤EtºEuû?Á׻ع܌«’ß]¬½Ø§Ð±Ò].¨ìß^ÝÍwÒúj¬2d™™”/2ˆÓ…²= šÉºŸý‡ú.® »7§Q]y7Œ®™‘U˜ì­Ä5Ô¸Ë÷÷·èígòUõïÒgQƱ΂êN„OÝ—#õuï=K~3+k d9®;ÍvÈþs÷ÕÙ}{kfœÒð+tÇÆZ®òdqGC›ÒZòuþGêϪ×Tàr(± eTßÝâÚçè[JXÿV‡Mêvçý ÞËÁv3™£]S¸õ?}íX×XÖdàçÜ÷³ahhlvæÇ½ßGó—AÒºµ>›pòœß²\wWoƒˆ†;þ)ûvÜ­óoׯæµÓÇ£ø’‰ÈŽÅF«ñ±Þqó7Ñk#JØ×·]C›eŽ.s_þ“k¯Ü-sK‹¶˜ø*†$n7SC¯Òv&L‘êѰ>¹©Üý/nÅÆõ+UÅŒ.¤K@dµ»ÿw{}ë¸êÕ›z8{gv-Ý¿vÑÿm‹ˆêt¸e¹­svÄ öŸÃb·‚«ßmÆŽ§X²Œ€Ýö¸9—rZï§áô4fæ"QµÞâ\憘†´÷lÎíÿEUmØÁkd:~øøW;LjÞÿþÜú*Ov®Ô—íGùößûRFý›×?zßûtzI{ðí?ÿÑôÂþŸÓ1ª¬º¬Lfmª¦¸¶¶Í®¶nÚÕayÏøä«&Ü.œÚ«±õ6ËicKšÖ†9û~çmW?ÅŸÖ‡õZ²pòi»¬°ïÖ°ØôO¥gÓk}›ý;–™ZZœñ‘õ/!™cuwXÒöÐ ‰6ê>Ê}ÛÛZßu_OÖ^“ÐqìÅè?Ö천j˜öžCšÆ‡|DAऑ)hõ>˜:‰¢»l#·ú—P–íþmwú6¿ßü´õü6õ¶tV5Öd9»žæ k4ݶÏì­'‡–80€òÒuöÑr¸Ý©t>ŸÔß·u¬’à^»ZãôÚ×ÛPHl õ‘þ¬z7yhãË ³Ö?«åñ_¶=ìòþvsý̧þÒÓ™‰‘m´Ss,¶ƒ¶êÚA-?Ëjw5¸Øï8Ô‚ZæÔÀ¹ÜÇfûܹ ìGêóò¯‡u~ x:㯻ù4ý;?áUªïëô 6gÞ_™pö=¥ÎôáÖz´ûÞ絟÷ÄNãÕV«û¬³ø},y°œžÔ ·ÎqÇ‹6HFä±þó£Ò22±zUÝO¬änu®u¯`;›Kg`¢½›¾ç,ÌŸ®}%–>Ì\OVɾÀ$êØõ{' ÔýXýœÒÊòë£Õ}m$Vï`?Gs—aeu€Æ¹Ä´ï“©#Ý!ѵž×ìþ¿Éá„¡r²{[K™–l’ÃÄxx 8GËÃî½W×>¯q ¨WŽ4Ì÷sæíÎÿ ³oê9y@ºì‹,,’ïq< k}6Ÿú•쇖6¶´›,ÆU¬4™÷¾ßnç·èûUrëÓc É‚E/1 ÒZ6{^ÝÊôpÄlbtEµ²ãͬ“ËŸ_»g»üõ nh·Ñ± ¹¿M¥¦H?»ºûŠ®®·º§5ï{+ô8c‹‡.wò^ïÑîþm§6ëîf3œæÀÉ/xxœZá;*wù‰ä/ÁOoõM¸G§Ùw¸bÚ-hä>µ³xréiͼv€Êí‘[GÍíýµÉýYs±º©me¶ÛsH²š ìl´ï¾ÏæÙéÿÓV~»õª,ÁÅÇ;oµÛÅ€j Ž?uŸœõ›š7”ú^¥!ÏèµôŸ¬6õs±ºV}ovH¬ .»»èúÍ{¬ÿ·'Õú{º§Yµø£ìlö–"¶ˆ÷Ö#ôŽoùëÐVé=WêåÙy¯h¢‘úöïÙc¶ÁXüí¯bár±²rºÓ31Øüb82ê2 Þúß¶ÆÛc›íõv}*Á6 ë\}£üÝËgëÛM•ô×ÐÂ^^N§nÖ?Ûý ¬`–_ú+.öW’ÑT50Æ0}̱Çüä,{œß§k_µš«œgi÷;r–N5l{mm¦–0C»W»Ûé±±ú'9=Ø–Pʳ*hº‡×¶§0ËÚæŸ¢ý€¹®Ýô^ÿøµ§¥Ý/SÒrhêcáZñë44a_-ŸÒbݦ×7Û»jZfןåÊ¹ŽŒVv!¬ ´ä4¹Àè]ïãܺþªÍ™÷¤Ãæ7,þdT€QCKí9®ÉéÖP*ŸBǸ›[e{¶¬Ž£õY¸ùfœ‹÷Àk¶Ö {nrU˳#2¬j±Ô½¥Ãt:g–~ú/X»ª3~̤äeZðÀ¹Ãv›šÏÏQñJ"¡-iL±úWOÆþj–ƒÜO⬷Ü‹«¡—ý™–87p`$NʯFE]?¸ýVÓ“ŸX‹…P+ÝûŽÈú;™üßèØgÖG8µ¸A´4ñél&7E–Û/oöã‹,õ¯¬”ô?ó?ÿ-_þoþd’ä¿ç?Qÿ¹wÿœRR}Û/qö%ÿÒõí®ê…Œ!ÌxW-oSÄëxÙà7©×}Y¯kZˬªkÉý_¦g¥ÿ üç½ Ú¬e;)¦ÌL°Xö‰]ùÍÛîWú7ÕŽ•Ò²-ͤٓ—y%Ù9õúM­ÐÖ³t~“óíÿ›²œÏ©½+¨ýWé™UõܪÝP±¾…‚Ç9¡¢°Ý¶môþÐb.]Êë=xcÓ4àcc‡yÆz¿ð{»Óÿ·C~>>C=<Š™s9Úö‡¹ÈxøX¯u˜ô²§¼C‹H‰ÄFV.DPðJLŒŠq¨³"÷USKžãØ ,ì\üfeb?ԦϢá#"±>¶ôî­Õ~ÉÓñÜ+_9vέ£¹¿»ÿ£°8=•’*Ç¡›Z;ÑÿIʸ$ÈŠÐ~%³~f,v'OÝíÛi.yA¶»wôv·èSùŠï,‘öy)²1ð †ìû~ÑeƒsꨖQ¾?Ÿuƒß¿nÍì©¿õÅk§bæõ+]…‡Cqqéh6–•m?JÛ]üãöÿÂX©t>ƒ‘Õ]hut9£Ô¸’Æ —8ÿ'oÐ]&E99Xîéý ϰˆßk¥Ž¹ãÛ½ö»Û豿AŠ,’ðƒdu?&5 »«ãôö7¤;eT¹¦Ü˜ý&CÚwåzÚÿ õç&Ÿ[!®÷]FÚÈÐÃåÛÛý•:>£fZYf^C) €7ê5ßÚY]_ˆÛ0:~=®¹ØUšÍÆ=ÚµÍÀmömüÕ½³(ˆ›"øñ’ÿVz»º>kœðrz}ÍÛ–Æ ä͵Ôý?oýB­õ‡ë3³®8³ö7ØH°‚7kíçóVõ}I±ÌâÖûu6¹¿Ér?Ú걑{wºAõØwqîŸm®gï=?ÛYS£ÑzÖN.}n¨‡ÖÃ¥â[¨3Ïæí]×kkËé}>úõ®ÂeÐ>ˆqd~vÝ¿š¸ŒFË îqDÚÿ%ßCèþbêz#Ÿ•U3.¿_ a¶Ö“®=Þ½ü×6Q”LrÐÖ_ÝSËæz.­v°Û5 {šàçmýÖý6³zªÛ3ë@&¶9Ï--;\?9Ð=¿Mt=c¥[ŒæRøû3‰4ß^Õ}*à ÝôZÿOÞ°…²Ê›a{[at9ÄÀ7kjs‡Ð±¿ø"³ ÄÆÆ©ntÇ—S]vÀׂ É‚wOµñü•Ü}gÊf3•ÎúšæÉ'@¸| ¦‚­ohsHn¼lö‘ü¯¤»þ¥o@ûÝa¦ÇYC}:u‡@nºGç;÷Õ^h8èN§@§Ïº{¯Êê”èm²Ë7»`ݧ+¬ÌÉ=¡ÝdÁ¢§{w;÷n»ó•=s¦¿+˜t;ÛˆØÖ»ý!Ùþ¿ð‹ƒëî¿Öõ^ —MyúN×ÎÍþâñœ“¹F£) -e™Uút0Ý^×n%íHÐoÜw-U§Öä6¶¹Í¹º-t{ƒÓÜå`%Áº¨ê\Gç³÷ØÅ»Ñ:=¹¹táÔéÞÐë_Áô½ßÖÿ«Vå.u–Ÿìl?ôçï /Aÿ™÷íÿ· J¯ß#ûÒûÿÿÓêºwôê?®~½Ûe].£]–SúQ/a-o=W7ÝýMª‡AéO³«×fM×ä;Þãô)cvþ{½ßEm}aúÃ_Fv;_C²s¢Ö°9­˜köÿYŒd<å}½,¸2ËHåˆP<@KÕ¨pºwÖO¬ é`¿-Õ±Äg–5­é?×ÛëY_õWOÐŽIé¯ËsŸ}•‡½Î2eÞþa¿šQñ3ñ3±ý|w‹+pî?’æ}%[:ž¨0í Ç¥Þ›t²GælúT5G ®ýãê]9Ë œø7—Ì#ÃŽ7åGøÈú·Ö>žöc6ÌË\ʤ 16¿ó¹ï®ýW¦zT9‡+¨Z×=ĵ­­Þ×44{=ÿEty}7êý¹43*º>ÒÈôâÌ{¾Œî±SúÑõjž¯_¬DÛXú3¸ïÍrh]G‡þ„¾=’c“Q/wôD¸½1ö¸C÷žG¦×Kè¯,Rj±Í>Òâ@Ÿ Çó¶ªÝ &ÇåYMê\IsôZGç¹îú ZtⳑŠÀZÚÁl;‘ýdøÝ5ÕÐÊDQS]½íl<£êXåbF¦˜2KŠr š³Ã»ú,ŸG®÷zsö­uºG‹*»éújŽGNÈÍÃuv–Ò1žÝö@kxs\?=ÿºÏÏZg'ªí{lex¸îk,ºt÷ ý ?Ã=sýO©]Õ˜ê±É¢šˆ5é¤Iníúz—¹K‡¥.ÀU’±Qꔲ†àaY4µÛd€l··¯nßðß¹þ]èÝî²]{}:qÈqÉ1µ¬ó¿:ÍÑôå «/²Á•–>Ë@.u÷ÙíÐGótÒ\÷˜¶Yõ‹åWÒ¨gÙzq†ã’aÏvŸ¥·þ5ÊÄæ#ZÈ 2ýßý /A^IèøããÖl§p¯Ô 5®yJÇ»ú©º—Rë´ÓëãÕP¡ÀmÚ „Oü+³þ‚ÀúÛŸK²ÛƒKH£ »v"ÇF÷;úŸž³ú[ËéÛ§aƒè¹À°·ó·5ʸåå(‰þ‘Ö¤§['­“[Î÷¸´‘fE’u{iýÊ›ô=‹?Ün¦}ÕìL˜$ä³é+™C¡õÍ3šî™›;}z‰4¼ø9¨Ø½þ•7Ùé¿t×VENæ¸~wòœÔÓnĺ¾†¶gÔ|–ºþ•î ÷cdô…Ÿš¹OÙ–Y˜1ÏIÎdÒ¹ÏÜ=®áw ×Eeª3p–;dðLp?”Ë ê§‡oÕ«ëJö¼:ýûWMõs©®Æk˜÷¸aîZµ¾¡[?Z:¿ÕއCmêuµÖÙüÕ4]ü Ö–{–å¥Ñ¨é㙘,,fSÿ|îÁŽŸ£·ó“%šR©È=$Òü\º ¸o;ˆisþ’¿Þÿ„¯ü"äúŸKÈÅÙn °=£cÀ–XÆ™eÝû¬öý5èwuþÔ›Ò¯ÊeyÎg¨Ú\`–ëùÇÙù¿As]WªôœŒ²åK"͸Ö.e±ü÷ü]ŸákNÜÀëò¤MgÁã(º,w©YÇ `´¹Ùºljî.ç7¢tœ¬«0ñXã’óô¶]sþïfÅËätÛú~K±²>“k/ö>¾ë}ŸàýÛ¾šÝ9B¯©TdYŽ3=äÜý¡¿L—º¿dý ÊÞcÅÀcûÕ§õ‚œž¯™oSÊõ©¬>ÌVWôêmnßαߘš¾ƒuU‡æ ê© ¹¶e–VæƒîÓG[ôŠþ±e¿¦Þj±˜6b´0¸?ÞÍÖ3u›ÚÆ?w»óÖy˵×Zâ^n{‹ÞÑÛéÏï§DKäÒþSÓ=¶ÝmïÊyß³X¥·n³oò™Ré:>@Â¥ÙøµSq ¯kɱÐ%Ïvàïkw. "Û~ÌÊíðCHs@3îíù»WQЮ6ôúÁ:°m øiÑAÌ4$”;®ú+íßüÁ%]%V”ÿÿÔïþ¯Ó·öÀÇkúÅq¿\ó,¿¬8µ¿¡ÆE¤€¾‹›¯ï.ç§§tv LºŠ·XOïFçÒ^gmùWÜn°8µ—:¸C‹¶¸Ï³Ý¿ÞÅc”ªRí§Ú”Ý+/ªa]öœmÔÓIò ,Ûµ¶±®±îÙïÿ­.·§uÕ/uô;ì=Yì5—pÛò›ôls7ü%k‡.mOkä5y’â\ïÑ£íüæ¥Sr4ãVám†'sK€üËE?ÎW»é©òàŽMM6’c)FøIC„×XžŽþC]Õ›V}.7ÐöÜÇ?‹Lï¢ïÎþR·õ¾ž­Ô©§/ÏÈéÎqês_ùα÷Yÿ¢Ô:oÖJÝPÁëRÑ ½Ñ½±íÜ9ßÖbÚîΕg­CþÓÒïÕÏn¥ŸË1ÿMggåÍËKý(þ“g–ç%Ëå†HÄLc¡“ÕWÍÁþm‡ìVÝѱ­p}9TÒÒÿPËŒ Ùt~zæºÅÙDzµâ²{™?àÛ?Gùo].gÖe—bÕP²—Á`w26—ÿUe; *k°Cˆý¦ñô7ÿ!ßE~š¾iËŽr•W2ÿår±mºªÿi\+¢©ô±êÒ~Žï£¿÷Þ·ƒéÅéÂÎ[Cöû^}‡Ï{ÿïŠOè7eå:¦Öö±“ënk¡°eÌÝ;[µiñëŒV‘[IÚ'qûÿ9Oš€?M wbÛšvúߤ¹Íлé˜úJ§M¶«íÉʺ†×GOfàxyµÇf5nöî÷?ôžÔ\œJ²}2òCªvö¹¦ÁiåôœÌ®IéÁ–{nKHlÊý¿á]àÜ£Ç\U-ëi5@ƒ¯é™ÈË;^^Ám¯-$»Yséû›ís¹Ü«ÕÔks‹N+¨!ÛÄúz5§ôNÜˆ[cêµ¾‘¶Æ¸G:íhúM÷*¶›1,õ›Y64‡–´ývû}FûG½hF1­?:Cdõ™´>‚Ætɞηݷwö]ÕnÆÆ`ŵþƒœèº LíoÍRºÛÝû&Ǹæ‰ÜO¾–9¯ý¤Ö}ˆ9 yenio¦½=§wù_ÚBpˆŸsć¤ésí2dzk˜ œf[¾ïÍWY^C[f;Œ5Þ׉·Áræ«1ºk(ÆaûFYx’>ˆ1ûË[§;ìøl¤µÎ´“¥ª¥’1Çz ³·Ôú/OúåEUäÙöN­üÖS%ÌåÍs4ßûË®ÁÄ« ¬Z¾M‰ˆ’}Ï|-þõÁÙÒú¶AªêÆF(cƒcÛKwO³Ô¾Ïú†­ž¡Õ:Å#ìÙV,sHÊ„íŸÍõ#é(H½ˆ¯÷ÜŽ¯Ó±õ“#¨‡ £JfN×úwnwòÿ›ÙüÚ§Ôºm}B¦1ïuf³¹®o˜…q$HQL'(HJ&¤6.¥}¾£õ}µd¹ÆºÉ ³—W·MßË¡ßáëTêèù/ú¥Ôº]µ;Ö¦ácXÓí,ßSÿ>·µ¯Úºo«¢:U~nqÿ¤UÊèu6²;‡Ð<´ÿ#þ ߸ŒsJ>ž‚BCÎ(|.ómÎ;ZÑYè#„FãçÒæ[mf©Õ¹…¤‘ݯpôW­a}Kè8™–æz³ìy±Œ²ÊçXª¿£þrµõ“7¢äQÀêÃCÀð,!ÂçšB†è|Žûšê[é Öƒîkd“1Ý®åÐýYfMT¹—±ÍÜâæ—i2$ûSRp1n5M`˜'ƒ:ÿk²ºÞ«†ÚCh}Ll]ï=µîk^çU,²œ†±"ú•: ,ÏùÇÓ?|ýÅ%»?ÿÕíþ¹gý‹¢ØZ%öÐÑ© íý•çÞ¥¿h{] cœÚÁ‚=¶¹µ“±ÞÅÔ}zÎ'*¼ZË­º¹¢H.#s‡æýËß½˜e¥­ 5®Øí[",:>Ç~•þÏëÿ!^å£XÆšÉ-L°ïM¸Õ=×XæÖ  N×4z[7{Ûý´&Sm«Ù“K„êu»\ÎþÛÛíÜ‹uî¬e‡Ñ´G ½Ãs˜ªç1UcáãÚõä7KuÛ;?©»óÕ¡²¦½ñéîôÙºÛ E›NúÛ»ßþ}JïNëù½'-¢§ú”ZÀãô˜á;}]ÿàusxÙÕÓMt—XÇiv3I.=×VÓ»cšïÝö=[mÛ[²üê¬AÌwç7wÑÝÿŸrÆ ‚,>…ÓÙѺÐN8Ïv¶ã‘»þúŸ/;êÿJ/c«vMõjö\GÇvÖ®\qMø÷¿}“T6Øpý¿ØýöÒ®«¦dãýjcñs©ÙŒÀêóX"CŒÕ7ôŒTçˈž#g^ñS™õƒëýÖSöL6—Y> 2^òý\zXÉ=Dz·—=ßÍ´Æg»vÏÍY=U™O#.NCmp±Ä ¦=“ù®úIS™è_]® :ŸoÒ÷BqÇŒw!ìNU6äÙPp{«ƒ”‘‘ŒÓn=Ρí‚^Þ`Ýüä&ÕeÌÈzŧi iô¶¦¯/¨Ñm–âQ¬~ÇÙý†Û꾚ªºÒÉÑ}Dê.€W߯  î¿Òú–Ex_ Ï64lΨDüè÷5C¨ý^²ª]~-ÌËÄqmºOÒ;]µRšԵóa±–;ub 5¤{Zë{«½¥ÔÕ}1.m²}ß›ì×idœ:ÿ‚S>@Ž€ MüÞ>¦¶Õ§æ´¼ßE50A±ðý¾MÛú=ßÉm«Wê—FÇ¢³®C1•qŠÿyîe5ûvÿÆ¿b3¾³ôÆzXÝI‡Ø i¶¦îc#ó½~ÏëlzËëøv5¹Ùç3Ö¬ì'@ߤ*Ú%¾ïä'¹r“>G¦#UÞ˜F2à'‹åâù4ÿ¤Ùê}_êomudY“sC¾ÌCDìu›[S[ÿƒ_Zs:xý•U=6Û$µï‹^`þ}ú[—/…в¬qkZ[®¯:ì«ù5Û[* Po«¨tÎ|~ïæ§{0±lø±™Èн<4vzwQëXøWÕ~Y·"÷±Í¼“ik?Hêc¬wÐÿB¢ç9î/q.sŒ¸I%±Øõº°\ƪîOËÍvÜzˇw>.Q+ZêÖMÌÍtPÏg{£Gö–öÕ¬jaùG×°k·†—ç­<Œ¬L*}L‹ECA¸€'÷XßÎwòšeÙL:vÂï»ydˆ‚I”Lœ¬lJý\›S8—Oî´~s¿ª¹®£õÍæ—YÓªÙŒ¡ÙùÖ5õæýíéŸì­ïÿ¶V5]{*²ÜÊ-˹†Æ_•_¨Âʯ½”Þ÷b·º™nÏÌ©ö3þµ\så.xµá&>¡ÇûŸÞôIw €ŠgºÀÏ£>§Û@{Ev:§6Æ–89œËîD̤_‰}_V·3_åÕ“õg!×ç<´¾ÛkÈ&¹ÛQKý»½ßš¶ÔÛ|gíuâÙém6:³«žßn柡éýóЭê×åÛŸSq& 5Ûû¬öþj±õƒü^©—[«†¶÷Gc´ûÁgï}%’\Æ–4¶~åhP³©=Pèï£Àž’¯êü>à’§ÿÖ±ÔóNGV³%±«œòÐ[°k_¿wÑnÏæ•+ikñÞ/iׇVɆ·g¹ïçw§¿Ø«†cÕs†EVZçZ×nhqs·=ú,uŸ™ûˆY/ õ2$›_§´H{ÏæïsýÛÁ­8ƨ”–•oÝ•Û`Ë« €†’f§ûv͈w2¿Jª¨­Ã2‡~’ˆsµoó¯s]½›}ª8õdY,¢«_HkMýÌàþ‘hâáff“e,}]K°ñcK[k›ôÝÆÛ›ÿ‚V¦$ oùx©¢2ÝoP®ÌFì±ÃkÃàN²î?Ôs[®Æµ–7m”Ý kL–g¦8ÜÍê6 Ê{2p¬ª÷Ì-a$8hßô¿7r-TÝP©™D¿+*Ám•HµÖas5îr*¼ÞŠžZñ¹“/?šÐÏ¡±¾çnwó‹°ú‹euæ[h!ûšÏqí·µ›77gµqÍÍsÚ×=íl¹§hõ ûZÓüçîÙÿ ÿ½ê[ }—XÏIÖ9Îs 7ÛþwÑU9£Xˆî@Sæß\]{¾²õcI¶Z×±Õ´ šYü¿b¤ÆÃKC‹„;ÿ&´þµæbdØÜf´[”ç½ý«ì÷ÒXl|¾Æ·è¶×ÌCHôÞw!fJÑsõc©U^…õ¶ÛÃS7v¸aÿ5ÈÌ}ŒvöÜ…ÍtGeØN;~Ñ\ˆ‰wüU ³²Ú{,¨‘em;oc¹ÏÚªeôÈéwªèLjï^'gÓºié}DŠrê Ê5¥¤´<ÛùHV³êèêÇ¥w¬Æ—[`>ÆmÎ÷?ù+ƒÆê6¼²Ê.µ¥§yisÄÇæ[úZVu|N§c•kÛpo§½û s~Ž×۳ܫŒ¼Z`oXäÓìdÂ1Ž3’2˜á<>ßèäýOú®¦mË©û!ºÛ&›-akxÿâÖïÜÕb±ÓMŒs+õ2ÐA¶ý'×WÑÿ=eabÐÖ‹A{öµÂx×;~‚Y'.Ù40<5‚©q÷{Ûÿ‘R‚b/òAœ„`HQ÷^-·8’\uqÔø•Ôñ~ÙQkks-l†¼x?EÈÕæ žðw†‡ \ñjXñNOÙÅï'G<˜¼ÝüíªH éèÅIþ«ôÌ\.nV²q»1êétí#ÙîvçûYZê°ºf›o¶¦ááVïN‡<€çí%¯w¤·þóÞ³ºŽ;õZüj+u®²ÀÚÙ_$ýÛ¿3Ùþfd?-î=?1·åRë…KHuµQoó×µ­­ïÚßfÏæÿ}A9ÊY<oõ¿Á}5 HÍÄ'„kÒz;“ýÖçĹ.[’ÅŽ8ärs—Èvk‡äù=rùËèWbeÕ™“ŽÖ¾êÙm;¬uî–î}­}¯ö]•»ÑþWóÌ×ú5õ ØÂ­´Šp*–WSmhßc¶Ùsí­Ï;nk mÈ}_£~ÏQu,³/¨7;Ô¹˜l}tb1¥‘±¯×±Ûfê±Ùéd7o­W«Bå>³u+3º°éøN/Öšª 2¢}ÞŸÐôþ›ÿ¶‘ÉŽQ…Ž\´„%ñK_ê4yOrY„¾ic×Å~˜Åú\Rz¿ñS“[ßÔ©ª¶ÕVÚXkÃÉ[KŸakŸ¶Ç9‹ÐWõ-ôc}c8fºªÊ·Õ»Ò`ª@}f3èäz;ŸýG®õ;OsgUÄ?"Á˜–`H‘³“üÌ?Ưý¹n<ì¬{DóíƒÿR±qzMùrYØí7ñà.Óëf6%½u‚Ê·\qÃÙa€‹‡ó•\W;……ÆÉ3.‰ø{Uᔈ7¦'ŸÿšOÿL×ä’é¾ÕüŸÅ$=é÷Sÿתڪ­áÛØßX·Ô{5s\Ùc÷³þÚüúh¬_e4ØÇS[í}–³w¼U^ç9ÌöïÓ·è=M˜Û1ä¼<±7_:tof¿Ôví¿¿j `¤($Š]CA"K¬c«çû_ÛZ£®»µ=kómÀü|[Cjö0ô»÷ÝûêîoRÂ7dœšqŸ'Ést¹ÍwèµßIŸž³ënPév´µ®`.n®!í >ÿoÑBv=MéíÉ©ïÎ µ¤€3í oÃó”† é¥_u7/·)´²Ü‹N…ÛwXAcŒ½Õ¾OÒ«ù?Î(b´5ï¸M¡´È‰—8¿Oý"›-ĵÿeÆšÛ—YÐݶ·ßK¿wv®©ûQú;ÛK˜÷Vöïp`nÐ'hsšñ»ù_Îo@šOâTÛul­Œ5›]m¸±­ˆ:ú[7û·ûuwù»§}M²ÖË^ÌBæø‡=¾Ï¥ùÛž¸Šëõo¥¯!åÎ sÒÜz{Hú+¶úãUÎúºüZ´×\ž çÔ*<ÉÖ÷²§É×’Æ É'ýVߣîþRvÔã,k=BÑÁ žeu ê•YBœ«\ö†8ËD=®•63ï¦E¶VKN I>—ÓÚäÓœ ¨pú_Kêmȯ ´V7¸¿B|ƒ~—ÑAêí®®©vÛ`rZD€^%Õ»þ­igæg1»^öTÇÈcê!Óü—ÌX—·&°c·Vøhy'B îtïÿ·=ê1˜e<˧§Oê³b±*ë§¥f—%Í"ÖÛcttŒ?»c¿›úö߇º¼Vc¾×²MÔ†·Ù--úLÛï÷~{“bR_kª¹Ïa¸m.®»üÚþ免ìkëÁk[].ÛµÂI?e¯úO}Ÿ¼€¨Ù7Ëü"Y1à9g.éˆâ¹SÒt‘·¦ãè[ì˜<‰%ÐUlN§kÀ®ÏBî}ûªtõú*å?£ÀgmµN¿ÕWë‡9ÍÛÜZ$ñíW1Cˆðj½këgÕuu60;ii–9§üݧõ•¡†ús>ÚÈedîõ€8{K}ß¼¨áõ|¬ohp¶°›waœO殃®×˜Öã½ì±ŒnÓ‡{C™ýÞý¤¸ %`hwI‘5gå<Ü\\¾»õ?ì´ä1¶¹Û}F™cšÂ?Fç3÷š…Óú=_Wq°2sK~×n\äZLíi§%­­ŽüÿûûÖ·Õ6U_H §b°XÿѸLý-Ç÷>»b[›ÒññjÑÖåÔÝÃH<9Û¿7Ú©çá„§”þ„do§õ6qó9}ŸºqáÉJZz»k/ÝyN»õ„uœŠóCwF¢ÃFfkMšý ²«ßêÚÆÿ9é~Š­ì\×S£¥3%™=-ïnÚâÊ÷1äµmvÛìsn¯}¬¥ö~ù´wôlÆ r›pÉ5bSSæ÷šÃ›{m÷löz–?ù¶~úÙê]_î˜*}UaŒ|‹~?Oq­Íßk¬ÎªÆì¹ßOôñ\¡†|y£*½éÿz¯ð‰{r„e)H{uÒqÉþNPá—¿ÍäÿÆÚ9]nΫ•¾€î›Óq, ©£}¦³ì±ô·oèîs6Ó¿ü¨©ô•oM°YÔqÅýG&l£p²×4 ì~k?í%N ¶Ûœ³ù¿Miôn¥Ò™möeeý—Ö1¯ôÙQ66\ápquV{ßE^—Úò,ÿÁ\Öf䫸5;Ì °9ïÈ¢¿Ò\-c®¾î~Û}/RÅ °Hr±Åˆp 7 õË^/Ÿ‹ü,Ÿ§þÍÊ×¥/"ú¯Õ²òóúK¾ÎÜ|L<¦Ö q{í/§"ç¶71ÏuÞ÷¿þ-z꟔#†åJ#åÒ¡Õú>Vf"3l‚?»ú?ó^ë'O»#+ê+6Y±ÕûGZýJÊ=9˜÷Æ~P¨4qëa}†zÏml]íÈs¡`­àÉ.nàG‡-\GXúÆmê™]+#–Ù‰™5’ÓÃ\íÍ÷~ò°r‹‘ :±FWBøGòù[Û¾®~æGÞ?½%ƒöÛÐÓÿÌQýëùÑö£„öÿЦÙ.ÝáÖc½ÄzV[u{~‹þ ïoøOúâ§“ƒs®°í²«Zí΢ÀXC´#ÓÑrÚÉé=G¦ú­ê5‡X÷ºÃk@k^Iúz}MŸ»½‹7s1˜Û_[¶È®ÉsÛþ¶Ñ½¯ØÏsv!jÆ]bAíIhæW`ß—I-©çfm,æ²cq÷Oèîýÿì(YƒƒvS+dzkÂa§y‘ôcqüïÝrÜû¸ï{ÙcrÖËC£~Ó£Ú~Ÿü_½PÉÂéö?Õn=•8ÃÜÚ&;jyöÿfÄèÏÇê?«¹øøÏiõqM–~hcËtÞßå£aȪ—5€÷ ¤8ý=ÖnÙíjªoêŸO §Uëû-¶ÓºÇ´ÎgîTÝßO÷Õê64ŒvVçZí¢²%Áƒs¶UùŽ÷»rRÛjþZ©×ú¹Uõ¼f°ï‡ï{v¾‹÷7MÏ­žÊß¿ü"ë>¶Xí˜t´À}¥ÏÒ}­oý¤°~¢á¿ö›­¹‘e,|™’Òóô?“½®Þ·~±ùµÀÃY¡ó%gsFòØ!ÈêäYÓGOƪ÷o²Á'~»½7ì,vÏí, ž“ü{[]~ݭဤïsŸïZ9Ù-ıp$<Á<C²zÛŸ–áYl45Œ?Dk·}sùûUipÞÄŸ×.3Pá”cD‡Òš‰ÎvÖæ5¥ÞßóV‹þ±õ›‰ÝœáV 9ºOq`ôÖOQë™ZVÜ—Û`fákžçuú[‹SÌgZð¶_÷ª}? âY‡ÓÅ@s^í·iýe•þ1mȧêËïÆsÛmwÐZêŒ<cXÝŸÊsµCü\[e¿W‹¬vçzïï1£ J¹õÚÁWÕû/5›…7Qa©°í¶Öv³w·î,ܸÅqP–Ÿ¼º&¤šuÔ}_5ë½C' דa»¬å˽„ÀýR·Õ¢¬Oðû=™zŠ_W~¨ç_N>Köâä¼äåÖØS×1ÖÚ=þ­Ž·ô wÐý'ój®_¯¹ì}® ·S–ÁYcA‡›¶îfÖÎëþvO£+77옔1•ß]5XÖ>ʬn=[™ü¾û=Ví©úÓ:¨ãÃrÒ†/FLœ7:àŒ8þn¨ÇòE»ÌO=¿oZ׫ý¯÷òÿÌÇÀòFÚ°ú¸Íèô¶¬6öK@/cýïWí~¦ýÍ»ô¾ÿôK@äáõk¨Ëè=??ÏÖp-¦¶¿Ú÷dfî}y>¥ŽÛCú_Cú›ÖÖF==;(UâØìkÚX{ƒ]~EÁ]VzL»ØïWþÓú‹'®daÑU§U]8˜Ík¯4·km¼´n´î—»gæzŠÇ±„NNˆ2ß‹ôI“/!†|îhb€À—4zàëÿ)>)zdöY½#§}]ÉÈÅÙe¤Õ‘nK;Ò²«=‡söÖÆWìg¨²>²}rêõwWÒŸ· [iÛ¹¯tÃýOä5ߣbÁè™ÙÍôÚœçcåÑsV¤ѽޣù›\ߦº:¯Å¦ûNxVæã6ææå’úí°†\ÑEnš}Î÷ûŸôÒ–A“H‘†¾ªÞ'÷[˜¹r\äá–šý_ xc KÛœ²B\_,sÝzÞ‘—~oLÆËȯҶ潑OÇ÷—Óñ_Õ:ŸR¿'×åYo§Žãïceì­þ­Ÿ¢Þdz¦º¯«™Y_WèÉ}Þ¶MÌs÷Øĺ¶½¿£bâ:×Q¾ŒvUÓGÚ22VCåϬ0›ÙU»ßúÃ?yû€JB$Qº>§?êógÇB#ŠP"ü±âýK¥ö_ô;üçÿé–gÙOú;Ϋÿ ’\{cûnÖÿÑëñºè³Óêu‹©à¾5ð¿EßÙTú‡Õ<~¡Cîèy~˜q}3,%§xkšï¢­ôžƒÕp^̦’úßË\Zb73è«ÔýYÀÇË9xö_M®hiÙf†;¹±îr1Ê`t$x~Š^3ü{Vu/a w´1ô ­pwµ®s_ûê¦[ñM^¾Q´ÚÝ¡–W.'Okyg±»]ùËÑ/ÎéYVÝÓ²ŸVi¥¥Ö´ ±­MÅ¿·ó½ûmaõ©þ»[•Ò/õè’÷b¼èýÃn¯úJÖ.jÜÑðÙt¡8×LoQÄ8t;<ƒñ›÷Ò[éó`Û¿Ý=ÎßîD!æ­û˜ék¬~Çà7HmÿIô5ø¯ÆË#"—×n8 ¶ítêøú>³ý¿IÈ/¼dÝp¯˜¬j\Gøy>ÏÌüÆ+W~K^×êªf^CÀk¬-ï4›»ûiúÖ‡³¬dôÇã³"–Ö-sl¾Çþó7~ê¿õ2·Ž‰]¶ϼ——DH?DÂãèe¹9Y½A¤2ü»Ÿé=ݘ}?¤³²rd2ú#ÍM¬ÊŽCÂv<ý%®ˆÜÙEÕœþ£ÐñªÄs^Xç6íçkžÝŽßü®Us2_‹ŠëÜÓkÚÜ'ú«®ú§—NgD¦Ê´:ïopâeWÉDU|;3àÉ“QÊ1–œ`N<|=œìž‹ÒìÀ¸âç°˜Xòç´µ¯NïÌ÷¡ô OØýØc¨W_PÏfüZÜðZ×jÀkxÜ×îrÊë}7  ôûªÊÉÝÔlöÉ`­þ•¿Iª7`ô÷]†ìmïÅǯèXu/.õw5Ìÿ¹ÊÖÌNÿï:1'‹‡¿# “â¿k‹Üö#ÇŽ/Ñ–wO=¶eb ¦d¿í5€eX澯δÔ?Ñ?þ‚¡Õ°rÊ]s÷èC‹dèßh–g]ë÷‡]^9÷d¿i†Ÿ~ê/ÕÜ&`à¬A€ÄŽ›Œþ,¶e·»G~Ž·}+ØñH@qjv9Y¥ ä2€1Œµ£ûߥòÿYÚʽ€Øcº¶Kp(¨¦ãôÛê.G/+hÚéfé.-‰æã›»ü#ÑsslÍαâÛòl /ð ÍíkX±e¶µŽ±ŽjÚIïm<ýþsž¯àÂ"5ßr±°r­mäR÷׸×ÖÓô#q·ÞçXÿ¢…™[­û=¶ÁµµZâÐÐNâX×íI•ý4vRn±ÍisÞàØ]ô¶Ÿvý¿¹ù•Ö­YÓ“}xõ:6Ò8ê¹À~ÿÒúIÙHíH{¿ñoÿ‰âDÁ½äOÁŸF?5]úóŒ2þ¬fc–½þ¡¨l®7ºm¯Ù^ïn÷þj'Õ*«§¤Š«XǸ4|šõ‘ÑîxåŽ©íø¶ÚœÕ‘3s'¹H|§â¼ç¸z7`aÒ÷Û’ÿ{½1ô·×»ký'{.üÿÐ]ëŒÆ»+"ªe•ÝPÈykNÿ³¶ÇZö7ÕkKîüÏÒTÏô•­>©ÑrzuÎÊêv°Ó½Â›êµí³cìª÷cý—þÖ?ú.ÿçŸê~‰ˆ}'êÏVxœZ,‹î¹…¥ÅÎu˜öÒnÎý_ùþÐúj´²e1Ž3’8A<:pñLË'®Ô‹>L±Í!)Ôb"8ǧøŸã4ò²©ºÊ³²-Éί%¹Ù·4}›k\ÆXü|GmÉÌێʨ¯üøOð©`ôz³:¿ÚqÏí,Si´UCL™qw¡û…xøû~…»ìÿ‹]nÔ®›Ae¹öYÔr/´ÃÖÐúYüï¸ÿÚ‡\·ë®º˜Úêkk­¢Æ€ÉkSãË\Ü&c áÿ‹çdÁÏdå½ÁËúXðHË×?ïDþŒžc¦}O}[váÓÛx-ut;Õ·cŒš¾×svUÿX£þ¼ÕNßV°ñì¶°Ö ÎÒZÊXßѳ×x;_vÆ×ê~bè\æµ¥Î!­“ YŸZúF1s+´dZÑ%µ9ÛôþùªC!Qü!dy©ûÞöS,ÙôÊr>™þ„¿ÀýÕ¾«tþ¡Óz_Ùz‡¦ÖµÎ51‡qcKË,ÑvÙ\×N˧*Ú²*ûmŻݨn§hc¾’'ÖίÖrºcÆ#½Hý+*òÓü¿¥ým«Áê—Y[)±­7RÒ÷“´³úö½ß›îSaÂD(kú4ÅŸ4³ežY%3Å.#eì¿l}QÿB?×ûI.oöÆ/ýÅÄÿ¶[ýé)>ë“ùÿÒéºSÅÁ9dÚÚè5‡ï'BZ7÷·nZ#ëwNêù®Â¦»òÒæé}v®w¡SÕÌ&JºÚK^Ñ£ CQzf ÿTr­Íê—Uè9ŽeUWî²×HÛéµÀ:½¿ž«f”įܤ]>O—å2òùµ”¹½°cùx¿sƒ‡‹Ž_½ü¦ßËéÝêíÙ9O˳gVú롞ç4¿é[T~“Ùù«2á”3z^Xn<†¬sKÃtý-vYk}Ê—_}=uöuš,!·c\A G¶Ê,»?à‘ºEcàWUÌmv %­óýï奄\‰¨þ‰ ¼ù8ðÆ3Ë)ó„sÉÁéôú#ÃózÎq½U™x™øl=kô6Öå0KGcêm÷ÓÿžÖ'Sú›•N!wC±™XÐM5¿Ý±®Õí¬¦Ç~âÌÖ~£ƒ•OõC°žZÏJ%À8 Û?wŸz»nwM©Ò¯ô·ÇÞêŸýÌþ½ OQÐëGXè.;Ù`TpúlpØêè%ÀƒÇÛù¾åæVõûJºëtÕYm%§PA>÷9¿Ö]7Uúé”þs-Åû.E‡ÑݸyuM\-Wï¼9¾•D5ïs€|ÑŠ┺þÕ=OT¿/ÔůÔx>í&ÝÛU¬> qq˜qíû-y°ÀCdvó–gL=Kmn/¦Ì{'në˜ c›½Íöµjæ}^=QÌ5ÏmPZêÞûv×;ó‚†p”I;þL±”Œ$8E“)ÇYŠÕÎéõg[U™»Ò$–wù®G_M¬©¥Ï`,m`$¢Õ¥wKÅÁclê¹¢ˆ2i®cà} y?KëTå]öN…ˆj%ÄY•qumsŸf×YéÁÖõ³cï#ú1õLýY%‚Otü±·¦}PÊ/ûo[aÄé´ öï 9àké~×ýz[êÿj´\ö–Vßf= ˜­ÑŒÛô®®ýhën̲¬Jm{ñ1†ãt€m{NßUÃÛ¾µËæd=îvúì° ™Þà"’æÿàŸöÚÓÁŽF¥=û~êÆ³.uù65ÂÙq -cLLïqÝýE{*üŒÊÚkõq®§cAvàùÕØãùßCn׬àÀ]FE´·A»@\æýVÑc}haÔÆÔòéq2ûœ Ö=Û´öìýïý¬Ê…ÊlôÜK«h¬çä¸iÇÚÛ*k${c—Ñêé–8´å½áÖ¸@&nÆôuJÕ•NºÞ~ÖV_Tý´úVƒüæÖvWTs©;=„¶œpk­„~k¿;ðT9Œ†r1,~cýoÝC×ý]È7`FƱµ8±¡³À 2éüç9Êæ~Yø–bZç5–€ ˜aÂps ÝîÜÕõ[úŸñ§ò5k[mT´¾×†4wq€©ÒÕÄé–ë¯~K¾–M¤Ùiÿ®Ù¹íþ«=ŠâÇËú͇T·¦÷xýÿœV6_\ê9R ž“æW§ý/¤ˆ‰(zŒ®¥…ˆ?OhýÁ«¿Í #?ë%ÆÝ×îUúÏCéX‡$zÕ³!†Çûl:§ÿYQéýzë,m.¥÷9çFÖ ËK?y·4çìý]Õú>'S¦->•ÕëVK~“?ÚfïÌrâó~¯e}ªœfÜZ+$cÅ„5Æ_uM¯ß]v?ßé¿óÕ™r’L½P¡Ã®¼^M®S rÏ„ÌcÐú¥–<>é¹×tìs“^À9Yèn¹Ö¼çiÛôÕie7êïN·¡à½¿h¾>Ýxâ¹ú8õþímnæçŹFVè}*êðñþÓ“kËimZíoýÉȶߧoò6>®õæ‹n»×:Öìs½®qŸs¬Ù½ÏÞç©ùLä‘­t‰žœ_ÕŒ–g•HãŒøá8öãúzœª¯¹¬4[SÙsáß¼ÚšÐßå)[‹µ¶ØËoq.¨¸ntz¾®?ôý5µGAë×mŽÅ¹¡Ä×w¶Z×úGµÿœ…û'­Y·õ<ƒSe¯œ÷c÷}?Oþ hŒ±é(éâÂâãã]êì%µPÖÁåî0wm:Ô.“ê·EoVËsß®-'ô§inàgôïäíú*–7Fë™6Sö\ªš× ãÓØÐ&m™úUlÿ»wœ?«½2¼ _ç]2{Éþr÷ÿYÊ.c=F¢G»tñSGë>~ApÀÄôÙ‰S©"eÍ£­¬oæU  ´fÝSZ×]~ÂKxüÕc¨Z[_ª×Ö±îp:Κ,î•›vP´XÖ´VFÀÁ ¦"xIéÕ¾'PÌÃölúBr×ßý÷Øëâã* ¥¸ÔðƒNn%ïutÚÛÞZÓ(}Sܼ7UM†·ò ÀwòŸê_Õ<÷f¾þ£Žü|v²÷hç~c÷]ûé’™´=[ðã–™ êpÚú3¥…Óòs¬ÙCtIçè·âWUÓºN6eƒ}Ä{­<üû­V©¢ª+RÀÆ7†„DÙL–[»&Ž•“n-#&ðØ®‚ÝÁÅÄ3k˜>“}Ëv-u5ŽeMÇu¢_ŠË=VÖïÎkù¿ñ˜º®™G¡XæÎ±ì`l–ƒ&`–ÿUpfÛ‡“ê5§ÑpÓnÂtþ¯¹K‹o­ªÎ×»Ñ⵸¡Ö²+±í‡èKuç «ù41ÀÞÛØúØ#q.†{Z³«Èmïc›aí‘S€“?»é-/«Ý /ªŽ¬á?e‘VºÂ=»¿•Rpô›:pê†ó?¨x7üâ’í’Cïy<ÿÿÔ­MŽ%ÍaZCƒà]0Ý»6†ìgüü"ÓÄú‘Öz›juäaR96]J+«û_IëÈW³qðŸn¼oþå/ÑêwFé,fÖ›™¨ºÿqƶ} Öâù]%›>;õÝø©ú¡pùYdÛmà“ê=À4ˆî¼=$qõQ}“ìôz&€À*<´hN„ìÁÕsórȦ¼½…þ1__L8}[ç<·hpvÝÍÿ…Óé)QÖž§˜Y³î ô1´L~–ïçlvÕåé'~£ˆÕqÿ/•ë8ÍíÞ»û|÷ϲzùùAã:ê,©Æ¸.vÀ[ô½¿ù¡nwR­Ù”ñfØ ¸|N«ÂÒP…ÒÐû¡êÝNd< :.üç7tíoòP«ê½q–4œç:¦™--l»ù%Û}«ÄCEß zÖ¬ žË,¾Ã›{ ¯Žp"Fçû}ŒþºÁ·¨g\Ögbä‹•CƒÚòÒö¹¥ÍØÚÝîwÓüÅã‰&äààÅÅÄ6lr·y>Jö§Åîü»iÁþ·ù·Ö°z‹2ǧcCl‚ÓçG{•ÞÒ¬n>EØõ†ÑS¨é Üï¤êWŒ$¤·/¦ÿ·…¯¥ë·‡ì}v¾§u…´‡>¶‚çÜ1¢7~–å¹õEØJû-nÛÛStpgóšåàÉ(ý]i–~Í+Ó†ÿçñÿ[ûÓ5ôΔì·_[m¬Ã˜ µ®æMšå}|®’l¾¬OÕ /•ÒMSô?×.ŸoQįč]pt#@@ÞuÛô—›Ð²+ÊfäI;µÕÌúL{“ªò¤•Œ>åi\:ךO »ý'Ùðíév^0©¬·¨ÖÈ8’Ûï§USô6ÿƒ]§GéµôΟ^#up—ZïÞ{Žëþrù‘$Ü» ºÒﺪ_+¤¡SÿÙdeal319/html/graphics/warning.gif0000644000175200017520000000171411341325566015201 0ustar cbecbeGIF89a÷U€ªÕû+ÀÀÀ€+ª+Õ+ÿ+UUU€UªUÕUÿU€U€€€ª€Õ€ÿ€ªUª€ªªªÕªÿªÕUÕ€ÕªÕÕÕÿÕÿUÿ€ÿªÿÕÿÿÿUUU€UªUÕUÿU+UU+U€+Uª+UÕ+Uÿ+UUUUUU€UUªUUÕUUÿUU€UU€U€€Uª€UÕ€Uÿ€UªUUªU€ªUªªUÕªUÿªUÕUUÕU€ÕUªÕUÕÕUÿÕUÿUUÿU€ÿUªÿUÕÿUÿÿU€U€€€ª€Õ€ÿ€+€U+€€+€ª+€Õ+€ÿ+€U€UU€€U€ªU€ÕU€ÿU€€€U€€€€€ª€€Õ€€ÿ€€ª€Uª€€ª€ªª€Õª€ÿª€Õ€UÕ€€Õ€ªÕ€ÕÕ€ÿÕ€ÿ€Uÿ€€ÿ€ªÿ€Õÿ€ÿÿ€ªUª€ªªªÕªÿª+ªU+ª€+ªª+ªÕ+ªÿ+ªUªUUª€UªªUªÕUªÿUª€ªU€ª€€ªª€ªÕ€ªÿ€ªªªUªª€ªªªªªÕªªÿªªÕªUÕª€ÕªªÕªÕÕªÿÕªÿªUÿª€ÿªªÿªÕÿªÿÿªÕUÕ€ÕªÕÕÕÿÕ+ÕU+Õ€+Õª+ÕÕ+Õÿ+ÕUÕUUÕ€UÕªUÕÕUÕÿUÕ€ÕU€Õ€€Õª€ÕÕ€Õÿ€ÕªÕUªÕ€ªÕªªÕÕªÕÿªÕÕÕUÕÕ€ÕÕªÕÕçççÿÕÕÿÕUÿÕ€ÿÕªÿÕÕÿÕÿÿÕÿUÿ€ÿªÿÕÿÿÿ+ÿU+ÿ€+ÿª+ÿÕ+ÿÿ+ÿUÿUUÿ€UÿªUÿÕUÿÿUÿ€ÿU€ÿ€€ÿª€ÿÕ€ÿÿ€ÿªÿUªÿ€ªÿªªÿÕªÿÿªÿÕÿUÕÿ€ÕÿªÕÿÕÕÿÿÕÿÿÿUÿÿ€ÿÿªÿÿÕÿÿ???mmm••• ÿÿÿ!ù,©H° ÁƒXX ¡Cƒ >œ(0¢DŠ -^ĨPcCŽ=nYQäG’&GrL©r¢Æÿ,¢´SãJ‹ÿø'£Æ:ÿi¤¨fÐ=j4  fR„aþ;úïiLj0ÿQÕ˜Ñ"L¦02ì&L˜0ÅŽ…h&ÌTÕž$¨&ÌTåÎ= &L˜0a”’¥á‡T|˜/cÃ%‹$É1 ;deal319/html/graphics/new01.gif0000644000175200017520000000022311341325566014460 0ustar cbecbeGIF89a òÿÿþþýý*ûû4ÿÿÿ!ù, XHº:쌄k cÊLåüJW}|&i¦ å+\Ìò Àš+ÍfÛ8]¨&ãÝn²œkCc´™hù<6Gå¨t-›M-CÅB&åé8DZš¶ð¢Ð- ;deal319/html/graphics/StampSm.gif0000644000175200017520000000341311341325566015116 0ustar cbecbeGIF89a(8³ÿÿÿÿ)))RRR„„„­­­ÆÆÆÀÀÀ!ù,(8@ÿÉIë4ØH\)˜%ZÅ1ÂqÚèVH¨k@¯­à €>d`»i¬—Å$ Je ”Óª"Lê¸F)%ãÁäþ¤¨€G`s¹„/y—¿ î·¸‚ÊX3H1€v#!Y3IˆŽKƒ+c`u|H™††=1v[BxF™&Y'E’-S«Y*'E–<™£7»¼Œz¶§F‡­d[Ç4P#ŸR°G?¶‰X‘ÓÄÃå7ÛQ;ê–}D&Q‘“0×7÷¡Ð]ý4â cä´LmzìsÄD¡O1YÚ‘âÛ]m~¥ÂƉùÁˆ“QA$F¥B¨j"&U"çDiV¸Ùƒ†EÈ„©iýÎéxéÅh =3å»"À‚›ÑÚÁˆcÃK®zÆy!sU °oÄn”h šODm»nË,qË’±+åç?}E%RP¦B-\]¶"ñ¥9å‘`2Š^8f¥°ñÛ·ã á|.<¯c!9Ã=2î$!^„E#]ãÇ迨ˆ lSõÊíÁæxWí‘2É©D‰;Ào]p¾ÆÐá4×yM#+g«I˜;¥º„ïVƒC'­µ2.˜JhÖ¬x1“ÆàAxh“¢ŠˆO@^Z¦!)¯€ù¸„ hÔС%|¨‡jå³¹ŽB½Ü V6°E`ÿ#¼P4€‡±±hÏHe…z6LÅÉ ¤ç |µÃ5Y"ŽWìGZ _M%‘vÊhø€ Œv„Q4B#Y ‚ÄY=Ê ;3‰zéd¨ƒBr’¤’" EB‘ÀA "7.Y·‚a !e_ŽÒ‘‚»½ðÒwa„Öqî€@õâea ¸øBurr§Z6r"À”3è(YÁ±?–™PÖ¢l úŒH”I)U_^sUt5!:i[¼a'DŸ8É0*À¹e©TJ¨ÅZØU÷”ÒIª¶êá'iÒH§Á¦è–ö:Æe9«ì³Ê0 Ý€ñ‚ÿH×2`ÕB‹›C½• ™;À XŒm¡³¹I§ëPÎ"X(î¦pì {š îsI»a§ï,'¨6k •ëj«Œ”gÏ TX4ónØž 2-QßÃÔaÔ!Àc“#ÒÙ‘DG,&oÁ’² ¦òxäy¼zׂìíÎ95 ­YÔSz; ±€bñcˆБ¬qÉO¼^G±¥ÔìuAä kü°¹ÖÆË¼"u/¾3YvngëàZ&)0ía ™“Žü$DÅ›RõH£Ý¸„À"¥pоu€õ`_ÝÆX–îmhÙ²’‡ZX¦Þ<’å.&¡ÿÔ³ »ì#J_Y̨á™l1wb÷zB¤‘…C†Ø¥ø{Xî2P@_Dº?_ýðOÀ)ÉáÖ¬œ„¸áT°:Ñ!`6‚@8á¥C)ÐÔ¦Ä5­ÂYß€ÐæÔ7^\çe+ðà)’C=–VÀßs'…¶õmPj¹ÙG€8…o6ÜÔ•®pPA¤Ô¥`ƒ¼pÄÆ{a~Ø ½¨ð…ëÛÈ1¸Ç4pS4¼-¶SÿÊÉby›2 >&E¢x=/‰Ø{BQ¯€ñYÜD„¨¸.±‹ I¡òÈ»_ C ª£°°A‚gé£Vð%/„QIS$ dhDúy+ŠH¸¤óHJ#08ðãÖŠ‚X+ì@Ob`Öø°!lŽ‘ŽBc¾F:’—2`@”DY$^c|D“Øt@Ë¥rD;@·»äɲ-͆4²é:zÒ…;0#`–yq:nŒÂ5ÙÁ#|ü °,'áùMÀ€¯|Lœ'§”sÅàsh¬Ã)Ç×Ã/Xê‹® Bup¨…˜Z GÿxŠ!Žo¡å"X)ÍRÏ’ˆ éìç†¸é¸‚Ò  ‰,O­@¯iÚ@U“»Tçc™y)=uÇ ™0&TFöwCÖ‚pÄLJö° g› ¸2öSûÞ‰ØÐÚ“ ¢®çAO³êÃø”­¬fæÁ¥·b§‰¤,<5óØy6gÌÚ}­æùÈ-£«ûÕõ!;deal319/html/graphics/idealbg.jpg0000644000175200017520000002610411341325566015136 0ustar cbecbeÿØÿàJFIFHHÿíPhotoshop 3.08BIMíHH8BIMó8BIM 8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIMøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM@@8BIM —€`€{ÿØÿàJFIFHHÿþ'File written by Adobe Photoshop¨ 4.0ÿîAdobed€ÿÛ„            ÿÀ`€"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?ôû'r‡tGý2†yð). ïÁçýŠC^SiH>0¼¤¦cù£”9xDdàÚg””§º#Â!D5#ñNî?¹(‘âÓÌsñI,L™çòÇŸï'ŽuöžÊ¥§Yׇ6´º<õŸïjrÒÊ7¼£ â¤íqgçµ5#Ùº#q>äÎÛ¸˜×Ǻ NÒDóÓ5Û‹šÖíp໺D¼8ÙiåÉÜèøöKd¬æ˜ÔÉ=§‚`‘ñ 2NçÀ)²§G¸Ä‚ŸÿÐôû>šîS°û”`r’àÄþ|©ãîO·àOŠhâRJù)‹`ùvI„Jy[Ù$#p3§À¨µÛIמÈÀv%)4™Fú*Ѹ°~ᮩÁ†|·HóS†÷ã ÃZ8õÐÞÿ.ò¦ÂÆ .–ž K¢–Ô‰ñ lj5iD$B^çò ”*l‚Ýx¦-#XÓ±S¯è‘â’˜ ¤Ù q#V¤ðI+yêMÕÂF£„ÚJcR|’B‡~þ(nÔéÏŠrã¸ÁÐr˜žRB˜H0G<¥¸n×Å(k´ñJ#_šJÿÓõÍwŸðLí„ëüP€ƒ(š8"¢ ¬è“˜ör׺@A ohs`ýéZíÂF¤p—e(ˆ?IÂvžÚ§wyøèR)bÇ¡ÔÊP$Fª!†tÔ%f{¹iHzž?ŠrI™0”a%,lx1?áîxî HŽJJIµ½Ï=ü“ìûŠ`TǸAäpRµRRÉü¹e@IOÿÔôòÆÌqÙ>ØàˆIÿH¨ªI¦D>`ñ”†÷}6–»³šd(ÈûÒÒ%%S"×¥¨‚9û”AÔÂ!ƒXQÁÕGs·Ð$¦%ûN½üR Ñ쉟ú¥=¬'^9…%ÄÊ(+—¸ÐÇi½}£Üج€>Â[šæ–Ù÷¢t2m¬yÚÿ¯)®Ú6è5)P¸€8<ø§·W´ ^‰ 4ù©~aD„ñ.]ÛƒƒÛôOÒ§Á'0"<)6uŸ¢y”=ã¾£_šHÿÙ8BIMÿþ'File written by Adobe Photoshop¨ 4.0ÿîAdobed€ÿÛ„            ÿÀ,"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?õ3¢&4xG<^wÿX"©“ܘÀ{ýévײGVù¢¥µ”Í1¬HÓóT÷iÔ§c„GŠ˜¸É¡Óï3¨ø¨Ì;QÁáIÎi=’Rçc›ðI‡pØî4¨°‰×OÒß „”ɲ à‘ðì‘úF1§1-#^Aà„jO³Í@ò²%Q¯Þ‘S+°ù ’Žèç…T ÚÊL·ÛñLâÞò JIÓºc®‡àŠƒ&OŽÅN4QhÛí™ ü’RÍt'²=¿2™ Ï÷AàhRMºHú@}郉ä'—Iëâ¢"@©“[FAð즶ÁóP1ò„Î’ÐI~ð@&ûªÚöDþ ƒ‰ÐêŸyhÚíG‡ŠfÀ™ÇqÝÿ+\·o$ØüÊAÍjÚ‰"Zx> ;cQ¨ ¦ú$ÍÀ–ðLøT Gn§iðì¦ 7–»QòR$5„Ž"AH^¶‹@Ç5üÈ{å[k`à*k¹ƒ´îû½Êòr ¡EìÝñ j;½Ä$„¬´É¢û ´à ðUbØ$'©¾#PyJ5H4ƒíÔø"zdê}¿‰I Žu> ÃI2Ñ>3¢&Æ7SÛ¹PvE`d¡j¢v\WÙÆTšß ø&p/gµÑÜw \9e‡î(º1¾«¾òÐݧÄê™ä¹“μ©ì´úÚöé?ùÅž›@™(­"èŸE)ptm|á¾%!ÑNŸç[óSÚÓÙ*ÚÑ` BJÿÐõ7}ðUÈ×_‘ þ‰@ƒÈùŽÈ…-=ÈáÉ€‚{¤ #CÈMHFŸr*bÂHwÑ:Àlv¢Gb–½õNŽ›àŠ”í®0£‚¢Yí‘Èä/M®þmÓü“ÊbÛ;Ä$¥Ú>>*!ºùrS†’`ŽÃ”ó„”¿çÊ}gO¹DsüT‡>E(ù©RaÑ☂ UÈpòI-…UÐÓ¸}U¥ZÝà8îc:ÈO%Ü TZ5–˜ò*Mb>a9,ˆ„‰)öxMxA <Êç] (ÄÂiÔ8wALƒ {i*.an£VHðIÚŽ÷§pƒô‚Â@C;~ M3ßCÈLøa×è»ÃU æ#ºI¤Ž€6Go–×su` ÷ñR®ÒÃâÓÈIIw6‚u!;}£Ï°„ƒÿuf‚Nsš!íùƒ+EvQF¤k¨¹ÞÝtRŠq&vêJƒÚ\Ò[3ÉŽcþ© PeŽØ³wbÝ ³¢­ˆ× äù¬"wdª¾çophcîV¬ê\\KH×S)è˜ÕêØ­âÆ˜óIìkµ(5µõ“¨‚¤I<”B¦ÌÍ•³Iû£ŸÁE¶ïãO%Öžßv‰5­@<”•¥uµÜ74´÷U‹Ò&<”ò‘˜ÈÅ3œÙk„ ÒU‡5®à<¨EKÔ!¿Êì’ ³{/¾¶˜!FÇu•Ðr’¨0yuEIÙ¼Ôi°:ÀµÚè‚@·ÿÑõ7ýÁÓwý«’?½¥Î¢{&$jG)ûø¨Æ¾3Ý1HƒòKºR*Piì‰F®¸Iï¢çXððRÚµžé)NkÇÒ˜ñå!ƪ-/i†ÿxDimŸDmîø¤¦?‘°‡>:x©jŽPS(Ÿî)Ƈ]GâšAç’£LsÜ”ÙBµ’éüe ù(Y;Ť&¸<§’¦å3©q>Üø¥¤ÂSÚRRÎ$ò$(ˆ·¸ðO.]B‰íÃæS0Í6Oæ w´ëÛ„VìÑÚ€ÓÈçº Ùm»Û¯ÔZè3ˆÔ|ÑKO´hy²“ªm­ö¦ëä›EéÇç¯Þ“ªp¡ñ…Òöhu 2Ët2¤x»§¥ƒlØÂ5;ÁD£Ä…’IXñйH¶9Ô}Ä tZm#uFüÔ0÷6@ÑXe,oŸwÓ#¸¢BF¥-^æoýïàˆ`†ä‘F‘j:†§aö$•L¥2dá%0{öF“*"ó:ÑÀöÁøÊ¡ýÈ@ßEÑà­wK3¯ŠI˜ÒÖ†žÉÂ+ ê{G™Qs÷>ˆLŠ—ÝI)R‘!M´Xî}ƒñFe5°è$ø””Š çˆƒäJ3k 3ÝM$ÿÿÒõ7ý«‘´ù+ú%˾<þ…-§»y&Ç‚qǘì”kù *` ê|Fâ|Ou6÷ãEº9ࢥËô"=Ɇè11Ü„ïäÝŠMpv#ñIJk„ëß‚“¹˜Ä’;©¤iÇt”§{À~Ÿó@:¦gÂT‡ ¥" FAúQ!å¨ðII˜}5³´S°Èäê¤#/“¹…¼&T³µ÷}é$rŸ^S9a$”Ä8÷Lç |Rqt!(žR_Äù£WfáéÅ„¾‰vI$XNëžLsä¢Zd@iN~–æóÊBÀA;u$ ÆÉΔ  xGþEw|tÖ4c“ø¦ÔŒ!ÍÔD‘ÞÀòù ·W9Ð6»ñE.Ð}!ßÅ ÒÔ»ÓÛDÖ×]]¹§p×´&¶5Ó±óEt[r“ÀåE¯kÇ·²®ò]©ã°ì¢ i‚•®ôñlZâjƒÇ> îh p;ù¡89‚N½¤"´ Ù"p†×ø¢ DŽé(èºR˜ÏÉ4¤Š]Aïì 's k§ŸeÔ÷ð x”TÆRÎú-.üˆÍÆ`ÕĸøvE4V„ Æ'ùÃCûÑšÖ3èˆRLH“ ’‚—å2…wÓc¡®×´÷JÞBJH™5&0’ŸÿÓõ7ý_¿â‡ý‚DðˆSg·»ÇÅ)ù‚”‚8JuEKL;pìšÆ€w ZäÒ01¡ÓÈEJ%¤vÕ0gŸÁH×?@Ï—uâÓî))v¶\A‰ìËdûIiìR¤úUA1ÝIºŽ$6¶êÝ-iÚy¥ÍtØøóù"ÂýÔòà7»Ì%QÞ`öÔø$ÚZèÚ½= Û»¸Ò J½4€é<N8&A†Î¡D÷묒'˜R­¯e›4êP_¨ý-i{'’?'Ü¢ÑìôݫԩžJiEe£É$v‘D¥<¤¢I݃çpÔ©†î€t%<ÜpŠ­žÆ0I‹“2úÜý€ÞÿT“Û¼0[ÂÌiže ƒûÃ蠆ܤ¢×µÃp2¤¥Ðîk_QkŽÐcR`)¡dÖë+†ö2GŠJj‘ñ±Kײu2ÑÙE•¼˜Ø@ä邦;G6Б0RRPAhpÒS×ôÂ`Gx)3é„TÿÿÔõ7j}A׺9(ŒøO…(H8H‘÷r‘q·éwóRÞ×6b *bvHHDŽÉÉD4ÇÚ$vä$¦0%NLx§·€@‚;%´DBJXÿ¹FïóS ¶@ž"JX³M24ñø¨¦GvIJàGq • kÇt¹‘%%f…M ³¯Á¦H . 9 ` ¥žÞê:òt!Cf¼èŠ” §Ú{©4ÂrRSФ òá)$¨ ÜɃÉÓº(©pSÀQ)ÚRRˆ! J”‚˜”É1:à)œ7á"¥¾éž÷Ê2+s]2#¸S&H.‘²ÏRPý}xÓÅ9¡PôÝ0>ô¦"=SH"G (±¡‚&T’XwRI&%%3a…eV ÕÌqÝÌA õEm€·qíÏÉ%!¨±¶«7~a"?ÍúMV!R!Ž;ë:OŒ©Vë›cvË€Sm4ú%))Z¨<TåÉÜ>©‰ Uý ˜ÉØ!Á%?ÿÕõ"4@ÚàH‰ÕÍ=ÓHñ… ’fˆ$G(ä4ê—à•©ì)£ýèð›c{‰ø¥jk‚ èT¸2m<µ7¢ÞÚ#ja¡ø$èuSôÚ ­t?­!‹¤Žt Ò<ÁÔ¤jÝΞi žÝ&BV³IðñF!Ôù5ïæ¬kÊEHß̦R°h „Ʉɮ„dh>ô1`&"<(©–÷O)÷PJa%3ÞR.• ÉnILà§(DùÂ:‚Jd\“ÂI§Á%/îî }ýŠM³ÅHÁ )ˆz}é¢Ñ/¸$âM-S'qNJ`|RM\'”ˆM*SŒ¦IL€ê¤!§ÈèPÑ’˜}›‰ ušçÝ3Àì‡ $¥ÒLšRRò ÿ¥òS•ý/’JYM†J©5Ðe%?ÿÖôÍ|’q‡Bq=†‰&–JT¡-©!‰'ÅÜfZLx#mP4 ${$¦-¶Éé$MÎÐØ×±þgû‘ >a%2c‰çïQõ¤è>vÀï¡C‚;"¤Âãà‘t!¢™#`IL…ƒÍ?¬ÄOd„””ŸÖgÅ/XÅ 7¹O)‘xr‰&q§*!þ(©Ed~)þ)JI)dŒBtÄ$¥’O ’˜ºH„«$|ӆƾ:¤¥çDÒ˜ø&ILÒ´Èù¦iLùIIšàR!Wú˜±Ü!%2:$–éLIA))g4Šˆc»èœ<þv¾iÍ?—\†Œ1¢v™QÑI©-]Ú4$G4QФ¦)Á‚‘ ’S0â×k«Oàˆ„Ò8:„Xö„k&N’(YEü©(8ê’˜žRLyNߤ>))ÿ×ôç yŸŠRZ•Œüà5î€$’àpäÿ—P­Ò›C`A< ý9@s7 à„«Üä’„A)ŇÂRûü Ôq⥬Ï>)j©÷ ZFàFšê”i§d–¿^ü!ªÔä‚Î…3,™ø©È"5ìB6¦0¥ÈRkFÑä”hŠ‘mHh–ï$·$¦I&”‰"Jbï5å¤ü“mw‚ ¢Èq3 !îàè¤r˜ù"ƒ»!ªQ ˆãU&¼;ÈŽÅ$.Rç”ñ¢B%%,¤8¶Å-RRÄ&N’JPH‚˜©$¦0*N ¢¦@©¡‰åLAJáDµ„ÌéÞˆèaÏà’­.ØÐ)4á;FÐÌwS RR7öPRµÐèðAq$ê’’¤( §Q¥'Ù)4ö<ªûÄð¥¼Äp…)1ŠzŸ¸y %, îTÔÉIL)Ûô›ñLS·éŠJÿÐõ À-®Hh9:B*p’š­µäíûψ] 'ÁÊ/©§^’Mi` jÞèZkªåÏw-ñâšàNŸr‹\[æ;¨ ·ŽÈª¯ø¥ð×ȦpÏâ“@:ŸŸ‡Í;aÚe-PÁû»iñþ šâ>ӹö°†I5=üRµÀi³e†Zc]R*;sLeLqª+QÔ¡'€S´"¥m>xéü{~îB#L(=‡é RPaÝ<¨¦ŸšJd\'B¡¸ÊS%1I4ÊR vL’HHÂS‘ªgRhvW·îIމµO ŠV”’NRRì0QbP;«H¡M sóB"Ý¡MÙ ¥‡ŠNÔ$Te)!¢~uKD”ɲ’a!8’”Tù¨IN<RŽ…)ND4Ú„”É„ÏÁâ¡T’|/¥£Á@‡ܤ[¯´ü“µÎ:8AAV±Óø¨“þå'p†Z\’˜—Jb%OgŠpÐ8 )dãH>)yL )#]*ÂJvé¢gd$¥J“]: ÊzÉÞߊ*ÿÒõ"œ'„´IMBv½ÝŒ“äS'ˆøjˆö“«u“$|PøãD• ÔèâöÎâ>Šq kó„šÐN†%",R-…‡|íŽ|~* -$5ÚvÍkwGj úæ4=Â@RèÞ`ö–˜~£³’sžÃÔv*mß·e‚Aàò•Ø.{| ›bË%ã]4£!º ®Þ£T¤v#ÇU$OÄ ¸x‚ºŽ<û]äSBq´ö•$F D÷C$¨Ä'ö» JBZ QœÂ ¤†0‘N’JXb‘ú=y”Y ”³Æ¾J;B“‰&P÷š*d[¢ŽÀuR™Mº{$¥ƒ@:…/M´òH;X)äq))oLø¤æ¤< d”Äéª`uR%8%%- ržtQïªJMPö©8ÂLЙå5HÜò /SŽ<Êg‰×ÅGo‚KÅR^Ê$j¼j‘ ,b0žéÑRД'Ne% -{í“àÛ^{§p#à™#pƒäŸM¿3Ô™Sw OiEOÿÓõB£2T»(ªIû~äÑå¬ê —¦ZýÍ:H3ÏÅHµÄ{¾ÿõRŠ)-1ù¼|Ü`öS-wÏÇÅD5ú‚Ùo ø%g²—2è3'H1à›ysŒˆ#_LC¢Ô}Ä%¼~“N…½ÂWàªX¸»Èxz@¹¦[¢E½Útí✰íkâÕ’ã]—‡´:…Úÿ¢=±ÉîTZ2tx©;l€ñð=¾%ÑhK»*ìÞ OÒ<ÐÉ…6† |ÛÀʃþ‘D"Uz,IHÉ"µžâMyî˜% )“žbí @tIKº§4ÈÕª;J;\Ø?‘%#lÊ#] 'Í1²*M n;˜ã¢$i:vAIviÊŽÃ<ÀM½Éo!.Xï¶™Mê‘Ù!o’Jfî`¦<§õGÀ§õ[ ¦ jÝQƒ¾‰÷0ø%jDÑ:ƒñ”äó‘\ö”ûX~=’µ2!ØuSÜ’…š6y() qìTÚw5 ÓîO¶Ž(ZãU¶«ƒt·–¸ƒÇb¢`ëãÈHÇ¿Ò%TÌŸ÷¨¹Ð<Ê‘<ùy ëÉDÕk èSu¡ÊRŠ“îj¡¹‡ºˆ|y§;]¨å%+”Jù§äƒ¨OQý#~ô”ÿÿÔõ9ì˜@ΡLx)R’J—d)Žé÷;Å%2I{‡yKÔw€IrD¤¨zžI '´$¤°!6ÆøÁá>à’Õ‹à ãX\tð(±ÜÿrIuBNÇ·Yh#ä%+Ûï'æQMU‘´ñÇ?êäÏlû†¾)  > P x¤ZB+JÀ§'DÉ$…¥$ˆQ˜IIâÓ(Ís^<|•dí$ R“šãÏÉ@€8áH<ížý”` JP œÕ&µÍ>#²wp’‘AHƒ Iå"Ñ$T x$¤z'D$Äæ Ÿô¾&©”§sÜ[óM ÃJ ^žàð?*#"'à†µ8zRWk]>á¨R-žLGtÎ.<ø£HHêšxçÅCJþ—?Š•oŸiù(ÜÏÏ4¶àíyC{`ùÜj¤Næ#ªu °I"’ ]<¨ðrJf lÚ\9„ § )ÿÕôrSLR!2rBF>yå!1¡ºž"#H#DTD¨©¦"PP,S€”'ID¨rp’´x!ÛPp™ÚGïEL’£h8féHÿz›sdk؄΢êôžZš štàÇš ÍHCUoßF§´£¸m@OcH÷7žêáä€é#‘)-‘½U p‘÷¦ €—¦ö™O$‹œ –ü £h`éà¨Â) pP-#„TÇ… £>*`hŠ—„Ú; P'Pe$cˆ~ð¦D„"%>çèxÔ¤¥ö•§iI¶nçB¦xÕ%#k¤øåÀr RN–»]÷7ÎâTÃZ8î“¢G’-§¾Ÿá sÏÜ‘?$À”Ëp~&Ü{&Ñ"4IL¦yL9“âŸD”ËV¥$üT`ÿ N$h{"¥æ £4‡·ÇÅJ²di<„ ˜º¸0~I¶ÇøVÐà‚ATAR77ÁE…ØÕ%- Úg¶ªLýÐO—Pd×ËEŠ “¤øx¥ªEuI]Õ¿ƒ»O)ß[\5UþÍh3¡Ž0‚ õØÀr4Ÿ–¨Z©ƒë±†~L×€¬ƒ"uGEÒÇò ø„PñN9ެh%£„=Ä¢¦nÙ ˜‘ß”·O(z©4”ÈÈQ"T:#jPq]S²Àí‡ðCsàÄIM¸Ú 4Ù8hº ÷* »x%¤hœ;uqÁáaiÜ5&¬›Ý>ç4×åüRÜæöÕ@–kô?šå;$°O:J¿‚6XÜ&:ø”™×ÊS8:„Çqƒ¡JÓQ> ýjr>!H[^‚yãB´‰ sÄ„ yŸîET:É{.âSoa0Ì*»ÝÀ2ѤTÛÇÄNˆX)öäÙŸ4úª­{f€ySkKl®ö¸Á'„[(‘ºmS„’E [6¸ü¾äàØ ™sâJN HçÇÇ_ö(–‘ñLæÁ„ä¸ë2~I)e&»MIÂ5ìÚí[£‡-ELæS±ûH‚ ‚]ü»„–ê½FéôÛ«J¬Z?¹Z­óíðá ê\×úŒïÈóL!!zÿ ã$p|B“ž„j…<¡"¸zÜ>ä"‰Ì=”Zã¶$¢µ®áÝJ¿¦SÿÐõ7ý«N¼ð¬»…T;ø"¼öwȧ"5ãÆRžÝÇ np>H©SÂŽ„È'æ”ÁÐià”€IïIL÷8D’AÎý⣠¶"o>Ǒ撙›,å¾CTþ­ƒ^T»PaÃñKã¢Jgëè{Ü9×ħR©5•‡jÞB: Oì~ôö3]Þè!ØI‘ÏtÌaqÐpµÄpS†8„’$B'°?ßæ–¤Üꕲ_øŠ- >(÷c´µú„ÂZÞvˆ#Ä'ƒR4 ÷L@>æ¦ø)`$hª‚“Gï|C€wðø¢1Í"†“䪊堎Lù¨èæ–€¢ç9°ñgxçò¢Vö‡p]ßûÓ­[jÖs9¿0›à­YQ'syîvq"'€šC0˜¤a»ÎÑÊ=<ðD2¤ÏH°†ˆRcD’<‚ SåFIœa¤øT¡Bã;àŠÆ |T›ÉòwáK‚8!8)a®…3uööð)ÈÛæÓÁL[ùÄT KLr“%´‘3îçýéH#Q¯t”¿Šq ë÷¦2SÉî‚” 8v#…`æøøªîòRªÈ0x?•"§¶º¨ KcÜs Ùí0á©ÛDÈÛc»ÇõT©'ÕhøŸÁ ç[ð))ÿÑõC®u4V ³9òóD)y:ýÓàu ÝÆ‰Ñ(©„Ÿ÷¤$òŸOívM¤"¥Ú[0N¾ZÁ?¶`TÍßÉóÿbwÄ~IILµn°Ÿp<… ÷Αü¶}œ$¥æBr4öžT[Ê‘„°ähG!¿ fÎó·ÎUŠø)­ooõ{{ -œ ñþC$‚ ‘º5¦3þº)ëÙDJIÕ˜⥻OÈ£ÛDåÊ ÷%¼Á$(‰S>v¾!%#õNé O‚)—·ufu}ÿ%üž{B V§éHw Ú\9ûÑDíý$'D¼ kªz2-cƇk’ôÅ¿úð¤"; Ú‘}ÚÜÂv˜þI~Tà°Lýæù¨¾$Ï’oÉ(iÝ'­î·  žDø(XàêÝZyñA~Ý6Ï©òþÊ“÷ú˜õc·=çù)ëEh½A®%¤îÂ{y+5ýæO?‚¨ÈÞ7Dvþô•ºþ€ü~=Ò –ìï?£ù¢!ÝÛæ’Ô tÒ5•9ž~hLÞÞÇ:~ Ê\ÙQà›ÛÄG’sƼ¤"?*JPlqª~xì˜D”ãñî’–„„‚NãÍ.âxî’—&DýéÃá HìNŠmôàmŸ*GËŸ>Rì ™>*µà6ÉiúZŸŠ{}~ÿGù(ZvAJD£ùÖü -?ηàRSÿÙdeal319/html/holding.html0000644000175200017520000001256011341325567013561 0ustar cbecbe Holding Procedures

Holding Procedures in Deal 3.1 and iDeal

Introduction

One of the main new bridge evaluation features in Deal 3.1 and iDeal is the ability to define fast procedures for evaluating a single holding.

In Deal 2.0, we were able to define Vector functions, which assigned integer values to each card. This covered a lot of standard evaluation techniques, but not the more complicated forms. Evaluators like "quick tricks" and "losers," while still computed suit by suit and totaled, cannot be defined by assigning values to cards alone.

The solution is to allow the creation of general procedures for evaluating a holding, while still taking advantage of fast lookup tables. Thus, the introduction of the holdingProc command.

The holdingProc Command

holdingProc looks like a normal Tcl definition of a procedure. For example, we might write:
holdingProc HCP {A K Q J} {
    expr {$A*4+$K*3+$Q*2+$J}
}
to define a function called HCP. This function behaves exactly the same as the builtin hcp routine - the user can ask for the total points in a hand or for a specific suit in the hand:
set n [HCP north]
set hs [HCP north spades]
When evaluated, the parameter A is set to one if the holding has the ace, and zero otherwise.

That's a simple example, but let's say we want to do some smart reevaluation. For example, we might want to add a point for each card in a suit beyond the fourth. We also might want to evaluate a stiff king as two points, rather than three, a stiff queen as zero, and a doubleton queen as one.

We can do this by adding a "length" parameter to the parameters list:

holdingProc SmartHCP {A K Q J length} {

    if {$length>=4} {
        # Normal evaluation, +1 for each card longer than the fourth
	return [expr {$A*4+$K*3+$Q*2+$J+($len-4)}]
    }

    if {$length==3} {
        # Normal evaluation for 3-card suits
	return [expr {$A*4+$K*3+$Q*2+$J}]
    }

    if {$length==2} {
        # Jacks in doubletons are worth zero, queens one
	return [expr {$A*4+$K*3+$Q}]
    }

    if {$length==1} {
        # Queens and jacks in singletons are worth zero, kings two
	return [expr {$A*4+$K*2}]
    }

    return 0
}
Even though this code is slow, it is only evaluated at most 160 times, after which values are reused, yielding remarkably fast evaluations. One deal, you might get a holding of KQ75 which this routine evaluates as if it were evaluating KQxx. The next hand, it sees the holding KQ82 and, seeing this also as KQxx, remembers the previous value.

Types of Holding Procedures

By default, the holding procedure assumes that the values returned are integers, so that when it tries to add up the values of all four suits, it applies an integer sum.

If you want the return value interpreted as a double, you can specify it in the declaration. For example, we can define a quick tricks procedure:

holdingProc -double QuickTricks {A K Q J T length} {
    if {$A&&$K} { return 2 }
    if {$A} { return 1 }
    if {$K && ($Q || ($J && $T))} {
         return 1
    }
    if {$K && $length>1} {
            return 0.5
    }
    return 0
}

You can define the type to be any of the following:

-integer
The default, adds integer values when evaluated across multiple suits.
-double
Adds resulting values as doubles when evaluated across multiple suits.
-boolean
When evaluated on a hand, lists the suits, by name, which evaluate as true. For example, if you defined 'biddableSuit' it would return the list "spades hearts" for the hand KT954 AJ32 94 92.
-string
Returns a list of values when evaluated on multiple suits.

Arguments Allowed

The arguments are interpreted based on the first character of their name, or, in the case of spots, via the idiom 'x.' For example, we could have defined SmartHCP as:
holdingProc SmartHCP {ace King QuizShow j len} {
      ...
}
They can occur in any order.

For spot cards, you can use arguments named "x2", "x3", "x4", .., and "x9." The ten can be passed as "x10" or "T."

One last possible parameter is anything beginning with an "s" or "S", which means that the holding is passed as a string. This is useful when you already have a hash table somewhere for stored data. For example, the 'ddeval' code which comes with iDeal and Deal 3.1 uses a table of raw data created in advance.


Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

Plane Dealing graphic above created using POV-Ray.

deal319/html/reference.html0000644000175200017520000005000411341325567014066 0ustar cbecbe Deal - New Features in Version 2.0
Plane Dealing image

Deal 2.0

Reference Guide

Covering:
  • Command line arguments
  • Additive Functions
  • Shape Functions and Classes
  • String Boxes and formatting
  • Often used Tcl features
  • Library routines

Command Line Options

-e expr
Evaluate the Tcl expression expr. Not very useful, but occasionally good for setting variables which affect the user's script, like:
deal -i userscript -e "set maxnorth 10"
-v
Verbose mode. Lets you know how many hands have been accepted and how many hands have been tried.
-[NSEW] hand-spec
Specifies the cards held by the specified hand. The hand-spec should be of the form: "AK8532 - KQ72 A65". Voids must be represented with a '-' character. hand-spec should be one argument, so the string should be quoted on the command line.
-i file
Source the commands in the file named. The language used is "Tcl". Read the man page for Tcl for help in writing Tcl code. Additions to Tcl specific to deal are listed in this manual.
-x file
Like -i, except execute this file and then exit.
-f
Instead of dealing new hands, reads hands from standard input. The hands must be in the format put out by "deal -l". You might deal, say, 10,000 hands which satisfy specific criteria, saving them to a file. Then you can use that output for input with deal -f to find out which hands satisfy other constraints.
-t
Print distribution table and exit. The distribution table is an ordered list of all possible hand patterns for a single hand.
-l
Write deals in a "single-line" format. In previous releases this was the default format. It is useful for piping to formatters written in other languages. Most formatting can be defined internally, using Tcl now. Still useful with the "-f" option.

Simple Usage

The most basic usage of the program is to generate random deals with no conditions:
% deal 2
	  S : QJ9
	  H : AJ
	  D : T52
	  C : AKQ84
 S : 752            S : AK83         
 H : T85            H : Q632         
 D : AK8763         D : J4           
 C : 2              C : T96          
	  S: T64
	  H: K974
	  D: Q9
	  C: J753
---------------------------
	  S : QJ9
	  H : 52
	  D : AKJT9
	  C : A86
 S : 763            S : A52          
 H : T763           H : J98          
 D : Q54            D : 876          
 C : T95            C : KQJ7         
	  S: KT84
	  H: AKQ4
	  D: 32
	  C: 432
---------------------------
If you want a raw format, more readable by external programs, use the -l flag, which prints deals in a single-line format:
% deal -l 5
K75 T987 AQT5 95|AQ86 2 943 QJ643|JT32 J43 KJ KT82|94 AKQ65 8762 A7
QJ96 KQ6 T95 K76|T5 J953 A72 AJT9|8432 A7 83 Q8432|AK7 T842 KQJ64 5
K52 QJT9 AKQ K63|AJ AK7542 T732 8|94 3 J965 QJT972|QT8763 86 84 A54
A76 A764 43 KJT2|J9 KJ53 K986 A87|K8543 T82 72 953|QT2 Q9 AQJT5 Q64
Q6 QJ75 3 AJ7642|AT9874 KT963 AT |K32 4 QJ2 KQ9853|J5 A82 K987654 T
This output form is crude; it is meant to be post-processed. Each line is of the form:
"North|East|South|West"
Each hand is specified by:
"Spades Hearts Diamonds Clubs"
where the space character separates each suit. In the examples above, the east hand in the last deal is:
"AT9874 KT963 AT "
which might be written more verbosely as:
S: AT9874   H: KT963   D: AT   C: ---
I've included three formatters with the package, one of which creates a TeX file for the hands generated, the other two simple text files. The formatters are Perl scripts, so if you don't have Perl on your system they won't work. To format, you just run deal with the -l flag, and pipe to the formatter:
% deal -l 5 | perl ./compactdeal
Deal # 1          - AKQT43 AKT65 A3
JT65 82 QJ32 752                    AKQ82 6 94 KJ984
                  9743 J975 87 QT6
------------------------
Deal # 2          3 QJT43 A8742 K4
QT4 86 T93 AJ973                    AK52 2 QJ65 T862
                  J9876 AK975 K Q5
------------------------
Deal # 3          A76 KT9 QJ84 K53
T952 A832 A95 Q8                    J Q76 KT632 J762
                  KQ843 J54 7 AT94
------------------------
Deal # 4          AQ752 J632 - 8652
6 AK74 A863 AKT9                    KJ98 Q95 J752 QJ
                  T43 T8 KQT94 743
------------------------
Deal # 5          A4 AJ72 852 AKQT
63 T9654 QT9 865                    QJ852 Q J764 J94
                  KT97 K83 AK3 732
------------------------
% deal -l 2 | perl ./formatdeal
Deal 1         S : 75                     |
               H : Q4                     |
               D : QJ962                  |
               C : AT64                   |
     S : KQ63           S : J98           |
     H : K732           H : T985          |
     D : K75            D : A843          |
     C : 83             C : J2            |
               S : AT42                   |
               H : AJ6                    |
               D : T                      |
               C : KQ975                  |
-------------------------------------------
Deal 2         S : AKQJ                   |
               H : J43                    |
               D : KQ4                    |
               C : 762                    |
     S : 73             S : 9865          |
     H : QT76           H : AK82          |
     D : J972           D : T86           |
     C : JT4            C : A9            |
               S : T42                    |
               H : 95                     |
               D : A53                    |
               C : KQ853                  |
-------------------------------------------

Putting Conditions on the Deal

There are two distinct types of conditions which can be placed on a hand.

One is the rigid placement of cards, as in, `South gets the ace of clubs,' or `East is "AK52 AK32 9652 6"'. Card placements are done before any randomnizations.

Card placements are ignored when using deal with the -f option. This is because `deal' is reading already built hands.

The other conditionals are evaluated conditionals, like "South has at least 4 hearts" or "West has 11 to 15 HCP" or "North has exactly one of the ace and king of clubs."

The flow of control is:

  1. Place known cards
  2. Deal rest of the cards at random
  3. Determine whether to accept or reject deal. If rejected, go to 2.
This is less than optimal in many ways. The optimizing problem here is pretty painful, though, and, although I have some ideas for solutions, I'm trying to be careful to do it right; in the meantime, this method will have to do.

Scripts use the Tcl language, with bridge-related additions. To understand these scripts, you should read the Tcl man page.

An example script (ex/1.tcl from the kit):

##############################################
# Look for deals where north has 44 in the majors, a short minor,
# and 11-15 HCP.
# To execute:
#       deal -i ex/1.tcl [num]
##############################################
main {
                                          # Pitch deals
                                          # where north does
                                          # not have four spades
        reject if {[spades north]!=4}

                                          # Pitch deals
                                          # where north does
                                          # not have four hearts
        reject if {[hearts north]!=4}

                                          # Pitch deals
                                          # where north has
                                          # 2 or 3 diamonds
        set d [diamonds north]
        reject if {$d==2} {$d==3}

                                          # Accept deals
                                          # where north has
                                          # 11-15 HCP.
        set hcp_n [north]
        accept if {$hcp_n>=11 && $hcp_n<=15}
}
##############################################
The "main" command defines the expression which is to be evaluated to ascertain whether a deal is accepted or rejected. This occurs after all cards have been dealt. If the hand is never explicitly accepted, the hand is rejected.

We can run this example as:

        % deal -i ex/1.tcl 10
This will produce ten deals where north has a mini-Roman hand with a short minor.

"deal" takes a "-v" flag which lets the user know about progress in the hand generation; how many hands have been searched, and how many have been checked.

% deal -l -v -i ex/1.tcl 5
KJ92 AQ42 7 K842|8 KT9763 A862 95|Q73 J JT94 QJ763|AT654 85 KQ53 AT
Deal 1 found after 61 tries
AJ62 AQ84 9 J764|K84 J2 875 KT932|QT T73 AJ643 Q85|9753 K965 KQT2 A
Deal 2 found after 269 tries
JT86 AQJ8  KQ543|9 T9432 542 A976|K7532 K6 KQJ7 T2|AQ4 75 AT9863 J8
Deal 3 found after 303 tries
A652 AT94 A985 2|3 QJ532 T63 J543|QT74 8 K7 KT9876|KJ98 K76 QJ42 AQ
Deal 4 found after 394 tries
AJ65 9743 K AJT8|T742 T6 T764 972|KQ83 AQ5 Q32 643|9 KJ82 AJ985 KQ5
Deal 5 found after 523 tries
The progress output is sent to "stderr", so you can still pipe the hands to a formatter or file without trouble.

You can specify on the command line that you want South to hold a specific hand:

        % deal -v -i ex/1.tcl -S 'AK52 42 K52 7642' 10
Here are some of the procedures built in to the program which have been added to Tcl for Deal.
accept
Accept the current deal. Use only from "main".
accept if expr [expr...]
Accept the current deal if one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.
accept unless expr [expr...]
Accept the current deal unless one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.

reject
Reject the current deal. Use only from "main".
reject if expr [expr...]
Reject the current deal if one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.
reject unless expr [expr...]
Reject the current deal unless one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.

spades hand, hearts hand, diamonds hand, clubs hand
Returns the number of cards held in the suit by hand hand

controls hand [suit]
Return the number of controls (A=2, K=1) held in the suit given. If no suit given, the total number of controls.

hand is hand-spec
This places all the cards of one hand. The hand spec looks like:
"AKQ - T642 QT9876"
The format is pretty inflexible. Example:
east is "AKQ AKQ AKQ AKQT"
This is the same as saying:
-E 'AKQ AKQ AKQ AKQT'
on the command line.

hand gets card [card...]
Places individual cards in to the hand. Example:
north gets AC
places the ace of clubs in the north hand.

hand has card [card...]
Checks to see if the hand holds the specified cards, e.g.
if {[north has AC]} {...}

hand shape
Returns a string of the 4 suit lengths, in the order S,H,D,C, e.g.
puts stderr [south shape]
4 3 2 4

hand pattern
Return a string of the 4 suit lengths, sorted in descending order:
puts stderr [south pattern]
4 4 3 2

hand
Return the HCP total for the hand, e.g.
reject if {[north]>=16}
[Design note: this treatment might go away. I have serious problems with making high card points so prominent, and [south] might be better used as a method of extracting a tcl list like: {AK} {QJ65} {T9872} {53} . If I were to do this, I would add a function, hcp. Of course, you can implement the hcp function yourself with defvector. ]
defvector name val [val ...]
A vector is a fast counting procedure. The "vector" for counting HCP is (4,3,2,1,0,0,0,0,0,0,0,0,0). We can define
defvector Hcp 4 3 2 1
and then use "Hcp" as a procedure later:
reject if {[Hcp north]>=16}
Or
defvector Top3 1 1 1
creates a procedure for counting how many aces, kings, and queens are held.

One nice thing about these routines is that they are fast. Clever use of vectors speeds up all sorts of evaluation routines.

vector suit [suit ...]
Counts the hand using the vector. If a list of suits is given, only those suits are counted. Otherwise, all suits are counted. E.g.,
defvector AKQ 3 2 1
AKQ south hearts spades
counts the Ace-King-Queen points held by the south hand in hearts and spades.

shapeclass name { code }
This, like defvector, is an optimization issue. E.g.,
shapeclass michaels {return [expr $h>=5 && $s>=5]}
main { accept if {[michaels north]}}
A shapeclass generates a lookup table the first time it is called, and fast shape matching occurs each time after.

shapecond name { expression }
This is just a shorthand for:
shapeclass name {return [expr expression] }
definedclass hand
Returns true if the hand is in the shape class and false otherwise.

definedclass compile
Returns a string of 0's, 1's and whitespaces for faster shapeclass reuse. Really for my personal use, but included here for completeness.

shapeclass.binary name { bits }
This is how to define the "compiled" form of the shapeclass definitions, only really useful for shape classes which are reused often.

balanced hand
Returns true if the hand is "balanced" in the classical Goren-style: 4333s, 4432s, and 5332s with 5-card minor. This could be implemented as a shapeclass, but there still remains an internal definition which is pretty fast.

losers hand [suit ...]
Returns the number of losing tricks for the hand, or, if suits are given, the number of losing tricks in those suits.

You can, of course, create new routines with Tcl, and then call them from the "main" procedure.

There are many examples in the kit; look them over. There is also a file called "library" which defines some useful procedures.

Hints

Clever use of count vectors can solve many problems efficiently. For example, if you and your partner play that a weak two promises 2 of the top 3 or 3 of the top 5, you could define:
defvector Weak2Quality 2 2 2 1 1
This vector evaluates to 4 or greater whenever the suit has the right quality, so we could check for a weak-two spade suit with:
reject if {[spades north]!=6} {[Weak2Quality north spades]<4}
The program doesn't do much optimization, but you can do some yourself. Try not to use logical conjunctions in "require" and "accept" parameters. It is better to say:
accept unless {[north]<13} {[hearts north]<7}
than to say:
accept if {[north]>=13 && [hearts north]>=7}
That's because the {[hearts north]<7} expressions doesn't get evaluated if {[north]<13} evaluated as true.

It is even better to do:

accept unless {[hearts north]<7} {[north]<13}
Why? Because you are eliminating more hands initially. (Also, the suit-length functions are faster than most since the numbers are incidentally calculated at deal-time.)

Automated optimization is another area which I'm considering for later versions of this program.

Who to Blame

Questions, comments and great thoughts are welcome. Just send me email at the address at the bottom of this page.
Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2005. Deal is covered by the GNU General Public License.
deal319/html/quickstart.html0000644000175200017520000005477511341325567014345 0ustar cbecbe Deal - An Introductory Tutorial
Plane Dealing image

Deal 3.1

An Introductory Tutorial

Covering:
  • Dealing hands
  • Stacking hands
  • Output formats
  • Basic scripting with Tcl

Prologue

First things first, you will need to download Deal and build it. The rest of this tutorial assumes you have already done this.

**Warning** It takes careful eyes, at least on the version of Netscape I am using, to distinguish between normal parentheses, (), and curly parentheses, {}. Almost all of the parentheses in the script listings below are curly parentheses.

Deal only works from the directory where you did your installation, because it looks there for files that Deal uses.

Basic Dealing - The Command Line

Basic Dealing - Scripting

Basic Dealing

Dealing hands

At your command prompt, you say, ./deal. By default, this deals ten hands. If you give deal a numeric argument, it will deal that number of hands.
$ ./deal 2
          S : T6542
          H : A4
          D : A93
          C : KT2
 S : Q83            S : K97          
 H : 9873           H : K52          
 D : JT7            D : Q64          
 C : Q74            C : J863         
          S: AJ
          H: QJT6
          D: K852
          C: A95
---------------------------
          S : ---
          H : 975
          D : AT986
          C : T9753
 S : J7             S : AKT6         
 H : T32            H : KJ864        
 D : K32            D : J74          
 C : AJ842          C : 6            
          S: Q985432
          H: AQ
          D: Q5
          C: KQ
---------------------------
$
Deal dealt two hands, as requested.

Stacking a hand

Okay, let's take another example. Say you opened 3H on the following hand in a team game:
S: ---
H: KQJT62
D: T9876
C: 84
You stumble into a six heart contract, when in fact, six diamonds has better play opposite partner's hand. Partner swears that opening 3H with this hand loses more often than it wins. You disagree. How do you resolve this?

Deal can help. Just run it as:

$ ./deal -S "- KQJT62 T9876 84" 25
          S : KJ2
          H : 954
          D : A5
          C : AKT65
 S : T9764          S : AQ853        
 H : A              H : 873          
 D : J2             D : KQ43         
 C : QJ973          C : 2            
          S: ---
          H: KQJT62
          D: T9876
          C: 84
---------------------------
          S : KJT64
          H : 5
          D : K42
          C : AQ65
 S : 9875           S : AQ32         
 H : A93            H : 874          
 D : AJ5            D : Q3           
 C : KJ9            C : T732         
          S: ---
          H: KQJT62
          D: T9876
          C: 84
---------------------------
	.... (rest of 25 hands ellided) ...
You inspect the 25 hands dealt, guessing how the auction would proceed. Sometimes, your answers will be inconclusive, but more often one or both partners learns something from the simulation.

There are, of course, also -N, -E, and -W options for the other three seats.

Formatting output

Perhaps you'd like the hands to be written in some other format. This can be arranged fairly easily.

For example, suppose you wish to deal 8 hands for practice bidding with partner. In that case, you would use the "practice" format:

$ ./deal -i format/practice 8 > out.all
$ cat out.east
                              east hands
============================================================================
     *1*                 *2*                 *3*                 *4*
  S 84                S T7                S QT3               S AJ9654
  H J8642             H Q65               H Q983              H K8
  D Q843              D KJ42              D 865               D J
  C 73                C T842              C AJ9               C K532

=============================================================================
     *5*                 *6*                 *7*                 *8*
  S J7                S 85                S AQT764            S 3
  H Q9864             H AK4               H K5                H JT4
  D 874               D A764              D 9                 D QJT86
  C J85               C Q862              C T976              C AK82

=============================================================================
The -i flag tells Deal to include the named file, in this case, the file named format/practice. This file redefines the output format. At the end of this run, you should get five files: out.north, out.east, out.south, out.west, and out.all.

Now you can print out these files, pass them out amongst four people, and practice your bidding, using out.all at the end to make a double dummy assessment of the auction results.

What if you only have two people, and you want to practice uninterrupted auctions? You could print out the north and south hands, and practice with those, but that would be an artificial test, because you obviously can't assume an uncontested auction for arbitrary deals.

When we learn about writing scripts for Deal, we will solve with this problem by filtering out hands we think would lead to competitive bidding.

What are the formats that come with the kit? Well, you can simply list the format sub-directory to find out. Here are the ones there as of this writing:

none
This script set the formatting routine to a null routine. Not useful, so far, but useful, for example, when doing statistical analysis.
numeric
This formatter writes the deal as a line which looks something like:
3031333123220300123320212213021202022103101101003113
It's a line of 52 numbers, where 0, 1, 2, and 3 mean north, east, south, and west, respectively. The first digit tells where the ace of spades goes, the second digit tells where the king of spades goes, etc.
okb
This formatter writes the output with the same spacing as the old OKbridge screen.
practice
We've just seen this one - for seperating out hands for practice bidding.
There is one last output format, which, for historical reasons, has its own command line switch, -l.
$ ./deal -l 3
AJ9 976532 K92 A|86 A AT87 987653|Q732 JT8 543 T42|KT54 KQ4 QJ6 KQJ
K94 J93 QJ3 7653|A8 A8765 97 KQ98|JT2 Q AKT8654 T4|Q7653 KT42 2 AJ2
KJ753 T A4 KQ932|AQ94 AJ92 QT87 J|86 Q764 K9653 74|T2 K853 J2 AT865
$
In the past, this was the only way to get alternate formats. The user would pipe this output to another program, usually a Perl script, which would parse each line and format the output.

With the addition, in v2.0 of Deal, of user-configurable formatting, this usage becomes obselete, but I'm leaving the feature because it has one other use, which will be mentioned later.

Basic Dealing - Scripting

Our First Script

Let's say we want a selection of deals in which north holds a one spade opener. For now, we will use a crude definition for an opening 1S call - we will require north to have 5 or more spades and 12 or more points.

Here is the script we write (to a file we'll call onespade):

main {
  if {[spades north]>=5 && [hcp north]>=12} { accept }
  reject
}

Running the script

We run this code by saying:
$ ./deal -i onespade 2
          S : AKQT5
          H : A7
          D : 8542
          C : AT
 S : 64             S : J98          
 H : K943           H : 862          
 D : J              D : AK963        
 C : KQ8732         C : 54           
          S: 732
          H: QJT5
          D: QT7
          C: J96
---------------------------
          S : AQT73
          H : A
          D : AJ987
          C : 73
 S : K5             S : J42          
 H : JT8632         H : KQ95         
 D : Q63            D : KT4          
 C : 85             C : K92          
          S: 986
          H: 74
          D: 52
          C: AQJT64
---------------------------

How the script works

By default, Deal accepts all hands. With the main code in onespade, we tell Deal to override that behavior.

This is similar to the way we used scripts to override Deal's default formatting. Note, we even use the same flag, -i, to load our formatters and onespade.

What does this main code do? It is run after every deal is complete, and used to evaluate the hand. In this case, we have only two lines of code:

if {[spades north]>=5 && [hcp north]>=12} { accept }
reject
The expression [spades north] returns the number of spades in the north hand. The expression [hcp north] returns the number of HCP (high card points) in the north hand. The "&&" is called a logical "and" operator, which returns true if the conditionals on both sides of it are true.

If the entire expression:

[spades north]>=5 && [hcp north]>=12
evaluates as true, the "accept" function is called. This causes Deal to exit the "main" code and format the hand.

If the expression evalutes as false, Deal goes to the next line of code, which calls the "reject" function. This tells Deal to discard the hand, and exit the "main" code.

Deal keeps trying until the requested number of deals is accepted.

What happens if a deal is not explicitly accepted or rejected? If neither accept nor reject is called, the deal is rejected. That means that in our first script, the reject call was redundant, and we could have simply written the script as:

main {
  if {[spades north]>=5 && [hcp north]>=12} { accept }
}

Monitoring Deal

You might want to try running this script with the -v switch:
$ ./deal -v -i onespade
The -v flag tells Deal to give a progress report, which looks like:
...
Deal 1 found after 2 tries
...
Deal 2 found after 21 tries
...
Deal 3 found after 31 tries
This will give you some idea of how rare your condition is, and also gives a good progress report when Deal is writing to a file or running with a "silent" format, like format/none. These status messages are written to "stderr", which means that the output from Deal can be redirected to a file without obscuring these messages.

Using formats with your script

If we wanted to use another output format with this script, we could do so on the command line, as follows:
$ ./deal -i format/practice -i onespade
Or, alternately, we could add an explicit "source" command to our script:
source format/practice

main {
        if {[spades north]>=5 && [hcp north]>=12} { accept }
}
In fact, this second format unveils the secret of the -i flag - it is simply a request to "source" a file. In fact, if you were to write your own formatter, you would not have to put the file in the "format" directory. If you put it in the current directory, you could then say:
$ ./deal -i myformatter 100
and it would work fine. The "format" subdirectory is just a convenience. You will often want to re-use a format, and placing them in one place lets you find out which formats are available.

Stacking hands with a script

Let's say you were dealt the hand:
S: ---
H: 98532
D: A864
C: T962
the previous day at a Swiss Teams event.

Your partner opened 1S, and, playing 2/1 Game Force, you chose to pass. This turns out well for you on this deal, because at the other table, the opponents played in three spades, down 1. Afterwards, you wonder if you really made the right decision. Your intuition tells you that it was the right choice, but you realize there are risks in both passing and bidding, and you know that intuition is very bad at assessing levels of risk.

Deal can help. Using our script, onespade, we can run the following simulation:

$ ./deal -S "- 96532 A864 T962" -i onespade
The -S flag stacks the south hand with the hand you held, and the script runs exactly the same thereafter. You can now peruse the output to see whether it was a good idea or a bad idea to pass.

As with the formatting, we can also do our deck-stacking in our script.

south is "- 98532 A864 T962"

main {
  if {[spades north]>=5 && [hcp north]>=12} { accept }
}
Notice, we do our deck-stacking outside of the evaluation loop. Remember, the main expression is responsible for evaluating the deals after Deal finishes dealing the hands. We obviously want the stacking instruction to occur before dealing occurs, so the stacking command must be outside the main evaluation.

A partial list of routines

For evaluation routines, we have seen the hcp and spades routines, as well as the "accept" and "reject" directives. Obviously, there are also routines called hearts, diamonds, and clubs which count their respective suits. The following functions are also built-ins:
controls
This function computes the number of controls held by a hand.
losers
This function does a crude computation of the losing trick count for a hand (it actually compute's half-losers, so when [losers south] returns 14, that really means 7 losers.)
balanced
This function returns true (1) if the hand name passed is balanced in the usual sense - no shortness, at most one doubleton, and no five-card major. It returns false (0) otherwise.
semibalanced
Returns true (1) if the hand passed has no shortness and no six-card or longer suit, and false (0) otherwise.
The three functions, controls, hcp, and losers, all have the property that we can compute them one suit at a time, and sum the result for the entire hand. The implementation takes advantage of this and allows the user to request these values for specific suits:
main {
  if {[hcp south hearts spades]>10} {accept}
}
This script accepts a deal if south has ten or more points in hearts and spades. controls and losers can be used similarly. Any function of this sort we will call "additive." We will see later that we can define a wide class of interesting additive functions.

The functions balanced and semi_balanced are entirely dependent on the shape of the hand, and not on which cards the hand holds. We will call these "shape functions." We will find out later how to define incredibly fast shape functions.

A Second Script - defining Tcl procedures

Let's say we want to write a script which accepts a deal if north has a strong notrump (15 to 17 range) and south has about invitational values and a 5-card major.

Our script , which we will call jacobytest might look something like:

# In deal 3.1, you don't need this next line, but deal 3.1 does - 
# without this line, the "balanced" routine is not defined.

main {
	if {![balanced north]} {reject}

	set hn [hcp north]
	if {$hn>17 || $hn<15} {reject}

	set hs [hcp south]
	if {$hs<8 || $hs>9} {reject}

	if {[spades south]==5 || [hearts south]==5} { accept }
}
We have used one of our new functions here, balanced, as well as a new Tcl feature, variables. We could, of course, not used variables, but then we would have had to write the lines:
if {[hcp north]>17 || [hcp north]<15} {reject}
That is going to be slower, with one more function call. Not appreciable today, with a simple query, but when you might be processing a million or more hands at a time, you learn to be frugal.

Suddenly, you realize you want to test this situation with a 12-14 notrump, instead. Or you realize you often want to reuse this concept. You can do so by defining Tcl procedures.

proc notrump {hand min max} {

  if {![balanced $hand]} {return 0}

  set hc [hcp $hand]
  if {$hc < $min || $hc>$max} { return 0}

  return 1
}

proc jacobyinvite {hand ntmin ntmax} {
  if {[spades $hand]!=5 && [hearts $hand]!=5} {return 0}

  set hc [hcp $hand]
  if {$hc+$ntmin <= 25 && $hc+$ntmax>=24} { return 1 }

  return 0
}

set NTmin 12
set NTmax 14

main {
  if {![notrump north $NTmin $NTmax]} { reject }
  if {[jacobyinvite south $NTmin $NTmax]} { accept }
}
You are unlikely to need the jacobyinvite function beyond this script, but the notrump function will be something you will want to use again and again. You might even put it in a library of routines, called mylibrary and source that library every time you need one or more of the routines for a script:
source mylibrary
rather than rewriting the routine every time.

In fact, the Deal kit comes with a file called library , which is just such a library of routines the author of Deal found himself re-using.


Revisiting accept and reject

The directives, accept and reject, can be used in more complicated ways that are sometimes more efficient and sometimes more readable.

Here is the main script from the notrump example using some odd constructs:

main {
  reject unless {[notrump north $NTmin $NTmax]}
  accept if {[jacobyinvite south $NTmin $NTmax]}
}
Some people might find this more readable. The first line says we are going to reject the deal unless the condition is true. The second conditional says we are going to accept the deal if the expression evaluates as true.

Multiple arguments are allowed. The following command:

reject unless {expr1} {expr2} ... {exprn}
runs through all of the expressions until it finds one which evaluates as "true". If it does not find a true value, it rejects the hand. Otherwise, deal goes on to the next line in evaluating main.

For reject if the deal is rejected if any one of the expressions is true. Similarly, accept if accepts a deal if one of the expressions is true. For accept unless, the deal is accepted unless the one of the expressions is true.


This concludes the Introductory Tutorial. I hope it inspires you to check out the Deal - Advanced Guide and to learn more about Tcl. Or check out the index of all deal commands.
Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

Plane Dealing graphic above created using POV-Ray.

deal319/html/quickdos.html0000644000175200017520000005633211341325567013764 0ustar cbecbe Deal - An Introductory Tutorial for Windows
Plane Dealing image

Deal 3.1

An Introductory Tutorial for Windows

Covering:
  • Dealing hands
  • Stacking hands
  • Output formats
  • Basic scripting with Tcl

Prologue

First things first, you will need to download Deal and install it. The rest of this tutorial assumes you have already done this.

**Warning** It takes careful eyes, at least on the version of Netscape I am using, to distinguish between normal parentheses, (), and curly parentheses, {}. Almost all of the parentheses in the script listings below are curly parentheses.

Deal only runs in Deal's installed directory. That's because for now it looks in the current directory for deal.tcl and other library files.

Basic Dealing - The Command Line

Basic Dealing - Scripting

Basic Dealing

Dealing hands

Start Command Prompt window and change your directory to the location where Deal was installed.

C:\> cd "C:\deal30"

C:\deal30> 
The most basic version of deal runs with no conditions set on the deal, and generates 10 deals:
C:\deal30> deal
The output probably scrolled off the screen, so you might want to do
C:\deal30> deal | more
to allow scrolling, or:
C:\deal30> deal > out.txt
which saves the output from deal to the file, out.txt.

If you give "deal" a number on the command line, it generates that many deals:

C:\deal30> deal 2
          S : T6542
          H : A4
          D : A93
          C : KT2
 S : Q83            S : K97
 H : 9873           H : K52
 D : JT7            D : Q64
 C : Q74            C : J863
          S: AJ
          H: QJT6
          D: K852
          C: A95
---------------------------
          S : ---
          H : 975
          D : AT986
          C : T9753
 S : J7             S : AKT6         
 H : T32            H : KJ864        
 D : K32            D : J74          
 C : AJ842          C : 6            
          S: Q985432
          H: AQ
          D: Q5
          C: KQ
---------------------------
C:\deal30> 
In this example, Deal dealt two hands, as requested.

Stacking a hand

Okay, let's take another example. Suppose you opened 3H on the following hand in a team game:
S: ---
H: KQJT62
D: T9876
C: 84
You stumble into a six heart contract, when in fact, six diamonds has better play opposite partner's hand. Partner swears that opening 3H with this hand loses more often than it wins. You disagree. How do you resolve this?

Deal can help. Just run it as:

C:\deal30> deal -S "- KQJT62 T9876 84" 25
          S : KJ2
          H : 954
          D : A5
          C : AKT65
 S : T9764          S : AQ853        
 H : A              H : 873          
 D : J2             D : KQ43         
 C : QJ973          C : 2            
          S: ---
          H: KQJT62
          D: T9876
          C: 84
---------------------------
          S : KJT64
          H : 5
          D : K42
          C : AQ65
 S : 9875           S : AQ32         
 H : A93            H : 874          
 D : AJ5            D : Q3           
 C : KJ9            C : T732         
          S: ---
          H: KQJT62
          D: T9876
          C: 84
---------------------------
	.... (rest of 25 hands ellided) ...
You inspect the 25 hands dealt, guessing how the auction would proceed. Sometimes, your answers will be inconclusive, but more often one or both partners learns something from the simulation.

There are, of course, also -N, -E, and -W options for the other three seats.

Formatting output

Perhaps you'd like the hands to be written in some other format. This can be arranged fairly easily.

For example, suppose you wish to deal 8 hands for practice bidding with partner. In that case, you would use the "practice" format:

C:\deal30> deal -i format/practice 8 > out.all
C:\deal30> more out.east
                              east hands
============================================================================
     *1*                 *2*                 *3*                 *4*
  S 84                S T7                S QT3               S AJ9654
  H J8642             H Q65               H Q983              H K8
  D Q843              D KJ42              D 865               D J
  C 73                C T842              C AJ9               C K532

=============================================================================
     *5*                 *6*                 *7*                 *8*
  S J7                S 85                S AQT764            S 3
  H Q9864             H AK4               H K5                H JT4
  D 874               D A764              D 9                 D QJT86
  C J85               C Q862              C T976              C AK82

=============================================================================
The -i flag tells Deal to include the named file, in this case, the file named format/practice. This file redefines the output format. At the end of this run, you should get five files: out.north, out.east, out.south, out.west, and out.all.

Now you can print out these files, pass them out amongst four people, and practice your bidding, using out.all at the end to make a double dummy assessment of the auction results.

What if you only have two people, and you want to practice uninterrupted auctions? You could print out the north and south hands, and practice with those, but that would be an artificial test, because you obviously can't assume an uncontested auction for arbitrary deals.

When we learn about writing scripts for Deal, we will solve with this problem by filtering out hands we think would lead to competitive bidding.

What are the formats that come with the kit? Well, you can simply list the format sub-directory to find out. Here are the ones there as of this writing:

none
This script set the formatting routine to a null routine. Not useful, so far, but useful, for example, when doing statistical analysis.
numeric
This formatter writes the deal as a line which looks something like:
3031333123220300123320212213021202022103101101003113
It's a line of 52 numbers, where 0, 1, 2, and 3 mean north, east, south, and west, respectively. The first digit tells where the ace of spades goes, the second digit tells where the king of spades goes, etc.
okb
This formatter writes the output with the same spacing as the old OKbridge screen.
practice
We've just seen this one - for seperating out hands for practice bidding.
There is one last output format, which, for historical reasons, has its own command line switch, -l.
C:\deal30> deal -l 3
AJ9 976532 K92 A|86 A AT87 987653|Q732 JT8 543 T42|KT54 KQ4 QJ6 KQJ
K94 J93 QJ3 7653|A8 A8765 97 KQ98|JT2 Q AKT8654 T4|Q7653 KT42 2 AJ2
KJ753 T A4 KQ932|AQ94 AJ92 QT87 J|86 Q764 K9653 74|T2 K853 J2 AT865
C:\deal30>
In the past, this was the only way to get alternate formats. The user would pipe this output to another program, usually a Perl script, which would parse each line and format the output.

With the addition, in v2.0 of Deal, of user-configurable formatting, this usage becomes obselete, but I'm leaving the feature because it has one other use, which will be mentioned later.

Basic Dealing - Scripting

Our First Script

Let's say we want a selection of deals in which north holds a one spade opener. For now, we will use a crude definition for an opening 1S call - we will require north to have 5 or more spades and 12 or more points.

Here is the script we write (to a file we'll call onespade):

main {
  if {[spades north]>=5 && [hcp north]>=12} { accept }
  reject
}

Running the script

We run this code by saying:
C:\deal30> deal -i onespade 2
          S : AKQT5
          H : A7
          D : 8542
          C : AT
 S : 64             S : J98          
 H : K943           H : 862          
 D : J              D : AK963        
 C : KQ8732         C : 54           
          S: 732
          H: QJT5
          D: QT7
          C: J96
---------------------------
          S : AQT73
          H : A
          D : AJ987
          C : 73
 S : K5             S : J42          
 H : JT8632         H : KQ95         
 D : Q63            D : KT4          
 C : 85             C : K92          
          S: 986
          H: 74
          D: 52
          C: AQJT64
---------------------------

How the script works

By default, Deal accepts all hands. With the main code in onespade, we tell Deal to override that behavior.

This is similar to the way we used scripts to override Deal's default formatting. Note, we even use the same flag, -i, to load our formatters and onespade.

What does this main code do? It is run after every deal is complete, and used to evaluate the hand. In this case, we have only two lines of code:

if {[spades north]>=5 && [hcp north]>=12} { accept }
reject
The expression [spades north] returns the number of spades in the north hand. The expression [hcp north] returns the number of HCP (high card points) in the north hand. The "&&" is called a logical "and" operator, which returns true if the conditionals on both sides of it are true.

If the entire expression:

[spades north]>=5 && [hcp north]>=12
evaluates as true, the "accept" function is called. This causes Deal to exit the "main" code and format the hand.

If the expression evalutes as false, Deal goes to the next line of code, which calls the "reject" function. This tells Deal to discard the hand, and exit the "main" code.

Deal keeps trying until the requested number of deals is accepted.

What happens if a deal is not explicitly accepted or rejected? If neither accept nor reject is called, the deal is rejected. That means that in our first script, the reject call was redundant, and we could have simply written the script as:

main {
  if {[spades north]>=5 && [hcp north]>=12} { accept }
}

Monitoring Deal

You might want to try running this script with the -v switch:
C:\deal30> deal -v -i onespade
The -v flag tells Deal to give a progress report, which looks like:
...
Deal 1 found after 2 tries
...
Deal 2 found after 21 tries
...
Deal 3 found after 31 tries
This will give you some idea of how rare your condition is, and also gives a good progress report when Deal is writing to a file or running with a "silent" format, like format/none. These status messages are written to "stderr", which means that the output from Deal can be redirected to a file without obscuring these messages.

Using formats with your script

If we wanted to use another output format with this script, we could do so on the command line, as follows:
C:\deal30> deal -i format/practice -i onespade
Or, alternately, we could add an explicit "source" command to our script:
source format/practice

main {
        if {[spades north]>=5 && [hcp north]>=12} { accept }
}
In fact, this second format unveils the secret of the -i flag - it is simply a request to "source" a file. In fact, if you were to write your own formatter, you would not have to put the file in the "format" directory. If you put it in the current directory, you could then say:
C:\deal30> deal -i myformatter 100
and it would work fine. The "format" subdirectory is just a convenience. You will often want to re-use a format, and placing them in one place lets you find out which formats are available.

Stacking hands with a script

Let's say you were dealt the hand:
S: ---
H: 98532
D: A864
C: T962
the previous day at a Swiss Teams event.

Your partner opened 1S, and, playing 2/1 Game Force, you chose to pass. This turns out well for you on this deal, because at the other table, the opponents played in three spades, down 1. Afterwards, you wonder if you really made the right decision. Your intuition tells you that it was the right choice, but you realize there are risks in both passing and bidding, and you know that intuition is very bad at assessing levels of risk.

Deal can help. Using our script, onespade, we can run the following simulation:

C:\deal30> deal -S "- 96532 A864 T962" -i onespade
The -S flag stacks the south hand with the hand you held, and the script runs exactly the same thereafter. You can now peruse the output to see whether it was a good idea or a bad idea to pass.

As with the formatting, we can also do our deck-stacking in our script.

south is - 98532 A864 T962

main {
  if {[spades north]>=5 && [hcp north]>=12} { accept }
}
Notice, we do our deck-stacking outside of the evaluation loop. Remember, the main expression is responsible for evaluating the deals after Deal finishes dealing the hands. We obviously want the stacking instruction to occur before dealing occurs, so the stacking command must be outside the main evaluation.

A partial list of routines

For evaluation routines, we have seen the hcp and spades routines, as well as the "accept" and "reject" directives. Obviously, there are also routines called hearts, diamonds, and clubs which count their respective suits. The following functions are also built-ins:
controls
This function computes the number of controls held by a hand.
losers
This function does a crude computation of the losing trick count for a hand (it actually compute's half-losers, so when [losers south] returns 14, that really means 7 losers.)
balanced
This function returns true (1) if the hand name passed is balanced in the usual sense - no shortness, at most one doubleton, and no five-card major. It returns false (0) otherwise.
semibalanced
Returns true (1) if the hand passed has no shortness and no six-card major or seven-card minor, and false (0) otherwise.
The three functions, controls, hcp, and losers, all have the property that we can compute them one suit at a time, and sum the result for the entire hand. The implementation takes advantage of this and allows the user to request these values for specific suits:
main {
  if {[hcp south hearts spades]>10} {accept}
}
This script accepts a deal if south has ten or more points in hearts and spades. controls and losers can be used similarly. Any function of this sort we will call "additive." We will see later that we can define a wide class of interesting additive functions.

The functions balanced and semi_balanced are entirely dependent on the shape of the hand, and not on which cards the hand holds. We will call these "shape functions." We will find out later how to define incredibly fast shape functions.

A Second Script - defining Tcl procedures

Let's say we want to write a script which accepts a deal if north has a strong notrump (15 to 17 range) and south has about invitational values and a 5-card major.

Our script , which we will call jacobytest might look something like:

# In deal 2.0, you don't need this next line, but deal 3.1 does - 
# without this line, the "balanced" routine is not defined.

main {
	if {![balanced north]} {reject}

	set hn [hcp north]
	if {$hn>17 || $hn<15} {reject}

	set hs [hcp south]
	if {$hs<8 || $hs>9} {reject}

	if {[spades south]==5 || [hearts south]==5} { accept }
}
We have used one of our new functions here, balanced, as well as a new Tcl feature, variables. We could, of course, not used variables, but then we would have had to write the lines:
if {[hcp north]>17 || [hcp north]<15} {reject}
That is going to be slower, with one more function call. Not appreciable today, with a simple query, but when you might be processing a million or more hands at a time, you learn to be frugal.

Suddenly, you realize you want to test this situation with a 12-14 notrump, instead. Or you realize you often want to reuse this concept. You can do so by defining Tcl procedures.

proc notrump {hand min max} {
  if {![balanced $hand]} {return 0}

  set hc [hcp $hand]
  if {$hc < $min || $hc>$max} { return 0}

  return 1
}

proc jacobyinvite {hand ntmin ntmax} {

  if {[spades $hand]!=5 && [hearts $hand]!=5} {return 0}

  set hc [hcp $hand]
  if {$hc+$ntmin <= 25 && $hc+$ntmax>=24} { return 1 }

  return 0

}

set NTmin 12
set NTmax 14

main {
  if {![notrump north $NTmin $NTmax]} { reject }
  if {[jacobyinvite south $NTmin $NTmax]} { accept }
}
You are unlikely to need the jacobyinvite function beyond this script, but the notrump function will be something you will want to use again and again. You might even put it in a library of routines, called mylibrary and source that library every time you need one or more of the routines for a script:
source mylibrary
rather than rewriting the routine every time.

In fact, the Deal kit comes with a file called lib/utility.tcl, which is just such a library of routines the author of Deal found himself re-using.

Revisiting accept and reject

The directives, accept and reject, can be used in more complicated ways that are sometimes more efficient and sometimes more readable.

Here is the main script from the notrump example using some odd constructs:

main {
  reject unless {[notrump north $NTmin $NTmax]}
  accept if {[jacobyinvite south $NTmin $NTmax]}
}
Some people might find this more readable. The first line says we are going to reject the deal unless the condition is true. The second conditional says we are going to accept the deal if the expression evaluates as true.

Multiple arguments are allowed. The following command:

reject unless {expr1} {expr2} ... {exprn}
runs through all of the expressions until it finds one which evaluates as "true". If it does not find a true value, it rejects the hand. Otherwise, deal goes on to the next line in evaluating main.

For reject if the deal is rejected if any one of the expressions is true. Similarly, accept if accepts a deal if one of the expressions is true. For accept unless, the deal is accepted unless the one of the expressions is true.


This concludes the Introductory Tutorial. I hope it inspires you to check out the Deal - Advanced Guide and to learn more about Tcl. Or check out the index of all deal commands.
Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

Plane Dealing graphic above created using POV-Ray.

deal319/html/look.css0000644000175200017520000000216111341325566012720 0ustar cbecbebody { background-image: url(graphics/idealbg.jpg) } A:link { color: #663300; } A:visited { color: #990000 ; } A:hover { color: white ; background: #336699 } A:active { color: #000099 } A.image:hover { background: transparent ; } div.header { text-align: center } span.alert { color: red ; background: transparent } span.code { font-family: Courier, monospace ; white-space: nowrap ; } pre.example { padding: 1em; background: #CCCCCC; white-space: pre; } div.codesample, pre.codesample { width: 0 ; font-family: Courier, monospace; font-size: small ; white-space: pre ; margin-left: 10% ; padding-bottom: 1em; padding-top: 1em; margin-top: 0.25in ; margin-bottom: 0.25in ; border-top: thin groove ; line-height: 120%; border-bottom: thin groove } div.back { margin-left: 5% ; margin-right: 5% ; text-align: right } div.toplevel,table.toplevel { width:90% ; margin-left: 5%; margin-right: 5%; } span.reference { font-style: italic ; } div#versionWarning { font-weight: bold; color: red; display: none; } deal319/html/license.html0000644000175200017520000000316011341325567013553 0ustar cbecbe Deal Licensing News

Deal Licensing News

Deal is now licensed under the GNU public license.

This means, very roughly, that anybody may download it for free, but, if they redistribute it, they must include the source code, including any changes they made to the source code, with this same license.

Past versions of Deal came with the license, "Free for non-commercial use." This was too vague - what is a "commercial use?"


Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

Plane Dealing graphic above created using POV-Ray.

deal319/html/index.html0000644000175200017520000001006511341325567013242 0ustar cbecbe Deal 3.1 Home Page

Deal 3.1

A bridge hand generator

by Thomas Andrews

Latest version: 3.1.9

Features:
  • Easy to use for quick, simple dealing
  • Customizable output formats
  • Infinitely extensible via TCL
  • Easily portable to most platforms
  • Free (GNU public license)
  • Deal 3.1

    Information found on these pages:

    Things you can do with Deal:

    • Dealing: Generate random deals for your club.
    • Bidding practice: Practice general bidding, or specific situations
    • Settle arguments: Was bidding game wise over that limit raise? Was that spade nine really the best lead?
    • Statistical experiments: How often does a bid occur? How often does this slam make?
    • "Problem solver" contests: Solve magazine problems, and learn where even the experts go wrong
    • Interface with other programs: Deal 3.1 comes with the ability to call the GIB double dummy solver.

    What is Tcl?

    Tcl, pronounced "tickle," stands for "Tool command language." If you are a Windows user, think of it as the Unix equivalent to Visual Basic. But, unlike Visual Basic, Tcl works on almost all operating systems, not just those made by Bill Gates.

    Tcl is used in a variety of different software, from testing tools to web software (AOL Server, Vignette) and, of most interest to bridge players, Floater, the free online bridge program.

    The people in charge of Tcl are Scriptics. But don't let their web site fool you - the basic software is free.


    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/history.html0000644000175200017520000001316511341325567013640 0ustar cbecbe Deal - A Brief History
    Plane Dealing image

    Deal 3.1

    A brief history


    D
    eal was originally conceived in 1988 for bidding practice. I was a math graduate student just learning bridge and another grad student, Robin Pemantle, suggested a way to practice bidding. His idea was to have the computer deal out twenty or so hands, and then offer each hand up to you, randomly, for bidding. This way, you could bid all four hands in each of twenty deals, and, if you tried hard, you could avoid remembering which hand was which.

    I mentioned that idea to my partner at the time, Nathan Glasser, and he wrote a program called bid, which is still available from the bridge archives.

    The problem with bid was that it could not be used for practicing specific auctions. John Oswalt solved this in a rather crude fashion. His modification forced you to re-link your application each time you wrote a new query (in C).

    After using this modified version for a while, I got frustrated and wrote a very crude interpreter. It was a "stack-based" language so I wouldn't have to write a parser. It was very much like the Unix "dc" calculator, only without all the features. (That's a joke, but I guess you wouldn't get it if you didn't know dc.)

    I could have used a fully interpreted language, like Perl, but for the types of simulations I was doing, I need very fast execution of the computation routines, and so implementing the core in an interpreted language was going to slow down the program too much.

    In about 1992 I first stumble across the Tcl language. Immediately, I saw that I could use it in my dealer. Tcl was an interpreted language which had excellent support for extensibility via fast C routines. It turned out that Nathan's code did not easily fit into my new scheme, so I rewrote the dealer from scratch. I had my first version done quickly, and released the first public version (v0.5 I called it, in retrospect) in 1993. I announced it on rec.games.bridge in this post.

    The next version (v1.0) was released about two years later, and basically cleaned up the query interface. In the haze of my memory, I can not recall what features were added, certainly "vectors" and "shape classes."

    Version 2.0 uses new optimization methods, some of which were suggested to me by the very same Nathan Glasser. There are some other new features, including shape functions, customizable output formatting, and more built-in formats.

    Version 3.0 was the next major release. Major changes were:

    • GNU GPL license - making it free for all use
    • Much faster execution using Tcl 8.x features.
    • Addition of 'holding functions' - like 'vectors' but more suitable for complex evaluations like "losers" and "CCCC."
    • "Smart stacking" for finding rare hands.

    Deal got mentioned in the New York Times bridge column.

    Version 3.1 was release in 2008, with Bo Haglund's double dummy solver built in, so you can call a 'deal::tricks' function to get double dummy data.

    Starting with release 3.1.6, the source code is hosted at Google Code.

    While Deal is a labor of love for me, it makes it easier to love the project if I get feedback which shows people are using Deal. Even if you tried Deal and did not like it, please let me know.


    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/examples.html0000644000175200017520000000602411341325567013751 0ustar cbecbe Deal - Example Scripts
    Plane Dealing image

    Deal 3.1

    Examples


    • Example 1: North is 44 in majors and short in a minor, with 11 to 15 points.
    • Example 2: South holds a specific hand and east opens two clubs.
    • Example 3: Holding a specific hand, south on lead after opponents bid: 1S(W)-1NT-2NT-3NT.
    • Example 4: South opens a weak two in spades or hearts
    • Example 5: Playing Blue Club, responder to 1C opening has three or more controls
    • Shape class variants of above examples:
    • Example 6: Find deals where north and south are void in the same suit, using several different methods.
    • Smart stacking examples:

    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/balanswer.html0000644000175200017520000001651511341325566014116 0ustar cbecbe The Sum of the Squares of the Suit Lengths

    The Sum of the Squares of the Suit Lengths

    A Measure of the "Sickness" of a Hand Pattern

    In any hand, the average of the suit lengths is 3.25 = 13/4, obviously, but what is the standard deviation of the suit lengths?

    The standard deviation, it turns out, is related to the sum of the squares of the suit lengths. In particular, the higher the sum of the squares, the higher the standard deviation.

    So it should come as no surprise that the more balanced hands should have lower standard deviations, and hence lower sums of squares. In particular, when the sum of the squares of the suit lengths is less than or equal to 47, the hand is "balanced" in the traditional sense: No singleton or void, and at most one doubleton.

    Since the smallest value is 43, and all values are odd, we can "normalize" this metric by subtracting 43 and dividing by 2.

    We get the following table:

    Normalized | Squares sum | Std Dev  | Shapes
    ============================================
             0 |          43 |  0.5000  | 4-3-3-3	 
             1 |          45 |  0.9574  | 4-4-3-2	
             2 |          47 |  1.2583  | 5-3-3-2       
             3 |          49 |  1.5000  | 4-4-4-1, 5-4-2-2 
             4 |          51 |  1.7078  | 5-4-3-1         
             5 |          53 |  1.8930  | 6-3-2-2        
             6 |          55 |  2.0616  | 5-5-2-1,6-3-3-1  
             7 |          57 |  2.2166  | 5-4-4-0,6-4-2-1 
             8 |          59 |  2.3629  | 5-5-3-0        
             9 |          61 |  2.5000  | 7-2-2-2,6-4-3-0  
            10 |          63 |  2.6300  | 7-3-2-1,6-5-1-1
            11 |          65 |  2.7538  | 6-5-2-0       
            12 |          67 |  2.8723  | 7-3-3-0, 7-4-1-1
            13 |          69 |  2.9860  | 7-4-2-0        
            15 |          73 |  3.2016  | 6-6-1-0, 8-2-2-1
            16 |          75 |  3.3040  | 7-5-1-0, 8-3-1-1
    	17 |          77 |  3.4034  | 8-3-2-0        
            19 |          81 |  3.5940  | 8-4-1-0       
            21 |          85 |  3.7749  | 7-6-0-0      
            22 |          87 |  3.8622  | 9-2-1-1     
            23 |          89 |  3.9476  | 8-5-0-0, 9-2-2-0   
            24 |          91 |  4.0311  | 9-3-1-0           
            27 |          97 |  4.2720  | 9-4-0-0          
            30 |         103 |  4.5000  | 10-1-1-1        
            31 |         105 |  4.5735  | 10-2-1-0       
            33 |         109 |  4.7170  | 10-3-0-0      
            40 |         123 |  5.1881  | 11-1-1-0     
            41 |         125 |  5.2519  | 11-2-0-0    
            51 |         145 |  5.8524  | 12-1-0-0   
            63 |         169 |  6.5000  | 13-0-0-0  
    
    
    In addition, one can get the wildness of a deal by adding up the sum of the squares of all 16 suit lengths, or add up the normalized values. Again, this is correlated to the standard deviation of the suit lengths.

    We can also measure the wildness of a "fit" by summing the squares of the fits in each suit. So if I'm 5-3-3-2 and partner is 4-3-2-4, our "fit" is 9-6-5-6. One thing interesting about this is that our opponent's fit wildness is the same as our fit pattern wildness. That's because if our pattern is: s-h-d-c, their pattern is (13-s)-(13-h)-(13-d)-(13-c), and the sum of the squares of these values is:

    (13-s)^s+(13-h)^s+(13-d)^2+(13-c)^2=
           s^2 + h^2 + d^2 + c^2 - 26*(s+h+d+c) + 4*13^2
    
    But (s+h+d+c) is 26, so the last two terms cancel, and we are left with the original value.

    Of course, if you think in terms of standard deviation, this makes more sense than the pure calculation - the opponents' pattern has the same relative distribution, just inverted, so the deviation should be the same.

    This table can also be normalized, by subtracting 170 and dividing by 2. There are 103 fit patterns, or 65 if we consider our fit pattern and opponent's as the same (e.g., that 8-6-6-6 is the same as 7-7-7-5. If the sum of the longest fit and the shortest fit is 13, then the pattern is self-dual, for example, if our fit pattern is 9-7-6-4, then so is the opponent's.)

    Normalized |  Squares sum | Patterns
    ============================================
             0 |          170 | 7-7-6-6
             1 |          172 | 8-6-6-6,7-7-7-5
             2 |          174 | 8-7-6-5
             4 |          178 | 9-6-6-5,8-8-5-5,8-7-7-4
             5 |          180 | 9-7-5-5,8-8-6-4
             6 |          182 | 9-7-6-4
             8 |          186 | 10-6-5-5,9-8-5-4,8-8-7-3
             9 |          188 | 10-6-6-4,9-7-7-3
            10 |          190 | 10-7-5-4,9-8-6-3
            12 |          194 | 10-7-6-3,9-9-4-4
            13 |          196 | 11-5-5-5,10-8-4-4,9-9-5-3,8-8-8-2
            14 |          198 | 11-6-5-4,10-8-5-3,9-8-7-2
            16 |          202 | 11-7-4-4,11-6-6-3,10-7-7-2,9-9-6-2
            17 |          204 | 11-7-5-3,10-8-6-2
            18 |          206 | 10-9-4-3
            20 |          210 | 12-5-5-4,11-8-4-3,11-7-6-2,10-9-5-2,9-8-8-1
            21 |          212 | 12-6-4-4,9-9-7-1
            22 |          214 | 12-6-5-3,11-8-5-2,10-8-7-1
            24 |          218 | 12-7-4-3,10-10-3-3,10-9-6-1
            25 |          220 | 12-6-6-2,11-9-3-3,11-7-7-1,10-10-4-2
            26 |          222 | 12-7-5-2,11-9-4-2,11-8-6-1
            28 |          226 | 13-5-4-4,12-8-3-3,10-10-5-1,9-9-8-0
            29 |          228 | 13-5-5-3,12-8-4-2,11-9-5-1,10-8-8-0
            30 |          230 | 13-6-4-3,12-7-6-1,10-9-7-0
            32 |          234 | 13-6-5-2,12-8-5-1,11-10-3-2,11-8-7-0
            33 |          236 | 13-7-3-3,10-10-6-0
            34 |          238 | 13-7-4-2,12-9-3-2,11-10-4-1,11-9-6-0
            36 |          242 | 13-6-6-1,12-9-4-1,12-7-7-0
            37 |          244 | 13-7-5-1,12-8-6-0
            38 |          246 | 13-8-3-2,11-10-5-0
            40 |          250 | 13-8-4-1,12-9-5-0,11-11-2-2
            41 |          252 | 12-10-2-2,11-11-3-1
            42 |          254 | 13-7-6-0,12-10-3-1
            44 |          258 | 13-9-2-2,13-8-5-0,11-11-4-0
            45 |          260 | 13-9-3-1,12-10-4-0
            48 |          266 | 13-9-4-0
            50 |          270 | 12-11-2-1
            52 |          274 | 13-10-2-1,12-11-3-0
            54 |          278 | 13-10-3-0
            60 |          290 | 12-12-1-1
            61 |          292 | 13-11-1-1,12-12-2-0
            62 |          294 | 13-11-2-0
            72 |          314 | 13-12-1-0
            84 |          338 | 13-13-0-0
    

    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/ex/0000755000175200017520000000000011341325566011656 5ustar cbecbedeal319/html/ex/6b.txt0000755000175200017520000000337411341325566012740 0ustar cbecbe# # File: ex/6b.tcl # # This implements the same search as ex/6a.tcl, using a simple # shape class. # # Basically, we use a shapeclass to immediately reject deals where # south doesn't have a void. This keeps us from doing unnecessary # work, and practically doubles the speed of the search. # # The shape class "hasvoid" returns one (True) if there is a void # somewhere in the hand and zero (False) otherwise. It would # seem like this is doing *more* work than example A, but the # lookup in a shapeclass is much better optimized, and we break # out of the loop if south doesn't have void, and move on to # the next. # # example6c is about the same speed but uses an idiom worth # seeing for other sorts of problems. # shapecond hasvoid {$s==0 || $h==0 || $d==0 || $c==0} main { reject unless [hasvoid south] accept if {[spades south]==0 && [spades north]==0} accept if {[hearts south]==0 && [hearts north]==0} accept if {[diamonds south]==0 && [diamonds north]==0} accept if {[clubs south]==0 && [clubs north]==0} reject } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/7.txt0000755000175200017520000000576611341325566012606 0ustar cbecbe# # A Certain poster to rec.games.bridge has been posting # a computer generated bidding system that, to most bridge # players eyes, looks somewhat deranged. # # bid.lib is a library of tcl routines which allow you # to define opening bids and later check to see if a hand # fits the conditions source lib/bid.tcl defvector AKQ 4 3 2 defvector Top4 1 1 1 1 defvector Aces 1 defvector None 0 proc top4spades {hand} { return [Top4 $hand spades] } # Usage: # describebid # # Don Quixote's system: # describebid 5D {$d>=8} AKQ 0 3 describebid 5C {$c>=8} controls 0 1 describebid 4S {$s==8} controls 0 3 describebid 4H {$h>=7} controls 0 1 describebid 4D {$d>=8} AKQ 5 7 describebid 4C {$h==8 && $d*$c*$s==3} Aces 1 1 describebid 3NT {$s==9 && ($h==2 || $d==2 || $c==2)} top4spades 2 4 describebid 3S {$s==7 && $d*$c*$h==6} AKQ 0 7 describebid 3H {$h==7} losers 16 17 describebid 3D {$d==7 && ($h==3 || $c==3 || $d==3)} hcp 3 3 describebid 3C {$c==7 && $d*$h*$s==4} AKQ 0 3 describebid 2NT {$s==7 && $c*$h*$d==8} hcp 4 5 describebid 2S {$s==7 && $c*$d*$h==4} hcp 3 5 describebid 2H {$h==7} Aces 0 0 describebid 2D {$d==7 && $h*$s*$c==6} hcp 2 5 describebid 2C {$c>=3 && $d>=3 && $h>=3 && $s>=3} hcp 22 23 ####################################### # # This uses the proceducre "getbidlist", which is really # a "shapefunc" defined in bid.lib . It returns a list # of all the possible described bids which can be made, given # only the shape of the hand. This turns out to be a very # good optimization - rather than looping through all the # bids, we only have to loop through a small subset. # # "checkcondition" then actually checks whether the hand # is fits the other condition (which does a computation # using the function provided and checks whether the hand is # in the correct range.) # # This search looks for (south) hands which would open # 2C under the above system. What kind of system # opens at the 2 level only 1/100 times, anyway? # Bizarre. # ####################################### foreach bid $bidlist { set count($bid) 0 } set accepted 0 set tried 0 main { incr tried foreach bid [getbidlist south] { if {[checkcondition $bid south]} { puts "$bid with [south]" incr count($bid) incr accepted accept } } reject } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/2.txt0000755000175200017520000000202211341325566012557 0ustar cbecbe # I held the south hand given below, and east opened 2C. # I overcalled 2S red-on-red. This procedure deals hands # where east will open 2C in front of the south hand. south is "Q86432 T2 932 83" main { set h [hcp east] reject if {$h<18} accept if {$h>22} {[losers east]<4} } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/3.txt0000755000175200017520000000270011341325566012563 0ustar cbecbe# You hold the south hand: 764 J4 J753 AQJ2 # and the auction has gone: 1S(W)-1NT-2NT-3NT by the opponents, # who are playing 2/1. # Choose a lead. # In this example, I've assumed west has no side 4-card suit, # and that he holds exactly 5 spades and 16-19 HCP. # I've also assumed that East had some way to show a 5-card heart # suit over 2NT, and hence, that he doesn't hold one, and also that # east does not have spade support. south is 764 J4 J753 AQJ2 main { reject unless {[spades west]==5} set w [hcp west] reject if {$w<16} {$w>19} {[hearts west]>3} {[diamonds west]>3} {[clubs west]>3} reject if {[hearts east]>4} {[spades east]>2} set e [hcp east] reject if {$e<6} {$e>11} {[losers east]<6} accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/3nt-common.txt0000755000175200017520000000212011341325566014407 0ustar cbecbeshapecond gam3NT.shape {$s<=3&&$h<=3&&(($d>=7&&$c<=4)||($c>=7&&$d<=4))} # return '1' if not compatible with a gambling notrump hand, # '0' otherwise holdingProc gam3NT.suit {A K Q J len} { if {$len>=7} { if {$len<=9&&$A&&$K&&$Q} { return 0} return 1 } if {$len<=4} { if {$A||$K} { return 1 } return 0 } return 1 } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/3-shapeclass.txt0000755000175200017520000000267111341325566014716 0ustar cbecbe# You hold the south hand: 764 J4 J753 AQJ2 # and the auction has gone: 1S(W)-1NT-2NT-3NT by the opponents, # who are playing 2/1. # Choose a lead. # In this example, I've assumed west has no side 4-card suit, # and that he holds exactly 5 spades and 16-19 HCP. # I've also assumed that East had some way to show a 5-card heart # suit over 2NT, and hence, that he doesn't hold one, and also that # east does not have spade support. south is 764 J4 J753 AQJ2 shapecond balanced5S {$s==5&&($h*$d*$c==18)} main { reject unless {[balanced5S west]} set w [hcp west] reject if {$w<16} {$w>19} reject if {[hearts east]>4} {[spades east]>2} set e [hcp east] reject if {$e<6} {$e>11} {[losers east]<6} accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/3nt-nostack.txt0000755000175200017520000000276111341325566014574 0ustar cbecbe# # # To run: # # deal -i ex/3nt-nostack.tcl # # Find deals where south is "AK K52 98765 962" and north has a gambling # 3nt hand. # # This uses the definition: Solid 7-9 card minor suit, no 4-card major or # 5+ card in the other minor, no controls outside the solid suit. # # This is slower than the smart-stacking version by an order of magnitude # when requesting 1000 deals. # source format/none south is "AK K52 98765 962" source ex/3nt-common.tcl set diamonds 0 set clubs 0 main { reject unless {[gam3NT.shape north]} reject unless {0==[gam3NT.suit north]} if {[diamonds north]>=7} { incr diamonds } { incr clubs } puts "-- [north shape]" accept } deal_finished { #puts "Solid diamonds: $diamonds" #puts "Solid clubs : $clubs" } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/6a.txt0000755000175200017520000000411711341325566012733 0ustar cbecbe# # File: ex/6a.tcl # # This is a test which shows why you'd want to use a "shape class" # or "shape function", which are fast lookup tables... # # This is the slow version, which doesn't use the shape function # # It seeks hands where north and south have voids in the same # suit. (Alternatively, it finds hands where east and west have # a 13-card fit.) # # See ex/6b.tcl and ex/6c.tcl for faster versions of the same search # main { accept unless {[spades south]!=0} {[spades north]!=0} accept unless {[hearts south]!=0} {[hearts north]!=0} accept unless {[diamonds south]!=0} {[diamonds north]!=0} accept unless {[clubs south]!=0} {[clubs north]!=0} } # It should be noted that this script is written so that # the north hand is never even dealt unless the south hand # has a void. That's because, internally, 'deal' doesn't deal # a hand unless information is requested about that hand. # # If the lines were: # # accept if {[spades south]==0 && [spades north]==0} # # 'deal' would request information for *both* hands, and that would # double the amount of work. Hence the use of the slightly less clear # 'accept unless' idiom. # # How much of an optimization is it to not deal the north hand? # Profiling has shown me that a vast amount of time is spent in # the randomnization routines, so cutting down on these calls # is a significant time savings. # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/5.txt0000755000175200017520000000254311341325566012572 0ustar cbecbe############################# # When I first wrote this I was somewhat surprised. # # This deals hands where south opens a strong blue club and # north has a 3+ controls (that is, he has a strong positive # response.) # # I was surprised to find that slam was making 1/2 the time on these # hands. In other words, for Blue-clubbers, if the auction starts: # # 1C 1S/1NT/2C/2D # # there is a 50% chance that a slam should be bid... ############################# main { reject unless {[controls north]>=3} set w [hcp south] reject unless {$w >=17} if {[balanced south]} { reject if {$w==17} {$w>=22 && $w<=24} } accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/6c.txt0000755000175200017520000000413611341325566012736 0ustar cbecbe# # File: ex/6c.tcl # # This file uses a "shape function" to optimize a search for hands # where north and south have voids in the same suit. # # The shape function "voids" returns a list of the suits in which # the hand given has a void. So if south is: # # S --- S AK5 S KJ8 # H 5432 H A982 H Q932 # D --- D 543 D AT9863 # C AQT986543 C T92 C ---- # # [voids south] will return: # # "spades diamonds" "" "clubs" # # We then run through this list and check if north has any void in # common. # # This doesn't seem like it would be faster, but it is, because # the shape function is computed up front as a table, and each call # after the first is a quick lookup. In fact, this is twice # as fast as the script in ex/6a.tcl . # # It is only slightly faster than ex/6b.tcl, though. The main # reason I include it is to show a technique that can be used elsewhere. # Another example which uses this is example7, a rather complicated routine... # shapefunc voids { set res "" if {$s==0} { lappend res spades } if {$h==0} { lappend res hearts } if {$d==0} { lappend res diamonds } if {$c==0} { lappend res clubs } return $res } main { foreach suit [voids south] { accept if {[$suit north]==0} } } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/6d.txt0000755000175200017520000000336011341325566012735 0ustar cbecbe# # File: ex/6d.tcl # # This file uses a "holding function" to optimize a search for hands # where north and south have voids in the same suit. # # The holding function "isVoid" returns a list of the suits in which # the hand given has a void. So if south is: # # S --- S AK5 S KJ8 # H 5432 H A982 H Q932 # D --- D 543 D AT9863 # C AQT986543 C T92 C ---- # # [voids south] will return: # # "spades diamonds" "" "clubs" # # This is the same output as in the "voids" procedure for ex/6c.tcl, # but it is implemented as a holding procedure rather than a shape # procedure. # # We then run through this list and check if north has any void in # common. # # This is considerably slower the 6b.tcl and 6c.tcl, though. holdingProc -boolean voids {len} { expr {$len==0} } main { foreach suit [voids south] { accept if {[$suit north]==0} } } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/4-stack.txt0000755000175200017520000000246411341325566013676 0ustar cbecbe# # By agreement, you open a weak 2 with exactly 6 cards in your major, # fewer than 4 cards in the other major, 5-10 HCP and either 2 of the # top 3 or three of the top 5 in your suit. # holdingProc -boolean Weak2Quality {length A K Q J T} { accept if {$length<3} reject unless {$length==6} accept if {(($A+$K+$Q)>=2 || ($A+$K+$Q+$J+$T)>=3)} } shapecond Weak2Shape {$d<=3&&$c<=3&&(($h<=3&&$s==6)||($h==6&&$s<=3))} deal::input smartstack south Weak2Shape hcp 5 10 smartstack::restrictHolding spades Weak2Quality 1 1 smartstack::restrictHolding hearts Weak2Quality 1 1 # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/1-stack.txt0000755000175200017520000000343711341325566013674 0ustar cbecbe############################################## # Look for hand where north has 44 in the majors, a short minor, # and 11-15 HCP. # # To execute: # deal -i ex/1-stack.tcl [num] # # This example uses the smart stacking algorithm to generate the # same sorts of hands as example1 and example1-shapeclass. # The very first deal is slow - when the deal is requested a # large "factory" object is built in memory - but every other # deal generated after that first one is generated extremely quickly. # # In this example, you'd have to want about 1500 matches to the condition # for the investment to break even. But after 1500, the advantage of # the smart stacking is huge. # # The payoff is even greater for rarer hand conditions. ############################################## shapeclass roman_short_minor {expr $h==4 && $s==4 && ($c<=1 || $d<=1)} deal::input smartstack north roman_short_minor HCP 11 15 set start [clock seconds] set count 0 defvector HCP 4 3 2 1 proc flush_deal {} { global start global count set time [expr {[clock seconds]-$start}] } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/4.txt0000755000175200017520000000234711341325566012573 0ustar cbecbe# # By agreement, you open a weak 2 with exactly 6 cards in your major, # fewer than 4 cards in the other major, 5-10 HCP and either 2 of the # top 3 or three of the top 5 in your suit. # defvector W2Q 2 2 2 1 1 main { set sh [hcp south] reject if {$sh>10} {$sh<5} {[clubs south]>3} {[diamonds south]>3} set s [spades south] if {$s == 6} { reject if {[hearts south]>3} {[W2Q south spades]<=3} accept } reject if {$s>3} set h [hearts south] reject if {$h!=6} {[W2Q south hearts]<=3} accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/4-holding.txt0000755000175200017520000000230711341325566014211 0ustar cbecbe# # By agreement, you open a weak 2 with exactly 6 cards in your major, # fewer than 4 cards in the other major, 5-10 HCP and either 2 of the # top 3 or three of the top 5 in your suit. # holdingProc -boolean Weak2Quality {length A K Q J T} { expr {$length==6 && (($A+$K+$Q)>=2 || ($A+$K+$Q+$J+$T)>=3)} } main { set sh [hcp south] reject if {$sh>10} {$sh<5} {[hearts south]>3} {[clubs south]>3} {[diamonds south]>3} accept if {[Weak2Quality south spades]} } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/3nt-stack.txt0000755000175200017520000000346711341325566014243 0ustar cbecbe# # Find deals where south is "AK K52 98765 962" and north has a gambling # 3nt hand. # # This was one of the first examples I gave of how "smart stacking" could # be used. # # Compare output from this with output from ex/3nt-nostack.tcl to make # sure that the relative odds are being obeyed, eg: # # deal -i ex/3nt-stack.tcl 1000 | sort | uniq -c | sort -nr > stack.txt # deal -i ex/3nt-nostack.tcl 1000 | sort | uniq -c | sort -nr > nostack.txt # # Obviously, they shouldn't be exactly the same, but they should be similar. source format/none shapecond gam3NT.shape {$s<=3&&$h<=3&&(($d>=7&&$c<=4)||($c>=7&&$d<=4))} # return '1' if not compatible with a gambling notrump hand, # '0' otherwise holdingProc gam3NT.suit {A K Q J len} { if {$len>=7} { if {$len<=9&&$A&&$K&&$Q} { return 0} return 1 } if {$len<=4} { if {$A||$K} { return 1 } return 0 } return 1 } deal::input smartstack north gam3NT.shape gam3NT.suit 0 0 south is "AK K52 98765 962" # Dump the data table from the smart stacking routine main { puts "-- [north shape]" accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/holdingProc.txt0000755000175200017520000000302611341325566014673 0ustar cbecbe# # A simple 'holding procedure' to determine high card points # holdingProc HCP {A K Q J} { expr {$A*4+$K*3+$Q*2+$J} } # # The 'smartPoints' procedure incorporates two adjustments to # the standard high card points. # # 1) A point is added for every card over 4 in a single suit # 2) Honors in short suits are somewhat discounted # holdingProc smartPoints {length A K Q J} { if {$length>=5} { return [expr {$A*4+$K*3+$Q*2+$J+$length-4}] } if {$length==0} { return 0 } if {$length==1} { return [expr {$A*4+$K*2}] } if {$length==2} { return [expr {$A*4+$K*3+$Q}] } expr {$A*4+$K*3+$Q*2+$J} } # # Find deals where north has less than 13 HCP but are compensated over # 13 points by shape # main { reject if {[HCP north]>12} accept if {[smartPoints north]>12} } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/1-shapeclass.txt0000755000175200017520000000230011341325566014701 0ustar cbecbe############################################## # Look for hand where north has 44 in the majors, a short minor, # and 11-15 HCP. # # To execute: # deal -i ex/1-shapeclass.tcl [num] ############################################## shapeclass roman_short_minor {expr {$h==4 && $s==4 && ($c<=1 || $d<=1)}} main { reject unless {[roman_short_minor north]} set hcp_n [hcp north] accept if {$hcp_n>=11 && $hcp_n<=15} } ############################################## # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/ex/1.txt0000755000175200017520000000304411341325566012563 0ustar cbecbe############################################## # Look for hand where north has 44 in the majors, a short minor, # and 11-15 HCP. # # Parts of this could be done more efficiently with a "shapeclass" # command. # # To execute: # deal -i ex/1.tcl [num] ############################################## main { # Pitch deals # where north does # not have four spades reject if {[spades north]!=4} # Pitch deals # where north does # not have four hearts reject if {[hearts north]!=4} # Pitch deals # where north has # 2 or 3 diamonds set d [diamonds north] reject if {$d==2} {$d==3} # Accept deals # where north has # 11-15 HCP. set hcp_n [hcp north] accept if {$hcp_n>=11 && $hcp_n<=15} } ############################################## # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/html/commands.css0000644000175200017520000000137111341325566013557 0ustar cbecbepre.example { padding: 1em; white-space: pre; } .tcl { color: #000066; background: #DDEEFF; font-size: smaller; border: 2px ridge; padding: 1em; width: 90%; } .programmer { color: #006600; background: #EEFFDD; } .tcl, .programmer { font-size: smaller; padding: 1em; width: 90%; border: 2px ridge; margin: 0 0 1em 0; } #indexbox { position: fixed; top: 0; left: 0; width: 230px; height: 100%; overflow: auto; } .index { font-size: smaller; padding: 10px; margin: 0px; background: #CCCCDD; } .index ul { margin-left: 1em; padding-left: 1em; } #commandsbox { position: absolute; top: 0; left: 250px; } .commands { padding: 10px; background: #EEEEFF; } span.nobr { white-space: pre; } deal319/html/dist.html0000644000175200017520000004077111341325567013105 0ustar cbecbe Hand Distribution Table

    Hand Distribution Table

    I am including this information in my web pages because I think it is neat and that it is a method I think other writers of hand generators might want to use.

    It is also the only time I can think of when I have used anything I learned in graduate school.

    Creation of the table

    My program, 'Deal', needed a fast way to determine whether a hand was in a particular class. The goal was to stay out of the TCL interpreter as much as possible. The answer was to implement a lookup table with an easy indexing algorithm.

    There are 560 hand shapes, where by "shape", I mean the ordered listing of suit lengths: spades-hearts-diamonds-clubs.

    The hand shapes are in easy 1-1 correspondence with the 3-subsets of {0,...,15}. In particular, the hand shape with s spades, h hearts, d diamonds, and c clubs corresponds to the 3-set {s, s+h+1, s+h+d+2}.

    There is a linear order on n-subsets, for fixed n, called the squashed order [see Combinatorics on Finite Sets, Anderson, pp 112-119.] The nice thing about this order is that it is easy to find the index of an n-set in the order. In the case of n=3, take a subset {x,y,z}, with 0<=x<y<z<=15. The index of this set in the squashed order is

    (z choose 3) + (y choose 2) + (x choose 1)
    For the hand shape s-h-d-c, then, the corresponding index in the squashed order is
    (s+h+d+2 choose 3) + (s+h+1 choose 2) + (s choose 1)

    For added speed, I pre-computed (n+2 choose 3) and (n+1 choose 2) for n=0,...13, placing the values in static arrays. The resulting C code looks like:

    static int distTableIndex(s,h,d)
    int s,h,d;
    {
      static choose2tab[]={0, 1, 3,  6, 10, 15, 21, 28,  36,  45,  55,  66,  78,  91};
      static choose3tab[]={0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286, 364, 455};
      return choose3tab[s+h+d]+choose2tab[s+h]+s;
    }
    
    It is precisely because I can quickly compute this index that I have chosen the squashed order. Perhaps other orders also happen to allow for quick indexing, but this is the one I found in my personal math library.

    Usage of the table

    The table is useful for fast lookups. For example, lets say you were looking for hands which were five-five or better in any two suits. You could, of course, simply check each suit length, but the problem with this is that in an interpreted language, like Tcl, that might be too slow. If, however, you built a 560 element binary array, and do the computation 560 times up front, then when we start analyzing actual deals, we can quickly determine whether a particular shape was in that class.

    In reality, the table is not computed until the first request is made of a shapeclass, which allows users to create large libraries to be included but not instantiated until used.

    For example:

    shapecond Balanced {$s*$s+$h*$h+$d*$d+$c*$c<=47}
    
    When this shapeclass is first used, a table of 560 entries is created, and then the interpreter evaluates this expression only 560 times. For rare hand classes, this is a significant improvement.

    When Deal is confronted with a specific query about membership in this class, all it has to do is use distTableIndex find the index, then look it up in the table. This is significantly faster than reinterpreting the Tcl code every time.

    The concept of "shape class" led to the concept of "shape function". These are functions which use the shape of the hand to determine the value. For instance, I have a function which determines the opening suit for a hand:

    shapefunc opensuit {
    
    	if {$s>=5 && $s>=$h && $s>=$d && $s>=$c} {return spades}
    
    	if {$h>=5 && $h>=$d && $h>=$c} { return hearts }
    
    	if {$d>=4 && $d>=$c} {return diamonds}
    
    	if {$c<3} {return diamonds}
    
    	return clubs
    }
    
    [ The current implementation of shapefunc is a bit of a memory hog, unfortunately, since it allocates strings for every element of the table, even if the strings are duplicates. For instance, the function above has only 4 return values, "spades", "hearts", "diamonds", and "clubs". Still, shapefunc instantiates 560 strings. Smarter implementations are certainly possible, and Tcl 8.0 alleviates the problem considerably (because it allows deals with reference-counted strings.) ]

    [ We could also instantiate the table an entry at a time, leaving null pointers in the table until a value has been requested. This has the advantage that we will often compute considerably fewer values from the table. The disadvantage is that every time we need a value from the table, we will have to do a check to see if a pointer value is null. It is not clear to me this would be an improvement or not, but it would add a complexity to the code that I am not willing to maintain. It might seem that you would need to check a pointer anyway, to determine if the shapeclass has been instantiated or not, but the implementation avoids such a check.]

    Note

    The above definition of Balanced is an interesting oddity, which I leave it up to the reader to try to understand. Think about it for a moment before you look here.

    Table

    Here is the raw data of the table. Not very interesting, but it does help to make it clear how the squashed ordering works, and why the index values are computed as they are. Index| S H D C ================== 0 | 0 0 0 13 1 | 0 0 1 12 2 | 0 1 0 12 3 | 1 0 0 12 4 | 0 0 2 11 5 | 0 1 1 11 6 | 1 0 1 11 7 | 0 2 0 11 8 | 1 1 0 11 9 | 2 0 0 11 10 | 0 0 3 10 11 | 0 1 2 10 12 | 1 0 2 10 13 | 0 2 1 10 14 | 1 1 1 10 15 | 2 0 1 10 16 | 0 3 0 10 17 | 1 2 0 10 18 | 2 1 0 10 19 | 3 0 0 10 20 | 0 0 4 9 21 | 0 1 3 9 22 | 1 0 3 9 23 | 0 2 2 9 24 | 1 1 2 9 25 | 2 0 2 9 26 | 0 3 1 9 27 | 1 2 1 9 28 | 2 1 1 9 29 | 3 0 1 9 30 | 0 4 0 9 31 | 1 3 0 9 32 | 2 2 0 9 33 | 3 1 0 9 34 | 4 0 0 9 35 | 0 0 5 8 36 | 0 1 4 8 37 | 1 0 4 8 38 | 0 2 3 8 39 | 1 1 3 8 40 | 2 0 3 8 41 | 0 3 2 8 42 | 1 2 2 8 43 | 2 1 2 8 44 | 3 0 2 8 45 | 0 4 1 8 46 | 1 3 1 8 47 | 2 2 1 8 48 | 3 1 1 8 49 | 4 0 1 8 50 | 0 5 0 8 51 | 1 4 0 8 52 | 2 3 0 8 53 | 3 2 0 8 54 | 4 1 0 8 55 | 5 0 0 8 56 | 0 0 6 7 57 | 0 1 5 7 58 | 1 0 5 7 59 | 0 2 4 7 60 | 1 1 4 7 61 | 2 0 4 7 62 | 0 3 3 7 63 | 1 2 3 7 64 | 2 1 3 7 65 | 3 0 3 7 66 | 0 4 2 7 67 | 1 3 2 7 68 | 2 2 2 7 69 | 3 1 2 7 70 | 4 0 2 7 71 | 0 5 1 7 72 | 1 4 1 7 73 | 2 3 1 7 74 | 3 2 1 7 75 | 4 1 1 7 76 | 5 0 1 7 77 | 0 6 0 7 78 | 1 5 0 7 79 | 2 4 0 7 80 | 3 3 0 7 81 | 4 2 0 7 82 | 5 1 0 7 83 | 6 0 0 7 84 | 0 0 7 6 85 | 0 1 6 6 86 | 1 0 6 6 87 | 0 2 5 6 88 | 1 1 5 6 89 | 2 0 5 6 90 | 0 3 4 6 91 | 1 2 4 6 92 | 2 1 4 6 93 | 3 0 4 6 94 | 0 4 3 6 95 | 1 3 3 6 96 | 2 2 3 6 97 | 3 1 3 6 98 | 4 0 3 6 99 | 0 5 2 6 100 | 1 4 2 6 101 | 2 3 2 6 102 | 3 2 2 6 103 | 4 1 2 6 104 | 5 0 2 6 105 | 0 6 1 6 106 | 1 5 1 6 107 | 2 4 1 6 108 | 3 3 1 6 109 | 4 2 1 6 110 | 5 1 1 6 111 | 6 0 1 6 112 | 0 7 0 6 113 | 1 6 0 6 114 | 2 5 0 6 115 | 3 4 0 6 116 | 4 3 0 6 117 | 5 2 0 6 118 | 6 1 0 6 119 | 7 0 0 6 120 | 0 0 8 5 121 | 0 1 7 5 122 | 1 0 7 5 123 | 0 2 6 5 124 | 1 1 6 5 125 | 2 0 6 5 126 | 0 3 5 5 127 | 1 2 5 5 128 | 2 1 5 5 129 | 3 0 5 5 130 | 0 4 4 5 131 | 1 3 4 5 132 | 2 2 4 5 133 | 3 1 4 5 134 | 4 0 4 5 135 | 0 5 3 5 136 | 1 4 3 5 137 | 2 3 3 5 138 | 3 2 3 5 139 | 4 1 3 5 140 | 5 0 3 5 141 | 0 6 2 5 142 | 1 5 2 5 143 | 2 4 2 5 144 | 3 3 2 5 145 | 4 2 2 5 146 | 5 1 2 5 147 | 6 0 2 5 148 | 0 7 1 5 149 | 1 6 1 5 150 | 2 5 1 5 151 | 3 4 1 5 152 | 4 3 1 5 153 | 5 2 1 5 154 | 6 1 1 5 155 | 7 0 1 5 156 | 0 8 0 5 157 | 1 7 0 5 158 | 2 6 0 5 159 | 3 5 0 5 160 | 4 4 0 5 161 | 5 3 0 5 162 | 6 2 0 5 163 | 7 1 0 5 164 | 8 0 0 5 165 | 0 0 9 4 166 | 0 1 8 4 167 | 1 0 8 4 168 | 0 2 7 4 169 | 1 1 7 4 170 | 2 0 7 4 171 | 0 3 6 4 172 | 1 2 6 4 173 | 2 1 6 4 174 | 3 0 6 4 175 | 0 4 5 4 176 | 1 3 5 4 177 | 2 2 5 4 178 | 3 1 5 4 179 | 4 0 5 4 180 | 0 5 4 4 181 | 1 4 4 4 182 | 2 3 4 4 183 | 3 2 4 4 184 | 4 1 4 4 185 | 5 0 4 4 186 | 0 6 3 4 187 | 1 5 3 4 188 | 2 4 3 4 189 | 3 3 3 4 190 | 4 2 3 4 191 | 5 1 3 4 192 | 6 0 3 4 193 | 0 7 2 4 194 | 1 6 2 4 195 | 2 5 2 4 196 | 3 4 2 4 197 | 4 3 2 4 198 | 5 2 2 4 199 | 6 1 2 4 200 | 7 0 2 4 201 | 0 8 1 4 202 | 1 7 1 4 203 | 2 6 1 4 204 | 3 5 1 4 205 | 4 4 1 4 206 | 5 3 1 4 207 | 6 2 1 4 208 | 7 1 1 4 209 | 8 0 1 4 210 | 0 9 0 4 211 | 1 8 0 4 212 | 2 7 0 4 213 | 3 6 0 4 214 | 4 5 0 4 215 | 5 4 0 4 216 | 6 3 0 4 217 | 7 2 0 4 218 | 8 1 0 4 219 | 9 0 0 4 220 | 0 0 10 3 221 | 0 1 9 3 222 | 1 0 9 3 223 | 0 2 8 3 224 | 1 1 8 3 225 | 2 0 8 3 226 | 0 3 7 3 227 | 1 2 7 3 228 | 2 1 7 3 229 | 3 0 7 3 230 | 0 4 6 3 231 | 1 3 6 3 232 | 2 2 6 3 233 | 3 1 6 3 234 | 4 0 6 3 235 | 0 5 5 3 236 | 1 4 5 3 237 | 2 3 5 3 238 | 3 2 5 3 239 | 4 1 5 3 240 | 5 0 5 3 241 | 0 6 4 3 242 | 1 5 4 3 243 | 2 4 4 3 244 | 3 3 4 3 245 | 4 2 4 3 246 | 5 1 4 3 247 | 6 0 4 3 248 | 0 7 3 3 249 | 1 6 3 3 250 | 2 5 3 3 251 | 3 4 3 3 252 | 4 3 3 3 253 | 5 2 3 3 254 | 6 1 3 3 255 | 7 0 3 3 256 | 0 8 2 3 257 | 1 7 2 3 258 | 2 6 2 3 259 | 3 5 2 3 260 | 4 4 2 3 261 | 5 3 2 3 262 | 6 2 2 3 263 | 7 1 2 3 264 | 8 0 2 3 265 | 0 9 1 3 266 | 1 8 1 3 267 | 2 7 1 3 268 | 3 6 1 3 269 | 4 5 1 3 270 | 5 4 1 3 271 | 6 3 1 3 272 | 7 2 1 3 273 | 8 1 1 3 274 | 9 0 1 3 275 | 0 10 0 3 276 | 1 9 0 3 277 | 2 8 0 3 278 | 3 7 0 3 279 | 4 6 0 3 280 | 5 5 0 3 281 | 6 4 0 3 282 | 7 3 0 3 283 | 8 2 0 3 284 | 9 1 0 3 285 |10 0 0 3 286 | 0 0 11 2 287 | 0 1 10 2 288 | 1 0 10 2 289 | 0 2 9 2 290 | 1 1 9 2 291 | 2 0 9 2 292 | 0 3 8 2 293 | 1 2 8 2 294 | 2 1 8 2 295 | 3 0 8 2 296 | 0 4 7 2 297 | 1 3 7 2 298 | 2 2 7 2 299 | 3 1 7 2 300 | 4 0 7 2 301 | 0 5 6 2 302 | 1 4 6 2 303 | 2 3 6 2 304 | 3 2 6 2 305 | 4 1 6 2 306 | 5 0 6 2 307 | 0 6 5 2 308 | 1 5 5 2 309 | 2 4 5 2 310 | 3 3 5 2 311 | 4 2 5 2 312 | 5 1 5 2 313 | 6 0 5 2 314 | 0 7 4 2 315 | 1 6 4 2 316 | 2 5 4 2 317 | 3 4 4 2 318 | 4 3 4 2 319 | 5 2 4 2 320 | 6 1 4 2 321 | 7 0 4 2 322 | 0 8 3 2 323 | 1 7 3 2 324 | 2 6 3 2 325 | 3 5 3 2 326 | 4 4 3 2 327 | 5 3 3 2 328 | 6 2 3 2 329 | 7 1 3 2 330 | 8 0 3 2 331 | 0 9 2 2 332 | 1 8 2 2 333 | 2 7 2 2 334 | 3 6 2 2 335 | 4 5 2 2 336 | 5 4 2 2 337 | 6 3 2 2 338 | 7 2 2 2 339 | 8 1 2 2 340 | 9 0 2 2 341 | 0 10 1 2 342 | 1 9 1 2 343 | 2 8 1 2 344 | 3 7 1 2 345 | 4 6 1 2 346 | 5 5 1 2 347 | 6 4 1 2 348 | 7 3 1 2 349 | 8 2 1 2 350 | 9 1 1 2 351 |10 0 1 2 352 | 0 11 0 2 353 | 1 10 0 2 354 | 2 9 0 2 355 | 3 8 0 2 356 | 4 7 0 2 357 | 5 6 0 2 358 | 6 5 0 2 359 | 7 4 0 2 360 | 8 3 0 2 361 | 9 2 0 2 362 |10 1 0 2 363 |11 0 0 2 364 | 0 0 12 1 365 | 0 1 11 1 366 | 1 0 11 1 367 | 0 2 10 1 368 | 1 1 10 1 369 | 2 0 10 1 370 | 0 3 9 1 371 | 1 2 9 1 372 | 2 1 9 1 373 | 3 0 9 1 374 | 0 4 8 1 375 | 1 3 8 1 376 | 2 2 8 1 377 | 3 1 8 1 378 | 4 0 8 1 379 | 0 5 7 1 380 | 1 4 7 1 381 | 2 3 7 1 382 | 3 2 7 1 383 | 4 1 7 1 384 | 5 0 7 1 385 | 0 6 6 1 386 | 1 5 6 1 387 | 2 4 6 1 388 | 3 3 6 1 389 | 4 2 6 1 390 | 5 1 6 1 391 | 6 0 6 1 392 | 0 7 5 1 393 | 1 6 5 1 394 | 2 5 5 1 395 | 3 4 5 1 396 | 4 3 5 1 397 | 5 2 5 1 398 | 6 1 5 1 399 | 7 0 5 1 400 | 0 8 4 1 401 | 1 7 4 1 402 | 2 6 4 1 403 | 3 5 4 1 404 | 4 4 4 1 405 | 5 3 4 1 406 | 6 2 4 1 407 | 7 1 4 1 408 | 8 0 4 1 409 | 0 9 3 1 410 | 1 8 3 1 411 | 2 7 3 1 412 | 3 6 3 1 413 | 4 5 3 1 414 | 5 4 3 1 415 | 6 3 3 1 416 | 7 2 3 1 417 | 8 1 3 1 418 | 9 0 3 1 419 | 0 10 2 1 420 | 1 9 2 1 421 | 2 8 2 1 422 | 3 7 2 1 423 | 4 6 2 1 424 | 5 5 2 1 425 | 6 4 2 1 426 | 7 3 2 1 427 | 8 2 2 1 428 | 9 1 2 1 429 |10 0 2 1 430 | 0 11 1 1 431 | 1 10 1 1 432 | 2 9 1 1 433 | 3 8 1 1 434 | 4 7 1 1 435 | 5 6 1 1 436 | 6 5 1 1 437 | 7 4 1 1 438 | 8 3 1 1 439 | 9 2 1 1 440 |10 1 1 1 441 |11 0 1 1 442 | 0 12 0 1 443 | 1 11 0 1 444 | 2 10 0 1 445 | 3 9 0 1 446 | 4 8 0 1 447 | 5 7 0 1 448 | 6 6 0 1 449 | 7 5 0 1 450 | 8 4 0 1 451 | 9 3 0 1 452 |10 2 0 1 453 |11 1 0 1 454 |12 0 0 1 455 | 0 0 13 0 456 | 0 1 12 0 457 | 1 0 12 0 458 | 0 2 11 0 459 | 1 1 11 0 460 | 2 0 11 0 461 | 0 3 10 0 462 | 1 2 10 0 463 | 2 1 10 0 464 | 3 0 10 0 465 | 0 4 9 0 466 | 1 3 9 0 467 | 2 2 9 0 468 | 3 1 9 0 469 | 4 0 9 0 470 | 0 5 8 0 471 | 1 4 8 0 472 | 2 3 8 0 473 | 3 2 8 0 474 | 4 1 8 0 475 | 5 0 8 0 476 | 0 6 7 0 477 | 1 5 7 0 478 | 2 4 7 0 479 | 3 3 7 0 480 | 4 2 7 0 481 | 5 1 7 0 482 | 6 0 7 0 483 | 0 7 6 0 484 | 1 6 6 0 485 | 2 5 6 0 486 | 3 4 6 0 487 | 4 3 6 0 488 | 5 2 6 0 489 | 6 1 6 0 490 | 7 0 6 0 491 | 0 8 5 0 492 | 1 7 5 0 493 | 2 6 5 0 494 | 3 5 5 0 495 | 4 4 5 0 496 | 5 3 5 0 497 | 6 2 5 0 498 | 7 1 5 0 499 | 8 0 5 0 500 | 0 9 4 0 501 | 1 8 4 0 502 | 2 7 4 0 503 | 3 6 4 0 504 | 4 5 4 0 505 | 5 4 4 0 506 | 6 3 4 0 507 | 7 2 4 0 508 | 8 1 4 0 509 | 9 0 4 0 510 | 0 10 3 0 511 | 1 9 3 0 512 | 2 8 3 0 513 | 3 7 3 0 514 | 4 6 3 0 515 | 5 5 3 0 516 | 6 4 3 0 517 | 7 3 3 0 518 | 8 2 3 0 519 | 9 1 3 0 520 |10 0 3 0 521 | 0 11 2 0 522 | 1 10 2 0 523 | 2 9 2 0 524 | 3 8 2 0 525 | 4 7 2 0 526 | 5 6 2 0 527 | 6 5 2 0 528 | 7 4 2 0 529 | 8 3 2 0 530 | 9 2 2 0 531 |10 1 2 0 532 |11 0 2 0 533 | 0 12 1 0 534 | 1 11 1 0 535 | 2 10 1 0 536 | 3 9 1 0 537 | 4 8 1 0 538 | 5 7 1 0 539 | 6 6 1 0 540 | 7 5 1 0 541 | 8 4 1 0 542 | 9 3 1 0 543 |10 2 1 0 544 |11 1 1 0 545 |12 0 1 0 546 | 0 13 0 0 547 | 1 12 0 0 548 | 2 11 0 0 549 | 3 10 0 0 550 | 4 9 0 0 551 | 5 8 0 0 552 | 6 7 0 0 553 | 7 6 0 0 554 | 8 5 0 0 555 | 9 4 0 0 556 |10 3 0 0 557 |11 2 0 0 558 |12 1 0 0 559 |13 0 0 0
    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/dds.html0000644000175200017520000000540211341325567012704 0ustar cbecbe Double Dummy Solver

    Double Dummy Solver

    Deal now has a built-in double dummy solver, as provided by Bo Haglund.

    The commands for accessing the double dummy solver is documented here.

    Deal currently contains the code for DDS 1.1.8.

    While DDS is fairly fast most of the time, on some deals, it can take a long time. In particular, when there are lots of voids, it can take several minutes to analyze the board.

    For example, in this symmetric deal:

              S: ---
              H: Q853
              D: AJ962
              C: KT74
     S: KT74           S: Q853
     H: ---            H: AJ962
     D: Q853           D: KT74
     C: AJ962          C: ---
              S: AJ962
              H: KT74
              D: ---
              C: Q853
    

    DDS takes more than 90 minutes to analyze South declaring Notrump on my iMac (2 gig memory, 2.33 GHz Intel Core 2 Duo.)

    As a general rule, hands with voids in every suit are hard to analyze, because on every play, one of the players can discard, and can choose any card. That essentially squares the complexity of analysis, because the leader can choose any of his cards, and theperson void in the suit led can pitch any of his cards.

    In this example, we also have nobody holding "touching cards," so all 13 cards are different. (If South holds, say K-Q-J-9-8, then the hand only really has two choices to play in the suit, since, double-dummy, playing the king and playing the queen or jack are the same thing.)

    Finally, the 5-4-4-0 distribution in each suit here makes almost all the spot cards important, so DDS can not skip some analysis that it often can.


    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/downloading.html0000644000175200017520000002451211341325567014442 0ustar cbecbe Deal 3.1 - Downloading
    Deal 3.1

    Downloading Deal


    Downloading Deal 3.1.9

    Go to the main Deal page to download the latest version.

    Google Code Source Repository

    There is now a Google Code project for Deal containing the source code for this project. You can browse the source code, check out the latest source code or past versions of the source code.

    Recent Changes

    Changes in Deal 3.1.9
    
       * Fix issue #14 - smartstack was broken on OS X
       * Fix issue #15 - holding procedures implementation incomplete
       * Added documentation of pattern functions to advanced.html
       * Minor documentation fix
    
    Changes in Deal 3.1.8
    
       * Added patternfunc, patternclass, and patterncond, which are similar in
         function to the shapefunc, shapeclass, and shapecond routines. [In
         Deal, a shape is the ordered list of suit lengths: s-h-d-c. A pattern
         is sorted by lengths (decreasing.)  So the 3-4-5-1 shape has the pattern
         5431.
    
       * Added documentation to commands-body.html for the new pattern procedures
    
       * Added google analytics code to the documentation (for my web site
         only - local documentation does not have the google analytics)
    
       * [Internals] Changed occurances of "hand" in variable names to "seat"
         when it refers to a location at the table (North, East, South, West.)
    
    Changes in Deal 3.1.7
    
       * Added code to pass argument values (argc, argv, argv0) when using the 
         '-x' flag
    
       * Added code to allow for easier build against Tcl 8.3.
    
       * Updated binky points with newly computed values.  The new version
         does not have binky::defense.suit or binky::defense.nt.
         Added documentation for Binky Points evaluators.
    
       * Fixed 64-bit builds using a fix found in Christoph Berg's Ubuntu
         package for Deal.
    
       * Added another fix by Christoph Berg which improves random number
         seeding
    
       * Added Make.ubuntu and Make.mac-osx to source release build
    
       * Clarified some build and install notes
    
       * Fixed docs to use './deal' rather than 'deal'
    
    Changes in Deal 3.1.6
    
       * Added newLTC function
    
       * Merged in changes with DDS 1.1.9 (about 5% performance increase in
         double dummy solving in tests of average deals)
    
       * Moderate changes in documentation
    
       * Moved the source code to a Google Code project, at http://andrews-deal.googlecode.com/
    
    Changes in Deal 3.1.5
    
       * Changed "stringbox" procedures to allow Unicode characters
    
       * Small changes to DDS to clarify code and very slightly improve performance (fixing a
         'bug' that I had created which required holding_t type to be unsigned int rather
         that unsigned short
    
       * Allow fully played tricks to be passed with the -trick option to 'dds' command
    
       * Documentation for 'dds'  -trick option
    
       * Reorganization of commands documentation file to create a non-framed version
    
    
    Changes in Deal 3.1.4
    
       * Added -trick flag to dds
    
       * Allowed for inclusion of Tcl release libraries
    
       * Moved most of deal.tcl to lib/features.tcl
    
    Changes in Deal 3.1.3
    
       * Fixed performance issue in DDS that I introduced in Deal 3.1.0.
    
       * Added -x command line flag
    
    Changes in Deal 3.1.2
    
       * Added dds command for more control over the double dummy solver
    
       * Added 'universal' target to Makefile for building Mac universal binaries
    
       * Added tests for double-dummy solver, including Great 88 file
    
       * Performance tweaks to the double-dummy solver
    
       * Fixed a typo bug in deal.tcl
    
       * Added full_deal command
    
       * Added unicode output option for default format (to put out suit symbols)
    
       * Changed to allow "-" as void in inputs
    
       * Fixed seeding with seed_deal command
    
       * Updated documentation and built a documentation-management system
    
    Changes in Deal 3.1.1
    
       * Implemented deal::tricks for caching of double dummy data
         and uniform interface to double dummy tricks data
    
       * Changed call to Haglund's solver to re-use data when processing
         contracts in the same denomination and different declarers.
    
    Changes in Deal 3.1
    
       * Added Bo Haglund's Double Dummy Solver
    
    Changes in Deal 3.0.8
    
    [ No binary changes ]
    
       * Fixed "line" input format
    
       * Updates documentation
    
    Changes in Deal 3.0.7
    
    [ No binary changes - all changes in the Tcl files. ]
    
       * Changed "score" to be a table lookup.
       * Fixed a bug in "parscore" which wrong-sided the
         contract sometimes.
       * Fixed documentation file "commands.html".
    
    Changes in Deal 3.0.6
    
    [ No binary changes this release - all changes in the Tcl files. ]
    
       * Made changes to gib.tcl to work with the latest version of GIB.
    
       * Fixed a few bugs with various formatting procedures.
    
    Changes in Deal 3.0.5
    
       * Fixed a bug - Deal 3.0.4 failed to recognize "-" as void
       in -S, -E, -N, -W options, as well as in "north is " commands.
    
         -----
    
    Changes in Deal 3.0.4
    
       * Update doc examples to match ex/ subdirectory.
    
       * Deleted util.c and util.h from distribution.
    
         -----
    
    Changes in Deal 3.0.3
    
      * Added GNU General Public License copyright to most files, and full
      GPL text to release.
    
      * Altered deal.c to improve performance of reset_deal() routine.
      Improved overall performance of 10%.
    
      * Re-implemented in Tcl the broken undocumented old procedures,
       intersectclass, negateclass, and joinclass.  This lets you create
       new shape classes from old shape classes using standard boolean
       functions.  Old code removed from dist.c, new code added to deal.tcl .
    
      * Deleted some unused code in deal.tcl which was left from early
       efforts at the smart stacking routines.
    
      * Updated the documentation
    
         -----
    Changes in Deal 3.0.2
    
      * Fixed a bug in the smartstack methods.
    
      * Altered zip builds to put files in deal302 directory (rather than
       deal3.0.2)
    
      * Polished the HTML docs (in docs/html directory.)
    
      * Many, many improved error messages when commands are misused
    
      * Cleaned up some code
    
      * Made dist.c use more Tcl_Obj pointers rather than strings - makes for
       faster compiles of shape classes.  (I can't believe I left those
       sprintf calls for so long. :-)
    
      * Fixed some of the examples which called deal::stack_hand, a non-existant
       procedure.
    
         -----
    
    Changes in Deal 3.0.1
    
    The changes for Deal 3.0.1 (from Deal 3.0 beta 11) were made essentially
    for two reasons:
    
     (1) To finish the Deal 3.0 release - e.g., added documentation.
     (2) To add features needed for the "smartstack" routines.
    
      * Include HTML docs in docs/html directory.
    
      * Most library files in release moved to the lib directory
    
      * Added "smartstack" input class for fast building of hands which fit
      specific patterns
      
      * Added "stacked" procedure to find out the current state of the
      deck-stacking. Returns the list of cards stacked to the named hand.
    
      * Altered stacking methods.  Added procedures "deck_stack_cards," 
      "deck_stack_hand", "stack_cards," and "stack_hand."  By default,
      "stack_hand" and "stack_cards" just call the "deck_" procedures,
      but the idea is that "stack_cards" and "stack_hands" can be
      overridden. Now when you call "south is AJ4 KJ54 9643 72" it in
      turn calls "stack_hand south AJ4 KJ54 9643 72." Similarly,
      "south gets ..." calls "stack_cards," although there the transformation
      is somewhat different.
      
      * Added "list" subcommand to shape classes.  e.g.,
    
    	  shapeclass hasVoid { expr {$s*$h*$d*$c==0} }
    
    	  foreach shape [hasVoid list] {
    		...
    	  }
    
      * Added "shape" subcommand to the shape classes and functions, e.g.,
    
    	  shapefunc foo { ... }
    
    	  foo shape {4 2 4 3}
    
        So:
    
    	  foo north
    
        Is the same as:
    
    	  foo shape [north shape]
    
      * Added the "holding" utility procedure, with subcommands length,
        disjoint, ...
    
    	  holding length AKxxx   =>    5
    	  holding disjoint AKJ4 QT94  => 0    [ false ]
      
    New to Deal 3.0:
    
      * Fast holding procedures definable with holdingProc.
    
      * GIB interfaces (gib::directory, gib::tricks, parscore)
    
      * Bridge utility routines - lho, rho, partner, score
    
      * Input format extensibility
    
      * Uses features of faster versions of Tcl (Tcl 8.x)
    
    

    Building Deal

    Ubuntu Users

    Be careful, there is an Ubuntu package of Deal which is almost always a few revisions behind. If it tells you to try to use apt-get to install deal, that just means that you've run deal outside of the directory where you built it, or you don't have '.' in your PATH environment variable.

    Otherwise, checkout the Wiki at the build notes in the Google Code project for notes on how to build Deal on Linux or Mac OS X or other Unix-like platforms.


    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/ext-ref.html0000644000175200017520000000362111341325567013505 0ustar cbecbe Deal - Other References and Resources Back to Deal Top Page.
    Jack of Hearts

    Deal 3.1

    Other References and Resources

    • Tcl Resources
    • Other Dealers

    Tcl Resources

    John Ousterhout wrote Tcl originally as a research project, and then Sun hired him, forming the Scriptics group around Ousterhout and Tcl. The Scriptics group was spun off into a separate company. The Scriptics website is the best place to go for the latest information about Tcl, online documentation, etc.

    Other Dealers

    • Aside from Deal, the most often cited dealer on rec.games.bridge is Dealer, originally written by Hans van Staveren.
    • There are quite a few more dealers listed at the Great Bridge Links Software Page.

    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/Optimization.html0000644000175200017520000001362011341325566014620 0ustar cbecbe Optimizing Dealing - Some Ideas

    Optimizing Dealing - Some Ideas


    After doing some profiling, I found 'deal' spends most of its time in the random number generator. This is apparently a problem other people have encountered, and at least one of the publicly available dealers actually cheats around this somewhat by using a bad methodology.

    To stay out of the random number generator as much as possible, I made improvements so that 'deal' only deals cards to a hand when information is requested about that hand.

    For example, with the script:

    main {
        #west has 15-17 HCP and east has a 5-card heart suit
        reject unless {[balanced west]}                     # line A
        set whcp [hcp west]                          
        reject if {$whcp>17} {$whcp<15}
        accept if {[hearts east]>=5}                        # line B
    }
    
    Each time through the main loop, 'deal' starts with no cards dealt. When it reaches line (A), a question is asked about the west hand. No cards have been dealt yet, so 'deal' parcels out 13 random cards to west (requiring 13 calls to the random number generator.) 'Deal' then checks whether the hand is in fact balanced, and if not, it rejects the hand.

    If the hand is balanced, 'deal' computes the HCP, rejecting the deal if west isn't between 15 and 17 HCP. Only at line (B) do we request that east have 5 or more hearts, at which point "deal" gives 13 cards to east and then checks the conditional. If the hand is accepted, the rest of the deal is completed.

    Under this implementation, you can often come close to tripling the speed of complex queries.

    Other optimizations are possible.

    Let's say you want to deal hands where south has a solid seven card or longer minor suit and no side aces or kings, and north holds: "S: AK H: K52 D: 98765 C: 962". To do this simulation now, we place north's card, and then deal the rest of south's cards, rejecting deals which don't satisfy our conditions. This might take a while.

    Theoretically, we could do this much faster by picking a shape for south using relative probabilities, and deal him cards which fit that shape. So, for instance, the number of ways to assign random cards to north to give north a 3-2-7-1 shape is (11 choose 3) * (10 choose 2) * (8 choose 7) * (10 choose 1)=594000, while the number of ways for him to have 3-2-1-7 shape is (11 choose 3) * (10 choose 2) * (8 choose 1) * (10 choose 7)=7128000.

    It should come as no surprise that it is more likely that south has seven clubs than that south has seven diamonds, given north's shape.

    Since there are only 560 total possible shapes without any restrictions, we can certainly run through all possible shapes and determine their relative odds. Then we can pick one of these possible shapes randomly, with the proper probability distributions, and assign cards at random, suit by suit, to bring the south hand to the proper shape. At this point, we check to determine that the other properties are met.

    This would certainly greatly improve the performance in certain "rare hand" situations. It's not clear how much it could improve more general randomizations. What if we simply need north to be balanced? Or for north to have a 5-card major? Would this sort of optimization improve things?

    Also, this methodology makes it much harder to *prove* that the hand generator is correct. The code to handle the probability computations has to be impeccable.

    Lastly, I can't see any way to automatically get the hand shape information needed for such optimizations; if I controlled the parser, I might be able to intelligently glean the information from the specification, but since I've chosen Tcl as my scripting language, I'm somewhat stuck in that regard. The user will almost certainly have to provide the optimization request directly.

    Why optimize?

    There is a logical argument against such optimizations, on the other hand. What are we trying to learn if we are looking at a sample of one in a million hands? Let's say you play gambling 3NT, and partner opens 3NT with you holding S: Axxx H: KQx D: Q C: xxxxx. If we try to simulate this, assuming partner has 7+ solid clubs and no side aces, we might not get a proper hand for a very long time. On the other hand, the number of possible hands where partner has "fudged" his call with AKJTxxxx of diamonds or with only six clubs is considerably higher. In simulations where hands are not being found after tens of thousands of tries, it is often right to loosen the parameters.

    On the other hand, if you are trying to settle an argument like, "Well, if you had your bid, that would have been a good slam," then the tighter parameters might be right, in which case optimizations might be necessary.


    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/commands.html0000644000175200017520000020625411341325566013742 0ustar cbecbe Index of Deal Commands

    Introduction

    This is meant to be a comprehensive list of commands in Deal which are not native to Tcl. If you want to learn Tcl, I will be providing a set of pointers later.
    Text in blue is meant for Tcl afficianado - reading this text without knowledge of Tcl might confuse more than enlighten.

    Text in green is meant for programmers interested in finding code definitions.

    Hand commands: north, east, south, west, hand

    Usage

    east [ -void string] [ suitname ... ]
    hand {hand string} [ -void string] [ suitname ... ]
    
    south subcommand [ ... args ... ]
    hand {hand string} subcommand [ ... args ... ]
    
    These are very strange commands - they really have too much stuffed into them. That's a historical anomoly which I'm reluctant to abandon.

    With no subcommands, the routine is used for formatting the hand as a string. For example, if south is:

    S: AJ5432
    H: KT94
    D: void
    C: K93
    
    Then the results of various commands are:
    south                    =>    {AJ5432 KT94 {} K93}
    south spades             =>    AJ5432
    south hearts clubs       =>    {KT94 K93}
    south -void -            =>    {AJ5432 KT94 - K93}
    south -void --- diamonds =>    ---
    
    set h {AK4 {} A95432 JT98}
    hand $h                  =>    {AK4 {} A95432 JT98}
    hand $h spades           =>    AK4
    hand $h hearts clubs     =>    {{} JT98}
    hand $h -void -          =>    {AK4 - A95432 JT98}
    
    The -void switch exists precisely for formatting the output.

    The various subcommands will be treated in seperate sections. The hand version of this command only works with some subcommands.

    For Programmers
    Implementation:
    C code
    Location:
    tcl_deal.c, function tcl_hand_cmd

    Subcommand: shape

    Usage

    north shape
    hand {AJTxx Axx JTxx x} shape
    

    Summary

    Returns a list of suit lengths, in standard order.

    For example, the second command above would return the list:

    5 3 4 1
    

    Subcommand: pattern

    Usage

    north pattern
    hand {AJ32 A5 JTxx xxx} pattern
    

    Summary

    Returns a sorted list of the suit lengths, starting with the longest. For example, the second command above would return the list:
    4 4 3 2
    

    Subcommand: is

    Usage

    south is {handstring}
    

    Summary

    This command pre-places a specific 13 cards. For voids, you can use the "-" character:
    south is {AJ32 KT932 - Q876}
    
    Calls to this subcommand must occur before dealing begins, outside the "main" command.

    This subcommand calls the stack_hand command. Inside the main code, the deal is already dealt.

    Subcommand: gets

    Usage

    handname gets card [card ...]
    

    Summary

    Puts a specific list of cards in the hand named. As with the "is" subcommand, this must be called before dealing starts, outside the "main" command. The card is specified in two characters, a rank character and a suit character:
    AS KH JH 9D
    
    This routine dispatches its data to the stack_cards command.

    Subcommand: has

    Usage

    handname has card [card ...]
    hand {string} has card [...]
    

    Summary

    This returns a count of the cards listed that occur in the hand named.
    % south
    AJ54 JT54 43 654
    % south has SA HK HJ HT
    3
    
     

    Control commands

    Commands: accept and reject

    Usage

    accept [ [ if | unless ] expr expr ...]
    reject [ [ if | unless ] expr expr ...]
    

    Summary

    Without arguments, accept and reject are the same as return 1 and return 0, respectively.

    With arguments it's a little more obscure.

    accept if {$h>4}
    
    This returns 1 if the expression matches. It is equivalent to:
    if {$h>4} { return 1 }
    
    The code:
    accept if {$h>4} {$s>4}
    
    Is logically equivalent to:
    if {$h>4 || $s>4} { return 1}
    
    That is, the values are accepted if either of the expressions evaluates as true.

    The unless option does the opposite:

    accept unless {$h>4} {$s>4}
    
    This is equivalent to:
    if {!($h>4) || !($s>4)} { return 1 }
    

    The means we return with a true value unless one of the expressions is true. If one of the values is true, we simply go on to the next line.

    Examples

    Virtually all of the examples included in the release contain an instance of "accept" or "reject."
    For Programmers
    Implementation:
    C code
    Location:
    tcl_deal.c, procedure tcl_deal_control.

    This construct is borrowed from the Perl programming language. Originally, I added it to Deal 2.0 for performance reasons. Those reasons are obsolote with Tcl 8.x, but I like the mnemonic enough to keep it, and removing it might confuse old users.

    For Tcl Experts

    There actually is one subtle and occasionally useful distinction between accept/reject and the stated

    if {...} { return ... }

    version. In reality:

    accept if {$h>4} {$s>4}
    

    is equivalent to:

    if {$h>4||$s>4} { 
        return 1
    }
    expr 0
    
    This only matters when the command is the last command in a procedure. The two procedures:
    proc A {h s} {
        if {$h>4||$s>4} {
            return 1
        }	
    }
    
    proc B {h s} {
         accept if {$h>4} {$s>4}
    }
    

    are slightly different.

    A call of A 3 3 returns an empty string, while a call of B 3 3 returns 0. That can be useful, as you can see here.


    Command: main

    Usage

    main {
       block of code
    }
    

    Summary

    This defines the primary block of code evaluated after each deal is generated. If the code returns true, Deal will treat the deal as a "match" and call write_deal. It will also increment its count of deals found and exit if the limit is reached.
    For Programmers
    Implementation:
    C code
    Location:
    tcl_deal.c, procedure tcl_deal_control.

    Command: whogets

    Usage

    whogets cardname
    
    This returns the name of the person holding the card cardname.
    For Programmers
    Implementation:
    C code
    Location:
    tcl_deal.c, procedure tcl_deal_to_whom.

    Command: deal_finished

    Usage

    deal_finished {
       block of code
    }
    
    This defines the code called at the completion of generating all deals. This is code you would use to dump statistics, for example.
    For Programmers
    Implementation:
    C code
    Location:
    tcl_deal.c, procedure tcl_after_set.

    Bridge Evaluators

    Common interfaces

    There are some standard interfaces to bridge evaluation functions.

    Hand Procedures

    Any procedure defined entirely based on the values in one hand is considered a hand procedure. These procedures can be called in one of two ways:
    Weak2Bid handname
    
    Weak2Bid hand {AKQxxx xxx xxx x}
    
    The handname parameter can be one of north, south, east, west. Shape procedures and holding procedures fit the hand procedure calling method, along with other options.

    Shape procedures

    Any procedure defined on the shape of a hand can be called with one of the following methods:
    balanced handname
    
    balanced hand {AJxx xxx AKxx Kx}
    
    balanced eval 4 3 4 2
    
    balanced shape {4 3 4 2}
    
    semibalanced handname
    
    semibalanced hand {AJ432 AKx Kx xxx}
    
    semibalanced eval 5 3 2 3
    
    semibalanced shape {5 3 2 3}
    
    This follows the hand procedure outline with the addition of the eval option.


    Holding procedures

    A holding procedure is a hand procedure which is evaluated on a bridge hand by evaluating each suit holding one at a time, and then accumulate the results. There are two common ways of defining holding procedures, defvector and holdingProc.

    This is an abstraction of a very common bridge evaluation technique. The most commonly used holding functions are high card points, losing trick count, controls. For example, when counting the losers in the hand AKxx Axx KQJxxx x, we find 1 loser in spades, 2 losers in hearts, 1 loser in diamonds, and one loser in clubs. We define the total losers to be the sum across all suits, and get 5 losers, total.

    The interface lets you evaluate the entire hand, or only selected suits in a hand, or a specific list of holdings.

    hcp handname [ suitname ...  ]
    
    hcp hand {AKJxxx K xxx xxx} [ suitname ...  ]
    
    hcp holding AK43 [ ... ]
    
    In the first two cases, if no suits are named, all suits are evaluated, and the results are accumulated. In the case of the holding call, the specific holdings passed in are evaluated.

    Note, I've been saying "accumulated" rather than added. In some cases, you might have an accumulation method different from addition. For example, you might return the standard opening leads from a holding:

        openingLead holding KQJ7    =>   K
        openingLead south           => {K} {7 2} {4} {J}
    
    Each suit would create a list of proposed leads, and the result would be a list of lists of all standard leads from all holdings. Here, the accumulation is to simply make a list.

    Command: balanced and semibalanced

    Usage

    balanced handname
    
    balanced hand {text hand}
    
    balanced eval s h d c
    

    Summary

    These are both shape procedures.

    balanced returns true if the hand is some 4333, 4432, or 5332 without a 5-card major.

    semibalanced returns true if the hand has no singletons or voids, not six-card majors, and no seven-card minors.

    For Programmers
    Implementation:
    Tcl with shapecond
    Location:
    lib/features.tcl

    These use to be hard-coded in the C code, but it made more sense to add them to the library code - the user can change the definitions as he likes.


    Commands: clubs, diamonds, hearts, spades

    Usage

         spades handname
         spades hand {AKxx Axx AJxx Kx}
    
    These implement the hand procedure interface, and return the suit lengths for the appropriate suit.
    For Programmers
    Implementation:
    Location:
    tcl_deal.c, function tcl_suit_count

    These could be shape procedures but for speed reasons, I've left them this way.


    Holding Evaluators

    Command: hcp

    Usage

    hcp handname
    hcp handname suitname [suitname ...]
    hcp hand {s h d c}
    hcp hand {s h d c} suitname [suitname ...]
    
    This procedure computes standard high card points - ace is 4, king is 3, queen is 2, jack is 1. The procedure implements the holding procedure interface.
    For Programmers
    Implementation:
    C code
    Location:
    Built with additive.c, tcl_create_additive and deal.c, count_hcp

    Command: newLTC

    Usage

    newLTC handname
    newLTC handname suitname [suitname ...]
    newLTC hand {s h d c}
    newLTC hand {s h d c} suitname [suitname ...]
    

    Rex Livingston provided this implementation of the New Losing Trick Count, from a 2003 Bridge World article.

    It looks to me much like a 3-2-1 count with some adjustments, and it seems odd to me that a stiff singleton would count as 1.5 losers. Somehow, doesn't match the intuitive meaning of "loser" to me.

    For Programmers
    Implementation:
    Tcl code
    Location:
    lib/features.tcl

    Command: losers

    Usage

    losers handname
    losers handname suitname [suitname ...]
    losers hand {s h d c}
    losers hand {s h d c} suitname [suitname ...]
    
    This implements a holding procedure which computes the number of half losers. This is for historical reasons - the only holding functions allowed in past releases returned integer values, but I wanted to have some refinements over raw losing trick count.
    For Programmers
    Implementation:
    C code
    Location:
    Built with additive.c, tcl_create_additive and deal.c, count_losers
    It is probably better to reimplement in Tcl using holdingProc.

    Binky Points Evaluators

    Binky Points are described in my hand evaluations articles.

    Binky Points are designed so that sum of your partnership's Binky Point values comes as close as possible to the number of tricks that your partnership can make, double dummy.

    Commands: binky::suit and binky::nt

    Usage

    source lib/binky.tcl
    binky::nt handname
    binky::nt hand {s h d c}
    binky::suit handname
    binky::suit hand {s h d c}
    
    These two functions are hand procedures which computes the Binky Point values for a hand.
    For Programmers
    Implementation:
    Tcl code
    Location:
    lib/binky.tcl and lib/binky-data.tcl

    Bridge Logic and Utilities

    Commands: lho, partner, rho

    Usage

    lho handname
    rho handname
    partner handname
    

    Summary

    These routines accept one hand name and return another. For example, "lho north" returns "east," and "partner east" returns "west."
    For Programmers
    Implementation:
    C code
    Location:
    tcl_deal.c, function tcl_other_hand

    Commands: holding

    Usage

    holding length AJxx           =>     4
    
    holding contains AJ64 A6      =>     1 (true)
    holding contains AJ64 A65     =>     0 (false)
    
    holding encode AJ4            =>     4612  (binary: 1001000000100 )
    
    holding decode 4612           =>     AJ4
    
    holding matches AKxx  AK42    =>     1 (true)
    
    holding disjoint AJ65 KT82    =>     1 (true)
    holding disjoint A65  A32     =>     0 (false)
    
    holding index AKJ4 0          =>     A
    holding index AKJ4 1          =>     K
    holding index AKJ4 3          =>     4
    holding index AKJ4 -2         =>     J
    holding index AKJ4 10         =>     ""
    

    Summary

    For Programmers
    Implementation:
    C code
    Location:
    holdings.c, function IDeal_HoldingCmd

    Command: score

    Usage

    source lib/score.tcl
       ...
    score contract vulnerability tricks
    

    Summary

    This routine computes the standard duplicate bridge score for a contract from the point of view of declarer, if declaring side takes the given number of tricks.

    The contract is passed as a list:

    2 spades
    
    2 spades undoubled 
    
    4 clubs doubled
    
    6 notrump redoubled
    
    The vulnerablity is one of the words vul or nonvul.

    The tricks is the number of tricks taken by declarer.

    Examples

    score {2 spades} nonvul 8           =>  110
    score {2 spades doubled} nonvul 8   =>  470
    score {2 spades redoubled} nonvul 8 =>  640
    score {2 spades doubled} vul 8      =>  670
    score {2 spades} nonvul 7           =>  -50
    score {2 spades doubled} nonvul 7   =>  -100
    score {2 spades doubled} vul 7      =>  -200
    
    For Programmers
    Implementation:
    Tcl
    Location:
    score.tcl

    Double Dummy Solver

    Starting with Deal 3.1, I've included simple access to Bo Haglund's double-dummy solver library.

    Command: deal::tricks

    Usage

    deal::tricks declarer denomination
    

    Summary

    deal::tricks returns the maximum number of tricks makable by declarer in the given denomination.

    declarer must be one of "north", "east", "south", or "west." By default, it is "south."

    denomination must be a suit name or "notrump." The default value is "notrump."

    By default, deal::tricks uses the tricks function, which calls Bo Haglund's double-dummy solver.

    However, if you include "lib/gib.tcl", deal::tricks will call the GIB double dummy solver.

    deal::tricks caches values, so multiple calls for the same deal with the same declarer and denomination will not result in multiple calls to the double-dummy solver.

    Bo Haglund's solver has a feature which makes it faster if the next double dummy solver call is in the same denomination as the previous call. That means that if you need all double-dummy values, you would want to write your code as:

       foreach denom {clubs diamonds hearts spades notrump} {
         foreach hand {north east south west} {
           set tricks [deal::tricks $hand $denom]
           ...
         }
       }
    
    For Programmers
    Implementation:
    Tcl
    Location:
    lib/features.tcl

    Command: tricks

    Usage

    tricks [ declarer [ denomination [ goal ] ] ]
    

    Summary

    Unless you are using the goal parameter, you will probably want to use the deal::tricks command, since it has the advantage of caching values.

    When no goal is passed, "tricks" returns the maximum number of tricks makable by declarer in the given denomination.

    If a (positive) goal number of tricks is set, "tricks" returns 1 if declarer can make that many tricks, and 0 if the defense can always hold declarer to fewer tricks.

    declarer must be one of "north", "east", "south", or "west." By default, it is "south."

    denomination must be a suit name or "notrump." The default value is "notrump."

    goal must be an integer value, either -1 for "best play" or a value from 1 to 13 equal to the goal number of tricks for declarer. Default is -1.

    For Programmers
    Implementation:
    C, C++
    Location:
    dds.cpp, tcl_dds.c

    Command: dds

    Usage

    dds [-reuse | -noreuse] [-diagram diagram] [-goal goal]  
         [-leader leader] [-trick list of cards [-trick cards ] ...] [ declarer [ denomination ] ]
    

    Summary

    The dds command gives even more refined access to Bo Haglund's double dummy engine, including the ability to solve problems with fewer than 52 cards.

    The -reuse flag tells the double-dummy solver to reuse the data it generated from the last call. For example, if the deal is identical to the previous call and played in the same denomination, you'll want to reuse the data.

    The -noreuse flag tells the double-dummy solver not to reuse the data. This is the default.

    The -diagram flag tells the double-dummy solver to solve a specific diagram, rather than the current deal. A diagram is of the form of a Tcl list in the order north, east, south, west.

    The -leader flag tells the double-dummy solver who is on lead to the current trick.

    The -trick flag gives a list of cards played to the current trick.

    For example, to solve George Coffin's "Avoidance" end position from his Great 88, you would write:

    set diagram {
               {A987 - A -} 
               {Q5 987 - -} 
               {64 K2 2 -} 
               {K2 AQ3 - -} 
    }
    set tricks [dds -leader south -diagram $diagram south notrump]
    ...
    

    If you wanted to see how many tricks are made if south plays a particular card, say the two of clubs, you would use the -trick flag:

    set tricks [dds -leader south -diagram $diagram -trick 4S south notrump]
    
    You can also pass full tricks, as in:
    set tricks [dds -leader west -diagram $diagram -trick {4S KS 7S 5S} south notrump]
    

    Note that the -leader option always refers to the leader to the current trick, not the leader of earlier completed tricks passed with -trick. Also, the number of tricks returned is the number of tricks after all completed tricks.

    There are example tests of all the Great 88 in the file tests/great88 that is included in this release.

    For Programmers
    Implementation:
    C, C++
    Location:
    dds.cpp, tcl_dds.c

    Command: parscore

    Usage

    source lib/parscore.tcl
       ...
    set result [parscore dealer vul]
    
    set contract [lindex $result 0]
    set declarer [lindex $result 1]
    set score [lindex $result 2]
    set tricks [lindex $result 3]
    set auction [lindex $result 4]
    

    Summary

    This computes the double-dummy par result for the current deal.

    The parscore routine returns a list of five values - the contract (in the same form that is used by the score routine above), the declarer, the score for north/south, the number of tricks taken, and a "stupid" auction to the contract suitable for putting into a PBN file.

    Dealer is relevant on a few occasions. If both south and west can make 1NT, for example, and no 2-level contracts make, then "par" is 1NT by whomever gets a chance to bid it first.

    For Programmers
    Implementation:
    Tcl
    Location:
    parscore.tcl

    GIB-related routines

    These next routines use calls to the GIB double-dummy engine. You must have a licensed version of GIB installed on your computer for these routines to work. Also, these routines only work on Windows at the moment.

    Command: gib::directory

    Usage

    source lib/gib.tcl
       ...
    gib::directory path
    

    Summary

    This tells the GIB-related routines where GIB is installed.

    If this routine is not called, it defaults to GIB's default install directory, C:/Program Files/GIB.

    Note: your path should include forward slashes '/', even on Windows.

    For Programmers
    Implementation:
    Tcl
    Location:
    gib.tcl

    Command: gib::tricks

    Usage

    source lib/gib.tcl
       ...
    gib::tricks declarer denomination
    

    Summary

    You probably want to use the deal::tricks command, even when using GIB's double dummy solver.

    Denomination can be a suit name or "notrump." Declarer can be any hand name.

    This routine returns the double-dummy number of tricks available in this deal, in the given denomination by the given declarer.

    If GIB is installed anywhere unusual, you will need to call gib::directory before deal::tricks is called.

    For Programmers
    Implementation:
    Tcl
    Location:
    gib.tcl

    Bridge Command Builders

    A number of common types of bridge functions can easily be implemented to run quickly via lookup tables, including holding and shape procedures. Deal lets the user take advantage of these two sorts of lookup procedures relatively easily

    Command: defvector

    Usage

    defvector vec aceVal [ kingVal ... ]
    
    vec handname
    
    vec hand {text hand}
    
    vec handname suitname [ suitname ... ]
    
    vec handname suitname [ suitname ... ]
    
    vec hand {text hand} suitname ...
    

    Summary

    This defines a holding procedure which assigns integer values to the various cards in the hand. For example
    defvector hcp6421 6 4 2 1
    
    Defines a holding procedure which counts the ace as worth 6 points, the king as worth 4, the queen as 2, and the jack as 1.

    Vectors are limited to being integer-valued. For more complicated holding procedures, use holdingProc.

    For Programmers
    Implementation:
    C
    Location:
    vector.c

    Vectors are slighly faster than their equivalent holdingProc. They are an old optimization which remain mostly for backwards compatibility.


    Command: holdingProc

    Usage

    
    

    Temporarily, see the seperate documentation.

    For Programmers
    Implementation:
    C
    Location:
    holdings.c, function IDeal_DefHoldingProc

    Commands: shapeclass, shapecond, and shapefunc

    Usage

    shapeclass name {... code ...}
    
    shapecond name {expr}
    
    shapefunc name {... code ...}
    
    name [ north | south | east | west ]
    
    name eval s h d c
    
    name shape {s h d c}
    
    
    A shape class (or equivalently, a shape condition) also has the list subcommand:
    name list
    

    Summary

    These commands create new procedures which fit the shape function interface.

    shapeclass and shapecond define procedures which returns boolean values. shapefunc can return any type of data. shapecond is actually an alias:

    shapecond name {expr}
    
    is the equivalent of:
    shapeclass name {
      if {expr} {
        return 1
      } else {
        return 0
    }
    
    The code or expr is allowed to use the variables s, h, d, or c.

    More details can be found in the Advanced Guide.

    The list subcommand for shape classes returns a list of shapes that are in the class.

    Why are there two subcommands, "eval" and "shape" which do the roughly the same things?

    Let's say you have a class named "SemiBalanced" already defined, which includes 5-card majors. You want to define a "Balanced" class which excludes the 5-card majors. You can do this with the call:

    shapecond Balanced {[SemiBalanced eval $s $h $d $c] && $s<5 && $h<5}
    
    On the other hand, if you have a shape - output by the, say, a call to [north shape] you can evaluate it as:
        SemiBalanced shape [north shape]
    
    In fact, this is exactly equivalent to calling
        SemiBalanced north
    
    only slightly slower.

    Since these routines cache results in memory and use lookup tables, you should not use any external state or global variables inside them.

    For Programmers
    Implementation:
    C
    Location:
    dist.c, functions tcl_shapeclass_define, tcl_shapecond_define, and tcl_shapefunc_define

    Commands: patternclass, patterncond, and patternfunc

    Usage

    patternclass name {... code ...}
    
    patterncond name {expr}
    
    patternfunc name {... code ...}
    
    name [ north | south | east | west ]
    
    name eval s h d c
    
    name shape {s h d c}
    
    
    A pattern class (or equivalently, a shape condition) also has the list subcommand:
    name list
    

    Summary

    These commands create new procedures which fit the shape function interface.

    patternclass and patterncond define procedures which returns boolean values. patternfunc can return any type of data. patterncond is actually an alias:

    patterncond name {expr}
    
    is the equivalent of:
    patternclass name {
      if {expr} {
        return 1
      } else {
        return 0
    }
    
    The code or expr is allowed to use the variables l1, l2, l3, or l4, the suit lengths in descending order.

    The list subcommand for pattern classes returns a list of shapes (not patterns) that are in the class.

    Why are there two subcommands, "eval" and "shape" which do the roughly the same things?

    Let's say you have a class named "SemiBalanced" already defined, which includes 5-card majors. You want to define a "Balanced" class which excludes the 5-card majors. You can do this with the call:

    shapecond Balanced {[SemiBalanced eval $s $h $d $c] && $s<5 && $h<5}
    
    On the other hand, if you have a shape - output by the, say, a call to [north shape] you can evaluate it as:
        SemiBalanced shape [north shape]
    
    In fact, this is exactly equivalent to calling
        SemiBalanced north
    
    only slightly slower.

    Since these routines cache results in memory and use lookup tables, you should not use any external state or global variables inside them.

    For Programmers
    Implementation:
    Tcl
    Location:
    features.tcl

    Statistics

    Command: sdev

    Usage

    sdev name
    
    name add data [ data ... ]
    
    name count
    
    name average
    
    name sdev
    
    name rms
    

    Summary

    The "sdev" command defines a new Tcl procedure with the given name, which behaves as a data collection object. You can add data points to it, or you can retrieve the current number of data points, the average of the data points, the standard deviation of the data points, or the "root mean square" of the data points.

    For Programmers
    Implementation:
    C code
    Location:
    stat.c, function tcl_sdev_define.

    This was implemented in C for efficiency reasons - most real number computations really need to be done in C if they are going to be done frequently, and here, the "add" command is called quite often in normal usage.


    Command: correlation

    Usage

         correlation name
    
         name add xval yval [ xval yval ... ]
    
         name count
    
         name correlate
    
         name average [ x | y ]
    
         name sdev [ x | y ]
    
         name rms [ x | y ]
    

    Summary

    The correlation declaration defines a routine much like the sdev command, but each datapoint is a pair of values, and it computes the linear correlation between the x and y values.

    You can also get individual data for the x and y values.

    If there is no data, it returns an error on average, correlate, sdev and rms.

    If there is only one pair entered, it will throw an error on sdev.

    For Programmers
    Implementation:
    C code
    Location:
    stat.c, function tcl_correlation_define.

    This was implemented in C for efficiency reasons - most real number computations really need to be done in C if they are going to be done frequently, and here, the "add" command is called quite often in normal usage.

    Utility Procedures

    Command Line: -x flag

    Usage

       deal -x filename   ...
    

    The '-x' flag tells deal to source the file and then exit.

    Before doing so, Deal puts remaining arguments into the variables argc and argv, and sets argv0 to the filename of the script.

    This is useful if you want to skip the entire deal loop, and process stuff on your own. For example, the code in tests/great88 does not generate any deals, it just solves 88 5-card double-dummy problems. Before the -x flag, you had to explicitly call 'exit' from such scripts.

    Command: full_deal

    Usage

       set deal [full_deal]
    

    This simple utility command returns the deal as a list of hands in the order of north, east, south, and west. Suitable for psassing into dds with the -diagram flag, or remembering a deal after the end of the loop.

    Command: seed_deal

    Usage

    seed_deal number
    

    Command Line: -s

    $ deal -s number ...
    

    Summary

    seed_deal is used to seed the random number generator, to make sure that Deal generates the same sequence of random numbers.

    Care has to be taken if you want to make sure that you are generating the same sequence of deals. For one thing, if you have a main inner loop, you should add the command "finish_deal" to the main section.

    main {
       finish_deal
       ...
    }
    

    That bypasses some optimizations and forces an entire deal to be generated each time through main.

    Command: deal_deck

    Usage

    deal_deck
    

    Summary

    deal_deck is called at every new deal, even when all 52 cards are specified (stacked) precisely. Imagine stacking cards as stacking them in an undealt deck, but that the cards are only distributed to the hands when deal_deck is called.

    Most of the time, you won't need to call deal_deck directly, but it is useful to understand its behavior if you are going to write advanced procedures like input formats.

    Stacked cards are permanently stacked until the deck is reset. In this code:

        stack_hand south {AKQ32 AJ53 K54 2}
        deal_deck
        deal_deck
        puts [south spades]
    
    The output is "AKQ32". Use reset_deck to undo card stackings.

    The deal_deck procedure does one thing rather complicated when it is called, the first thing it does is execute all code registered with the deal_reset_cmds. This allows the script writer to do one of several things before the deal is generated:

    • Delete metadata related to the deal. For example, the first time the user calls deal::tricks south spades it calls the double-dummy processor. Each time after that, it uses a stored value for this function call up until the next call to deal_deck.
    • The reset command might, instead, read the next deal from a file, stack the deck, and then re-register itself. Then when deal_deck is is called, it just deals that hand from the file. This is a crude way of allowing Deal to transparently read deals from a file (or generate deals in other ways, such as smart stacking.
    For Programmers
    Implementation:
    C
    Location:
    tcl_deal.c, function tcl_deal_deck

    Command: reset_deck

    Usage

    reset_deck
    

    Summary

    This forgets about all stacked cards. The deck, from Deal's point of view, plus a list of cards which must go to specific hands. The cards which are assigned to specific hands are "stacked." The cards which are not stacked can go anywhere at the next call to deal_deck.
    For Programmers
    Implementation:
    C
    Location:
    tcl_deal.c, function tcl_reset_deck

    Commands: stack_hand and stack_cards

    Usage

    stack_hand handname hand
    stack_cards handname suitname holding [...]
    

    Summary

    By default, these two routines just call deck_stack_hand and deck_stack_cards, respectively - that is, they forcibly place cards in the deck.

    But these routines are meant to be overridden. For example, when using one of the input formats which reads deals from a file, the format will redefine these two procedures to give errors.

    % deal -I "line foo.txt" -e "stack_cards south spades AJ"
    Tcl stack dump of error info:
    No card stacking with input format ::line
    ...
    
    A more complicated re-definition occurs in the smartstack input format, which alters its hand generation depending on what cards are stacked where.
    For Programmers
    Implementation:
    C
    Location:
    hand.c, function tcl_stack_hand and tcl_stack_cards

    Commands: deck_stack_hand and deck_stack_cards

    Usage

    deck_stack_hand handname hand
    deck_stack_cards handname suitname holding [...]
    

    Summary

    These routines are the "underlying" deck-stacking routines. Any cards stacked with these routines remain stacked until the next call to reset_deck
    For Programmers
    Implementation:
    C
    Location:
    hand.c, function tcl_stack_hand and tcl_stack_cards

    Command: stacked

    Usage

    stacked handname
    

    Summary

    Determines what cards are stacked to this hand, returning them as a list of holdings:
    south gets AS KH 3H QD JD TC 9C 8C
    puts [stacked south]
    
    writes out the list:
    A K3 QJ T98
    
    This is useful for the smartstacker, because we don't want to force the user to stack cards *after* specifying conditions.
    stack_hand north {AJT KT3 KJ 75432}
    deal::input smartstack south balanced hcp 20 21
    
    The call to stack_hand occurs before smartstack is loaded, so stack_hand has not been redefined. So what smartstack does is read the cards already stacked, and use that for its initial conditions.

    For Programmers
    Implementation:
    C
    Location:
    tcl_deal.c, function tcl_stacked_cards

    Command: deal::nostacking

    Usage

    ::deal::nostacking
    

    Summary

    This procedure redefines the stack_hand and stack_cards procedures to generate error messages, and generates an error if any cards are currently stacked.

    This is used in all of the input formats which read complete deals from files, and thus are incompatible with stacking.

    For Programmers
    Implementation:
    Tcl code
    Location:
    lib/features.tcl, function deal::nostacking

    Command: deal_reset_cmds

    Usage

    deal_reset_cmds {...code...} [ ... ]
    

    Summary

    This adds a set of commands that are to be called before the next deal. The code is executed at the next call to the deal_deck procedure, which, unless you are doing something complicated, means it is called at the beginning of each time through the evaluation loop.

    deal_reset_cmds can be used so that metadata about the previous deal, such as cached values and the like, are unset. See deal::metadata.

    It is also used for defining input formats, so that deals can be read from files. For example, the "line" input format has the following routine declared:

    namespace eval line {
        #....
        proc next {} {
    	variable handle
    	set length -1
    	catch { set length [gets $handle line] }
    
            # ... process the line, or handle oef stuff ...
            # ...
    	deal_reset_cmds {::line::next}
        }
    }
    

    The key is that when line::next is done, it re-registers itself, making sure that it is called next time through as well.

    The code passed in to deal_reset_cmds is called only once, at the next request for a deal - think of it as registering a one-time trigger. Multiple triggers can be registered - they are called in the reverse order that they are added, which can seem counter-intuitive until you think of the process as an "undo" process.

    For Programmers
    Implementation:
    C
    Location:
    tcl_deal.c, function add_reset_cmds

    Command: deal::metadata

    Usage

    deal::metadata name {...code...}
    

    Summary

    Currently, this is just a peculiar way of caching slow evaluation routines. At the moment, the only place it is used is in deal::tricks.

    When you call deal::metadata, it will check to see if there is a value associated with the name requested already. If there is, the value is returned. If it does not, it evaluates the specified code and associates the result with the name. The key is, when the next deal is being analyzed, all the cached values are pitched.

    This isn't really necessary or efficient in most cases, but with evaluations which take some time, e.g. GIB calls, it improves things.

    For Programmers
    Implementation:
    Tcl
    Location:
    lib/features.tcl

    In later releases, metadata read from input streams (say, the fields from a PBN file) will also be stored here.

    This procedure uses deal_reset_cmds. The metadata is cleared each time the deal_deck command is called.


    Input formats

    Command: deal::input

    Usage

    deal::input formatName args
    

    Summary

    The deal::input command is used to define an input source for deals. It works as follows:
    1. The file input/<formatName>.tcl is loaded. This Tcl file should define a new Tcl 'namespace' with the name formatName, with member procedures named set_input and next.
    2. Deal then calls <formatName>::set_input args, which should initialize the format reading. Usually, the argument(s) are one argument representing the source file.
    3. The next deal, <formatName>::next is called.
    For Programmers
    Implementation:
    Tcl code
    Location:
    lib/features.tcl

    Input Format: giblib

    Usage

    deal::input giblib [filename]
    
    or on the command line:
    % deal -I giblib
    
    or
    % deal -I "giblib filename"
    

    Summary

    Specifies that deals are read from the specified file in the format of Matt Ginsberg's library.dat file. This includes double-dummy tricks data, so that later calls to deal::tricks will not entail calls to the GIB binaries.

    If no filename is given, the library tries to read from a file called "library.dat" in the current directory.

    The -I command-line flag is a quick alias for deal::input, passing the next argument as Tcl arguments to the deal::input command.

    For Programmers
    Implementation:
    Tcl code
    Location:
    input/giblib.tcl

    This procedure uses deal_reset_cmds.


    Input Format: line

    Usage

    deal::input line [filename]
    

    Summary

    Specifies that deals are read from the specified file in the format written by Deal's "-l" option.

    If no filename is given, the library reads from standard input. This way, you can create a single data file and then run several different queries against it:

    % deal -l 100000 > sample
    % deal -e "deal::input line sample" -i query1
    % deal -e "deal::input line sample" -i query2
    
    [ The -e option just evaluates the code in the next argument as Tcl code. Alternative, you can use the -I option, which is shorthand for input formats:
    % deal -I "line sample" -i query1
    
    The -I args option is exactly the same as -e "deal::input args".]
    For Programmers
    Implementation:
    Tcl code
    Location:
    input/line.tcl

    Input Format: ddline

    Usage

    deal::input line [filename]
    

    Summary

    Specifies that deals are read from the specified file in the format written by Deal's ddline format.

    The ddline format include doubled-dummy tricks data, so when using ddline for input, calls to deal::tricks return the data read from the file.

    For Programmers
    Implementation:
    Tcl code
    Location:
    input/line.tcl

    Input: smartstack

    Usage

    deal::input smartstack hand shapeclass [holdproc min max]
    
    or on the command line:
    % deal -I "smartstack shapeclass ..."
    

    Summary

    This is the most complicated Deal input method in the current release. It does not read deals from a file - it is, instead, a different path to generation of deals. The purpose of this format is to allow fast generations of deals where one hand fits a very specific description. For example, if you want to find hands where south has a balanced 27-count, you could write:
    deal::input smartstack south balanced hcp 27 27
    
    On my computer, that returns the first deal in 14 seconds, and every deal after that takes a tiny fraction of a second. That's because smartstack first builds a large "factory" in memory, but once it is built, the factory spits out hands matching this condition very quickly.

    By contrast, a standard "deal" script to find balanced 27-counts takes about 2.8 seconds to find each deal. That means that if you only want to find about five deals of this sort, the old style program is faster, but if you want a lot more, use smartstack. For example, if you wanted 1000 examples, smartstack takes about 15 seconds, while the old deal will take about 45 minutes.

    One interesting feature of smartstack is that it is often faster if the hand type is less frequent. For example, it takes about 6 seconds to find ten deals with 9-card spade suits, and about 5 seconds to find ten deals with 10-card spade suits. Similarly, it is faster at finding hands with exactly 9 controls than it is at finding hands with 9-12 controls.

    The smartstack routine only works on one hand - after it places cards in that hand, it generates the rest using the usual algorithm.

    For Programmers
    Implementation:
    Tcl code
    Location:
    input/smartstack.tcl, lib/handFactory.tcl
    Notes
    See the two articles from the bridge developers mailing list describing the algorithm: My first stab at describing it and some corrections.

    Formatting

    Command: write_deal

    Usage

    write_deal
    

    Summary

    This is the the name of a procedure which is called when deals are accepted. By default, it writes the result in the format:
              S: 98632
              H: A4
              D: AJ754
              C: J
     S: K              S: AJT7
     H: J3             H: QT95
     D: T98            D: Q2
     C: AKT7532        C: 984
              S: Q54
              H: K8762
              D: K63
              C: Q6
    --------------------------
    
    New output formats are defined by redefining this routine.
    For Programmers
    Implementation:
    Tcl
    Location:
    format/default

    Command: flush_deal

    Usage

    flush_deal
    

    Summary

    This routine is called at the very end of a run for deal. It does nothing, by default, but some output formats may require it if data is cached.
    For Programmers
    Implementation:
    Tcl code
    Location:
    format/default, function flush_deal

    Output Format: format/par

    Usage

    source format/par
    

    Summary

    By including this file, you are setting the output format to write the results in PBN format, with results set to the double dummy theoretical par.

    $ deal -i format/par 1
    [Date "2008.05.19"]
    [Board "1"]
    [West "West"]
    [North "North"]
    [East "East"]
    [South "South"]
    [Dealer "N"]
    [Vulnerable "None"]
    [Deal "N:K.A7.QJT9865.AK7 T94.K98532.2.943 A872.QT4.AK4.862 QJ653.J6.73.QJT5"]
    [Contract "6N"]
    [Declarer "S"]
    [Result "12"]
    [Score "NS 990"]
    {
              S: K
              H: A7
              D: QJT9865
              C: AK7
     S: QJ653          S: T94
     H: J6             H: K98532
     D: 73             D: 2
     C: QJT5           C: 943
              S: A872
              H: QT4
              D: AK4
              C: 862
    north makes 9 tricks in clubs
    north makes 12 tricks in diamonds
    north makes 8 tricks in hearts
    north makes 7 tricks in spades
    north makes 12 tricks in notrump
    east makes 3 tricks in clubs
    east makes 1 tricks in diamonds
    east makes 5 tricks in hearts
    east makes 4 tricks in spades
    east makes 1 tricks in notrump
    south makes 8 tricks in clubs
    south makes 12 tricks in diamonds
    south makes 8 tricks in hearts
    south makes 7 tricks in spades
    south makes 12 tricks in notrump
    west makes 3 tricks in clubs
    west makes 1 tricks in diamonds
    west makes 5 tricks in hearts
    west makes 4 tricks in spades
    west makes 1 tricks in notrump
    }
    [Auction "N"]
    Pass   Pass   6N
    [Play "W"]
    *
    
    For Programmers
    Implementation:
    Tcl
    Location:
    format/par

    Output Format: format/ddline

    Usage

    source format/ddline
    

    Summary

    By including this file, you are redefining the output format to the form "ddline", which writes out the deal on a single line, as with the '-l' flag, but then adds complete double-dummy data to the deal as well. If you write the output to a file:

    $ deal -i format/ddline 100 > doubledummy.txt
    

    then you can use the ddline input format to read the file back in:

    $ deal -I "ddline doubledummy.txt" -i query.tcl 100
    

    And any call to deal::tricks in query.tcl will use the value stored doubledummy.txt.

    For Programmers
    Implementation:
    Tcl
    Location:
    format/ddline

    Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2010. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/html/GIBstuff.html0000644000175200017520000001431311341325566013603 0ustar cbecbe Deal 3.1 - GIB interfaces

    Deal 3.1 - GIB interfaces

    If you add the line:

    source lib/gib.tcl
    

    it will include the GIB interface library.

    This code only works on Windows.

    gib::directory

    This command tells Deal where GIB is installed. If GIB is installed in the standard Windows directory, C:\Program Files\GIB, then you don't need to call this. But if it is installed elsewhere, you need to call this procedure:
    source lib/gib.tcl
    
    gib::directory "c:/Games/GIB"
    
    Note that Tcl uses forward-slash characters, / to seperate directory patchs.

    You can also just edit gib.tcl to permanently change the default.

    Another thing you might want to change is where the gib library places temporary files. Currently, gib.tcl has the directory C:\temp hard-coded for the temporary files. If you don't have such a directory, and don't want to create one, then you'll need to edit gib.tcl .

    deal:tricks

    Note: In past releases, you would use the gib::tricks command, but that is obsolete in Deal 3.1.

    By default, deal::tricks uses the built-in double dummy solver written by Bo Haglund. But when you include lib/gib.tcl, deal::tricks changes to call GIB's double dummy solver.

    The procedure deal::tricks returns the number of tricks a hand can make in a specific denomination (suit or notrump.) For example:

    source lib/gib.tcl
    
    main {
    
      accept if {[deal::tricks south notrump]>=12}
    
    }
    
    finds deals where south can make 12 or more tricks in notrump, double-dummy.

    This is going to be slow - each call to deal::tricks can take over a second - so you might try to put some additional conditions:

    source lib/gib.tcl
    
    main {
    
      reject if {[hcp north]+[hcp south]<26}
    
      accept if {[deal::tricks south notrump]>=12}
    
    }
    
    That might miss the occasional freakish slam, but it will be considerably faster.

    The deal::tricks procedure caches values, so that multiple calls with the same parameters on the same deal result in quick turn-around.

    This is useful if we are using the parscore in our query, or if we use the output format, gibpar, discussed later.

    parscore

    This routine determines the double-dummy par score for a deal. Because it calls deal::tricks 20 times - once for each declarer and denomination - it can take 20 seconds or more per deal. Not good for huge batches.

    Parscore takes as input the dealer and vulnerability:

    set result [parscore north NS]
    set contract [lindex $result 0]
    set declarer [lindex $result 1]
    set score    [lindex $result 2]
    set tricks   [lindex $result 3]
    set auction  [lindex $result 4]
    
    Vulnerability can be one of None, NS, EW, or All.

    The result returned is fairly complex - it consists of a list of elements.

    • The first element is a contract, in the form "2 spades doubled" or "2 spades." [ Double-dummy par scores are, of course, never redoubled. ]
    • The second element is the declarer.
    • The third element is the score
    • The fourth element is the number of tricks declarer can take.
    • The fifth is a stupid auction to get to the contract. If north is dealer and east is declarer in the double-dummy par contract of 4 clubs doubled, the auction will be "Pass 4C X Pass Pass Pass". Not very inspired, but needed for the gibpar application, below.
    [Why do we need to know the dealer? Suppose north and east are the only ones who can make 1NT, and that no higher contracts make. Then double-dummy par is 1NT by east if east is dealer, while it is 1NT by north if anybody else is dealer.]

    The gibpar format

    As soon as I got GIB, I wanted to use Deal to generate PBN files for GIB to use in play. It was trickier than I thought - GIB apparently wants a *score* in the PBN file. This was why I created the parscore command above - so that I could write out a PBN file with a score which was objective, rather than random.

    This format is used like any other format:

    C:\Deal30> deal -i format/gibpar 36 > myfile.pbn
    
    As with any other Deal format, format/gibpar can be used with filters:
    C:\Deal30> deal -i format/gibpar -i ex/1.tcl > myfile.pbn
    
    Once you've generated this PBN file, you can load it into GIB via the "Load Saved Deal" command.

    Competing against double-dummy par is grueling work - it's essentially playing a team game where everybody at the other table is an infallible psychic - both your "opponents" and your teammates. That means that any swings are due to errors at your table and/or luck. They will always bid that making 15% grand at the other table, for example.


    Silhouette Thomas Andrews (thomaso@best.com) Copyright 1996-2008. Deal is covered by the GNU General Public License.

    Plane Dealing graphic above created using POV-Ray.

    deal319/tcl_deal.c0000644000175200017520000003455611341057671012225 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include extern int getpid(); #include "deal.h" #include "vector.h" #include "stat.h" #include "tcl_dist.h" #include "formats.h" #include "additive.h" #include "stringbox.h" #include "dealtypes.h" #include "holdings.h" #include #include "getopt.h" #include #include "tcl_incl.h" typedef struct formatter { char *(*fn)(); } *FormatFN; Tcl_Interp *interp; void Tcl_ObjDelete(ClientData data) { Tcl_DecrRefCount((Tcl_Obj *)data); } void Tcl_AllocDelete(ClientData data) { Tcl_Free((char *)data); } int (*next_deal)() = start_deal; static Tcl_Obj *after_exp=0; static Tcl_Obj *main_exp=0; static int cachesize=0; static Tcl_Obj *resetCmds=NULL; static void create_cache_reset() { if (resetCmds==NULL) { Tcl_IncrRefCount(resetCmds=Tcl_NewListObj(0,0)); cachesize=0; } } static int do_reset_commands(Tcl_Interp *interp) { if (resetCmds!=NULL && cachesize!=0) { /* * Allow the resetCmds to cache data in the * next resetCmds */ Tcl_Obj *oldCmds=resetCmds; int i,count; Tcl_Obj **code; int result; cachesize=0; resetCmds=NULL; result=Tcl_ListObjGetElements(interp,oldCmds,&count,&code); if (result==TCL_OK) { for (i=count-1; i>=0; i--) { result=Tcl_GlobalEvalObj(interp,code[i]); if (result==TCL_RETURN) { /*fprintf(stderr,"Got return in reset\n");*/ return TCL_RETURN; } if (result==TCL_ERROR) { return TCL_ERROR; } } Tcl_ListObjReplace(interp,oldCmds,0,count,0,0); } Tcl_DecrRefCount(oldCmds); } return TCL_OK; } static void add_reset_cmd(Tcl_Interp *interp,Tcl_Obj *code) { int length; if (resetCmds==NULL) { create_cache_reset(); } Tcl_ListObjLength(interp,resetCmds,&length); Tcl_ListObjAppendElement(interp,resetCmds,code); cachesize++; } static int add_reset_cmds(TCLOBJ_PARAMS) TCLOBJ_DECL { int i=1; while (ifn(); if (format!=NULL) { Tcl_SetResult(interp,format,TCL_DYNAMIC); return TCL_OK; } else { Tcl_AppendResult(interp,argv[0]," failed due to error: ", Tcl_PosixError(interp),NULL); return TCL_ERROR; } } int tcl_write_deal (TCL_PARAMS) TCL_DECL { FormatFN fmt=(FormatFN)cd; char *format; FILE *file=stdout; finish_deal(); format=fmt->fn(); if (argc==2) { file=stderr; } if (format!=NULL) { fputs(format,file); Tcl_Free(format); return TCL_OK; } else { Tcl_AppendResult(interp,argv[0]," failed due to error: ", Tcl_PosixError(interp),NULL); return TCL_ERROR; } } int tcl_flush_deal (TCLOBJ_PARAMS) TCLOBJ_DECL { return TCL_OK; /* Default write flushing routing */ } int tcl_rotate_deal (TCL_PARAMS) TCL_DECL { if (argc!=2) { Tcl_AppendResult(interp, "wrong # of args: \"",argv[0]," \"",NULL); return TCL_ERROR; } rotate_deal(atoi(argv[1])); return TCL_OK; } int tcl_stacked_cards (TCLOBJ_PARAMS) TCLOBJ_DECL { Tcl_Obj *holdings[4]; int handnum, suit; int h[4]; if (objc!=2) { Tcl_AddErrorInfo(interp,"Usage: stacked_cards \n"); return TCL_ERROR; } handnum=getHandNumFromObj(interp,objv[1]); if (handnum==NOSEAT) { Tcl_AddErrorInfo(interp,"Invalid hand name\n"); return TCL_ERROR; } get_stacked_cards(handnum,h); for (suit=0; suit<4; suit++) { holdings[suit]=Tcl_NewHoldingObj(h[suit]); } Tcl_SetObjResult(interp,Tcl_NewListObj(4,holdings)); return TCL_OK; } int tcl_rand_cmd( TCLOBJ_PARAMS ) TCLOBJ_DECL { long res,tclres,modulus; res=random(); if (objc>1) { tclres=Tcl_GetLongFromObj(interp,objv[1],&modulus); if (tclres==TCL_ERROR) { return TCL_ERROR; } res %= modulus; Tcl_SetObjResult(interp,Tcl_NewIntObj(res)); } else { double dres = res * 1.0 / RANDOM_MAX; Tcl_SetObjResult(interp,Tcl_NewDoubleObj(dres)); } return TCL_OK; } int tcl_after_set(TCLOBJ_PARAMS) TCLOBJ_DECL { if (objc!=2) { return TCL_ERROR; } if (after_exp != 0) { Tcl_DecrRefCount(after_exp); } Tcl_IncrRefCount(after_exp=Tcl_DuplicateObj(objv[1])); return TCL_OK; } int tcl_seed_deal(TCLOBJ_PARAMS) TCLOBJ_DECL { int result,value; if (objc!=2) { return TCL_ERROR; } result=Tcl_GetIntFromObj(interp,objv[1],&value); if (result==TCL_OK) { #ifdef USE_RAND48 srand48(value); #else srandom(value); #endif } return TCL_OK; } int tcl_main_set(TCLOBJ_PARAMS) TCLOBJ_DECL { if (objc!=2) { return TCL_ERROR; } if (main_exp != 0) { Tcl_DecrRefCount(main_exp); } Tcl_IncrRefCount(main_exp=Tcl_DuplicateObj(objv[1])); return TCL_OK; } int tcl_deal_loop(TCLOBJ_PARAMS) TCLOBJ_DECL { int result; if (objc!=2) { return TCL_ERROR; } while (1) { result=tcl_deal_deck(cd,interp,objc,objv); if (result==TCL_RETURN) { return TCL_RETURN; } if (result==TCL_ERROR) { return TCL_ERROR; } result=Tcl_GlobalEvalObj(interp,main_exp); if (result==TCL_ERROR) { /* fprintf(stderr,"Error in eval loop: %s\n",Tcl_GetStringResult(interp)); */ return result; } if (result==TCL_RETURN) { Tcl_Obj *output=Tcl_GetObjResult(interp); int value; if (Tcl_GetIntFromObj(interp,output,&value)!=TCL_ERROR && value>0) { break; } } #ifdef DEBUG fprintf(stderr,"Rejected after %d cards dealt\n",complete_deal.dealt); #endif } return Tcl_GlobalEvalObj(interp,objv[1]); } static Tcl_Obj *logicObj[2]={ NULL, NULL}; static int tcl_init(TCLOBJ_PARAMS) TCLOBJ_DECL { return Tcl_Init(interp); } /* * implements the 'accept' and 'reject' commands */ int tcl_deal_control(TCLOBJ_PARAMS) TCLOBJ_DECL { int i=2,value,result; Tcl_Obj *iffound,*ifnotfound; int data; int found,nfound; char *logic; /* Either "if" of "unless" */ int length; if (logicObj[0]==NULL) { logicObj[0]=Tcl_NewBooleanObj(0); Tcl_IncrRefCount(logicObj[0]); logicObj[1]=Tcl_NewBooleanObj(1); Tcl_IncrRefCount(logicObj[1]); } data=(int)cd; /* True if 'accept', false if 'reject' */ if (objc==1) { Tcl_SetObjResult(interp,logicObj[data ? 1 : 0]); return TCL_RETURN; } logic=Tcl_GetStringFromObj(objv[1],&length); if (0==strcmp(logic,"if")) { iffound=logicObj[data!=0]; found=TCL_RETURN; ifnotfound=logicObj[data==0]; nfound=TCL_OK; } else if (0==strcmp(logic,"unless")) { iffound=logicObj[data==0]; found=TCL_OK; ifnotfound=logicObj[data!=0]; nfound=TCL_RETURN; } else { return TCL_ERROR; } for (i=2; i1) { fprintf(stderr,"Condition %s passed\n",Tcl_GetStringFromObj(objv[i],&length)); } return found; } } Tcl_IncrRefCount(ifnotfound); Tcl_SetObjResult(interp,ifnotfound); return nfound; } DEAL31_API int *Deal_Init(Tcl_Interp *interp) { int result; FormatFN compact=(struct formatter*)Tcl_Alloc(sizeof(struct formatter)); FormatFN deffmt=(struct formatter*)Tcl_Alloc(sizeof(struct formatter)); initializeLengths(); init_name_tables(); initializeDealTypes(interp); compact->fn=&format_deal_compact; Tcl_CreateCommand(interp,"write_deal_compact",tcl_write_deal, (ClientData)compact,NULL); Tcl_CreateCommand(interp,"format_deal_compact",tcl_format_deal, (ClientData)compact,NULL); deffmt->fn=&format_deal_verbose; Tcl_CreateCommand(interp,"write_deal",tcl_write_deal, (ClientData)deffmt,NULL); Tcl_CreateCommand(interp,"format_deal",tcl_format_deal, (ClientData)deffmt,NULL); Tcl_CreateCommand(interp,"write_deal_verbose",tcl_write_deal, (ClientData)deffmt,NULL); Tcl_CreateObjCommand(interp,"flush_deal",tcl_flush_deal, NULL,NULL); Tcl_CreateObjCommand(interp,"stacked",tcl_stacked_cards, NULL,NULL); Tcl_CreateCommand(interp,"rotatedeal",tcl_rotate_deal,NULL,NULL); Tcl_CreateCommand(interp,"sdev",tcl_sdev_define,NULL,NULL); Tcl_CreateObjCommand(interp,"correlation",tcl_correlation_define,NULL,NULL); HandCmd_Init(interp); Dist_Init(interp); Vector_Init(interp); Stringbox_Init(interp); IDealHolding_Init(interp); DDS_Init(interp); Tcl_CreateObjCommand(interp,"deal_deck",tcl_deal_deck,NULL,NULL); Tcl_CreateObjCommand(interp,"reset_deck",tcl_reset_deck,NULL,NULL); Tcl_CreateObjCommand(interp,"finish_deal",tcl_finish_deal,NULL,NULL); Tcl_CreateObjCommand(interp,"main",tcl_main_set,NULL,NULL); Tcl_CreateObjCommand(interp,"deal_finished",tcl_after_set,NULL,NULL); Tcl_CreateObjCommand(interp,"deal_loop",tcl_deal_loop,NULL,NULL); Tcl_CreateObjCommand(interp,"seed_deal",tcl_seed_deal,NULL,NULL); Tcl_CreateObjCommand(interp,"reject",tcl_deal_control,(ClientData)0,NULL); Tcl_CreateObjCommand(interp,"accept",tcl_deal_control,(ClientData)1,NULL); Tcl_CreateObjCommand(interp,"rand",tcl_rand_cmd,NULL,NULL); Tcl_CreateObjCommand(interp,"deal_reset_cmds",add_reset_cmds,NULL,NULL); Tcl_CreateObjCommand(interp,"deal_init_tcl",tcl_init,NULL,NULL); result=Tcl_VarEval(interp,"source deal.tcl",NULL); if (result==TCL_ERROR) { tcl_error(interp); } Tcl_VarEval(interp,"reset_deck",NULL); return TCL_OK; } static int executeScript(Tcl_Interp *interp, const char *argv0, int argc, char *argv[], const char *command) { int i, result; Tcl_Obj *list = Tcl_NewListObj(0,NULL); Tcl_SetVar(interp,"argv0",argv0,TCL_GLOBAL_ONLY); Tcl_SetVar2Ex(interp,"argc",NULL,Tcl_NewIntObj(argc),TCL_GLOBAL_ONLY); for (i=0;i1 && isdigit(*argv[1])) { count=atoi(argv[1]); argc--; argv++; } if (main_exp!=(Tcl_Obj *)0) { sprintf(tcl_command_string,"deal_loop %s",writecmd); argc--; argv++; } else { sprintf(tcl_command_string,"deal_deck ; %s",writecmd); } command=Tcl_NewStringObj(tcl_command_string,(int)strlen(tcl_command_string)); Tcl_IncrRefCount(command); for (i=1; i<=count; i++) { const char *s; result=Tcl_GlobalEvalObj(interp,command); if (result==TCL_ERROR) { tcl_error(interp); } if (result==TCL_RETURN) { break; } s=Tcl_GetStringResult(interp); if (*s=='e' && (0==strcmp("exit",s))) { break; } if (verbose) { fprintf(stderr,"Deal %d found after %d tries\n",i,count_deals); } } result=Tcl_VarEval(interp,flushcmd,NULL); if (result==TCL_ERROR) { tcl_error(interp); exit(1); } if (after_exp) { result=Tcl_GlobalEvalObj(interp,after_exp); if (result==TCL_ERROR) { tcl_error(interp); exit(1); } } return 0; } deal319/stringbox.c0000644000175200017520000002366011062564550012466 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "stringbox.h" #include typedef Tcl_UniChar Char; typedef struct string_box_base { int rows, columns; Char *start; int refcount; } *StringBoxBase; typedef struct string_box { StringBoxBase parent; int rows,columns; Char **strings; } *StringBox; static void clearStringBox(box) StringBox box; { int rows=box->rows, columns=box->columns; int r,c; for (r=0; rstrings[r][c] = ' '; } } } static int writeStringBox(interp,box,row,column,string) Tcl_Interp *interp; /* May be null. For error messages */ StringBox box; int row; int column; Char *string; { int rowcount=box->rows, columncount=box->columns; Char *boxstring; int startcolumn=column; Char c; if (row<0 || row>=rowcount || column>=columncount || column<0) { if (interp != (Tcl_Interp *)NULL) { char s[20]; sprintf(s,"%d %d",row,column); Tcl_AppendResult(interp,"illegal parameters \"",s,"\"",NULL); } return TCL_ERROR; } boxstring=box->strings[row]+column; while ((c=*(string++))!=0) { if (c=='\n') { row++; if (row>=rowcount) return TCL_OK; column=startcolumn; boxstring=box->strings[row]+column; continue; } if (columnrows*(box->columns+1)+1)); Char *rindex=result; for (row=0; rowrows; row++) { for (col=0; colcolumns; col++) { *(rindex++)=box->strings[row][col]; } *(rindex++)='\n'; } *(--rindex)=0; *lengthPtr = rindex - result; return result; } static Char *compactStringBox(box,lengthPtr) StringBox box; int *lengthPtr; { int row,col; Char *result=(Char *)Tcl_Alloc(sizeof(Char)*((box->rows)*(box->columns+1)+1)); Char *rindex=result; Char c,*lastnonspace; for (row=0; rowrows; row++) { lastnonspace=rindex; for (col=0; colcolumns; col++) { *(rindex++)=c=box->strings[row][col]; if (c!=' ') { lastnonspace=rindex; } } rindex=lastnonspace; *(rindex++)='\n'; } *(--rindex)=0; *lengthPtr = rindex-result; return result; } static StringBox newStringBox(rows,columns) int rows; int columns; { StringBoxBase parent; StringBox result; int i; if (rows<=0 || columns<=0) { return 0; } parent=(StringBoxBase)Tcl_Alloc(sizeof(struct string_box_base)); parent->rows=rows; parent->columns=columns; parent->start=(Char *)Tcl_Alloc(rows*columns*sizeof(Char)); parent->refcount=1; result=(StringBox)Tcl_Alloc(sizeof(struct string_box)); result->rows=rows; result->columns=columns; result->strings=(Char **)Tcl_Alloc(rows*sizeof(Char **)); for (i=0; istrings[i]=parent->start+i*columns; } result->parent=parent; clearStringBox(result); return result; } static StringBox subStringBox(interp,parentbox,rowloc,columnloc,rows,columns) Tcl_Interp *interp; /* For error messages only */ StringBox parentbox; int rowloc,columnloc; int rows; int columns; { StringBoxBase parent; StringBox result; int i; if (rows<=0 || columns<=0 || rowloc< 0 || columnloc<0) { goto error; } if (rows+rowloc>parentbox->rows || rows+columnloc>parentbox->columns) { goto error; } parent=parentbox->parent; parent->refcount++; result=(StringBox)Tcl_Alloc(sizeof(struct string_box)); result->rows=rows; result->columns=columns; result->strings=(Char **)Tcl_Alloc(rows*sizeof(Char **)); for (i=0; istrings[i]=parentbox->strings[rowloc+i]+columnloc; } result->parent=parent; clearStringBox(result); return result; error: if (interp != (Tcl_Interp *)NULL) { Tcl_AppendResult(interp, "subbox: illegal argument",NULL); } return 0; } void deleteStringBox(ClientData boxdata) { StringBox box=(StringBox)boxdata; Tcl_Free((char *)box->strings); #ifdef DEBUG fprintf(stderr,"Deleting stringbox\n"); #endif if (--(box->parent->refcount) <=0) { Tcl_Free((char *)box->parent->start); Tcl_Free((char *)box->parent); #ifdef DEBUG fprintf(stderr,"Deleting parent box\n"); #endif } Tcl_Free((char *)box); } static int tcl_string_box(TCLOBJ_PARAMS) TCLOBJ_DECL { const char *command; StringBox box=(StringBox)cd; int len; if (objc==1) { int length; Char *result = formatStringBox(box,&length); Tcl_Obj *unicode = Tcl_NewUnicodeObj(result,length); Tcl_SetObjResult(interp,unicode); Tcl_Free((char *)result); return TCL_OK; } command=Tcl_GetStringFromObj(objv[1],&len); if (command==NULL) { return TCL_ERROR; } if ('w'==(*command) && strcmp(command,"write")==0) { int row, col; if (objc!=5) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " write row column string\"",NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp,objv[2],&row)!=TCL_OK || Tcl_GetIntFromObj(interp,objv[3],&col)!=TCL_OK) { Tcl_AppendResult(interp,"\nbad row or column arguments: row=\"", Tcl_GetString(objv[2]), "\", column=\"", Tcl_GetString(objv[3]),"\"", NULL); return TCL_ERROR; } return writeStringBox(interp,box,row,col,Tcl_GetUnicode(objv[4])); } if (*command=='c' && strcmp(command,"clear")==0) { clearStringBox(box); return TCL_OK; } if (*command=='r' && strcmp(command,"rows")==0) { if (objc!=2) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ",command,"\"", NULL); return TCL_ERROR; } Tcl_SetObjResult(interp,Tcl_NewIntObj(box->rows)); return TCL_OK; } if (*command=='c' && strcmp(command,"columns")==0) { if (objc!=2) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ",command,"\"", NULL); return TCL_ERROR; } Tcl_SetObjResult(interp,Tcl_NewIntObj(box->columns)); return TCL_OK; } if (*command=='s' && strcmp(command,"subbox")==0) { StringBox subbox; int rows=0,columns=0,rowloc=0,columnloc=0; if (objc!=7 && objc!=5) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " subbox name rowloc columnloc [ rows columns ]\"", (Char *)NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp,objv[3],&rowloc) != TCL_OK) { if (rowloc<0) { Tcl_AppendResult(interp,"Illegal row location \"", Tcl_GetString(objv[3]),"\" passed to subbox routine",NULL); } return TCL_ERROR; } if (Tcl_GetIntFromObj(interp,objv[4],&columnloc) != TCL_OK) { if (columnloc<0) { Tcl_AppendResult(interp,"Illegal column location \"", Tcl_GetString(objv[4]),"\" passed to subbox routine",NULL); } return TCL_ERROR; } if (objc==7) { if ((Tcl_GetIntFromObj(interp,objv[5],&rows) != TCL_OK)) { return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp,objv[6],&columns) != TCL_OK)) { return TCL_ERROR; } } if (rowloc<0) { rowloc=(box->rows)+rowloc; } if (columnloc<0) { columnloc=(box->columns)+columnloc; } if (rows<=0) { rows=rows+(box->rows)-rowloc; } if (columns<=0) { columns=columns+(box->columns)-columnloc; } subbox=subStringBox(interp,box,rowloc,columnloc,rows,columns); if (subbox==(StringBox)0) { return TCL_ERROR; } Tcl_CreateObjCommand(interp,Tcl_GetString(objv[2]),tcl_string_box,subbox,deleteStringBox); return TCL_OK; } if (*command=='c' && strcmp(command,"compact")==0) { int length; Char *result = compactStringBox(box,&length); Tcl_Obj *unicode = Tcl_NewUnicodeObj(result,length); Tcl_SetObjResult(interp,unicode); Tcl_Free((char *)result); return TCL_OK; } Tcl_AppendResult(interp, "unknown stringbox operation: \"", Tcl_GetString(objv[0]), " ", command," ...\"",NULL); return TCL_ERROR; } int tcl_create_string_box(TCLOBJ_PARAMS) TCLOBJ_DECL { int rows,columns; StringBox box; if (objc!=4) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " name rows columns\"",(Char *)NULL); return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp,objv[2],&rows) != TCL_OK) || (rows<=0)) { Tcl_AddErrorInfo(interp, "\n (reading value of )"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp,objv[3],&columns) != TCL_OK || (columns<=0)) { Tcl_AddErrorInfo(interp, "\n (reading value of )"); return TCL_ERROR; } box=newStringBox(rows,columns); Tcl_CreateObjCommand(interp,Tcl_GetString(objv[1]),tcl_string_box,box,deleteStringBox); return TCL_OK; } int Stringbox_Init(interp) Tcl_Interp *interp; { #if 0 int code; code = Tcl_PkgProvide(interp,"stringbox","1.0"); if (code != TCL_OK) { return code; } #endif Tcl_CreateObjCommand(interp,"stringbox",tcl_create_string_box,NULL,NULL); return TCL_OK; } deal319/ddsLookup.cpp0000644000175200017520000000013111062643575012744 0ustar cbecbe#include "ddsLookup.h" int highestRankLookup[8192]; holding_t topCardsLookup[14][8192]; deal319/format/0000755000175200017520000000000011224443222011554 5ustar cbecbedeal319/format/ddline0000644000175200017520000000307311063454127012750 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: ddline 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # set ddline(counter) 0 proc write_deal {} { global ddline set line [list] set dd [list] foreach suit {spades hearts diamonds clubs notrump} { puts -nonewline stderr "." foreach hand {north east south west} { set dummy [deal::tricks $hand $suit] } } foreach hand {north east south west} { lappend line [join [$hand] "."] set handdd [list] foreach suit {spades hearts diamonds clubs notrump} { lappend handdd [deal::tricks $hand $suit] } lappend dd $handdd } puts "[join $line |]|[join $dd |]" incr ddline(counter) if {$ddline(counter)%10==0} { puts stderr "Finished #$ddline(counter)" } else { } while {[file exists "lock.txt"]} { puts stderr "Sleeping a bit... lock.txt exists" after 10000 } } deal319/format/count0000644000175200017520000000174011063454127012640 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: count 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # set dealCount 0 proc write_deal {} { global dealCount incr dealCount if {$dealCount%1000==0} { puts stderr $dealCount } } proc flush_deal {} { global dealCount puts $dealCount } deal319/format/simpleokb0000644000175200017520000000265611063454127013504 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: simpleokb 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # stringbox okbox 14 70 okbox write 4 15 "West" okbox write 4 50 "East" okbox write 0 30 "North" okbox write 10 30 "South" okbox subbox okbox.north 0 36 4 15 okbox subbox okbox.south 10 36 4 15 okbox subbox okbox.east 5 50 4 15 okbox subbox okbox.west 5 15 4 15 proc write_deal {} { foreach hand {west south north east} { okputhand $hand } puts "[okbox]" puts " -----------------------------" } proc okputhand {hand} { okbox.$hand clear set rowhand 0 foreach char {S H D C} suit {spades hearts diamonds clubs} { okbox.$hand write $rowhand 0 "$char [$hand -void --- $suit]" incr rowhand } } deal319/format/gibpar0000644000175200017520000000002211062564546012752 0ustar cbecbesource format/par deal319/format/default0000644000175200017520000000407311101413626013126 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: default 277 2008-10-27 17:36:14Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # namespace eval formatter { variable loc set loc(row:east) 4 set loc(col:east) 19 set loc(row:north) 0 set loc(col:north) 10 set loc(row:west) 4 set loc(col:west) 1 set loc(row:south) 8 set loc(col:south) 10 variable suitletters [list S: H: D: C:] variable suitsunicode [list "\u2660" "\u2665" "\u2666" "\u2663"] variable suitsymbols $suitletters variable voidsymbol "---" stringbox ::formatter::writer 12 60 foreach hand {north east west south} { ::formatter::writer subbox ::formatter::writer.$hand $loc(row:$hand) $loc(col:$hand) 4 16 } proc puthand {hand} { variable suitsymbols variable voidsymbol writer.$hand clear set row 0 foreach suit {spades hearts diamonds clubs} symbol $suitsymbols { writer.$hand write $row 0 "$symbol [$hand -void $voidsymbol $suit]" incr row } } proc write_deal {} { foreach hand {north east south west} { puthand $hand } puts stdout [writer compact] } } if {$deal::unicode && [info exists env(LANG)] && [string first "UTF-8" [string toupper $env(LANG)]]>=0} { set ::formatter::suitsymbols $::formatter::suitsunicode } proc write_deal {} { formatter::write_deal puts stdout "--------------------------" } proc flush_deal {} { } deal319/format/parArticle0000644000175200017520000000356111063454127013601 0ustar cbecbe# # parArticle - an output format used for generating HTML with comments # which include ways to load into GIB's bridge.exe or iDeal. # # Copyright (C) 1996-2001, Thomas Andrews # # $Id: parArticle 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/parscore.tcl set particle(num) 0 set particle(dealer) [list north east south west] set particle(vul) [list None NS EW Both NS EW Both None EW Both None NS Both None NS EW] proc par_upcase {word} { set first [string toupper [string range $word 0 0]] set rest [string range $word 1 end] append first $rest } proc write_deal {} { global particle particle set num $particle(num) set dealer [lindex $particle(dealer) [expr {$num%4}]] set vul [lindex $particle(vul) [expr {$num%16}]] incr num puts stderr "$num $dealer $vul" set par [parscore $dealer $vul] set contract [lindex $par 0] set declarer [lindex $par 1] set score [lindex $par 2] puts "Deal #$num" puts "Dealer: [par_upcase $dealer]" puts "Vulnerability: $vul vul" puts "Contract: $contract by [par_upcase $declarer]" puts "N/S score: $score" puts "" puts -nonewline [format_deal] incr particle(num) } deal319/format/none0000644000175200017520000000146711063454127012455 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: none 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # proc write_deal {} { } deal319/format/okb0000644000175200017520000000405711063454127012267 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: okb 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This is set up to make output look like an okbridge screen. # set okrow(east) 5 set okcol(east) 50 set okrow(west) 5 set okcol(west) 15 set okrow(south) 10 set okcol(south) 36 set okrow(north) 0 set okcol(north) 36 proc okputhand {hand} { okbox.$hand clear set rowhand 0 foreach suit {spades hearts diamonds clubs} letter {S H D C} { okbox.$hand write $rowhand 0 "$letter [$hand -void --- $suit]" incr rowhand } } proc okinit {} { global okrow global okcol stringbox okbox 14 70 okbox subbox okbox.center 4 30 6 18 okbox.center write 0 0 "------------------" okbox.center write 1 0 "| |" okbox.center write 2 0 "| |" okbox.center write 3 0 "| |" okbox.center write 4 0 "| |" okbox.center write 5 0 "------------------" okbox write 4 15 "West" okbox write 4 50 "East" okbox write 0 30 "North" okbox write 10 30 "South" foreach hand {north east west south} { okbox subbox okbox.$hand $okrow($hand) $okcol($hand) 4 14 } } okinit proc write_deal {} { foreach hand {west south north east} { okputhand $hand } puts "[okbox compact]" puts "---------------------------------------------------------------------------" } deal319/format/pbn0000644000175200017520000000206311063454127012266 0ustar cbecbe# pbn - A really crude pbn line output format # # Copyright (C) 1996-2001, Thomas Andrews # # $Id: pbn 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # proc write_deal {} { foreach hand {north east south west} { set fmt($hand) "[$hand spades].[$hand hearts].[$hand diamonds].[$hand clubs]" } puts "\[Deal \"N:$fmt(north) $fmt(east) $fmt(south) $fmt(west)\"\]" puts "" } deal319/format/numeric0000644000175200017520000000211711063454127013151 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: numeric 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # set handno(south) 2 set handno(west) 3 set handno(north) 0 set handno(east) 1 proc write_deal {} { set string "" global handno foreach suit {S H D C} { foreach card {A K Q J T 9 8 7 6 5 4 3 2} { append string $handno([whogets $card$suit]) } } puts $string } deal319/format/practice0000644000175200017520000000531311224443222013273 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: practice 308 2009-04-06 20:38:34Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # This writes hands to seperate files set handcomment "" rename write_deal old_write_deal set suit(S) spades set suit(H) hearts set suit(D) diamonds set suit(C) clubs # Default output prefix to "out" if {[catch {set output}]} { set output out } # Default hands to write - all of them if {[catch {set hands}]} { set hands {south north east west} } # create file handles for writing foreach hand $hands { set ofile($hand) [open "$output.$hand" "w"] stringbox box.$hand 7 80 for {set i 0; set j 0} {$i<4} {incr i ; incr j 20} { box.$hand subbox box.$hand.$i 0 $j 7 20 } puts $ofile($hand) " $hand hands" set practicecolumn 0 set practicecount 1 } proc write_hand {hand} { global practicecolumn global practicecount global handcomment global suit set box box.$hand.$practicecolumn # write number of deal at top of hand box, about midway across $box write 0 5 "*$practicecount*" set i 1 foreach suitl {S H D C} { $box write $i 2 "$suitl [$hand -void --- $suit($suitl)]" incr i } $box write 6 0 "$handcomment" } proc flush_writing {} { global hands global ofile global practicecolumn if {$practicecolumn!=0} { foreach hand $hands { puts $ofile($hand) "[box.$hand compact]" puts $ofile($hand) "=============================================================================" flush $ofile($hand) box.$hand clear } } } proc flush_deal {} { global ofile global hands flush_writing foreach hand $hands { close $ofile($hand) } } proc write_deal {} { global hands global handcomment global practicecolumn global practicecount global ofile foreach hand $hands { write_hand $hand } if {$practicecolumn==3} { flush_writing set practicecolumn 0 } else { incr practicecolumn } puts "Deal: $practicecount" old_write_deal set handcomment "" incr practicecount } deal319/format/onehand0000644000175200017520000000345411224443222013121 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: onehand 306 2009-04-06 20:37:14Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # This writes hands to seperate files stringbox handbox 5 80 for {set i 0; set j 0} {$i<4} {incr i ; incr j 20} { handbox subbox handbox.$i 0 $j 5 20 } set column 0 set handcount 1 set outputhand north set suit(S) spades set suit(H) hearts set suit(D) diamonds set suit(C) clubs proc write_hand {} { global column global handcount global outputhand global suit # write number of deal at top of hand box, about midway across handbox.$column write 0 5 "*$handcount*" set i 1 foreach suitl {S H D C} { handbox.$column write $i 2 "$suitl [$outputhand -void --- $suit($suitl)]" incr i } } proc flush_deal {} { global hands global ofile global column if {$column!=0} { puts stdout "[handbox compact]" puts stdout "=============================================================================" handbox clear } } proc write_deal {} { global column global handcount write_hand incr handcount if {$column==3} { flush_deal set column 0 } else { incr column } } deal319/format/article0000644000175200017520000000264611063454127013141 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: article 255 2008-09-15 12:43:02Z thomasoa $ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # set article_file random.txt proc write_deal {} { global article_file article_file set fh [open $article_file "a"] puts $fh "" puts $fh "
    "
        puts $fh [format_deal]
        puts $fh "
    " close $fh } deal319/format/par0000644000175200017520000000750211063454127012274 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: par 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/parscore.tcl namespace eval par { variable par set par(num) 1 set par(incr) 1 set par(dealer) [list north east south west] set par(vul) [list None NS EW All NS EW All None EW All None NS All None NS EW] if {[info commands clock]=="clock"} { set par(Date) [clock format [clock seconds] -format "%Y.%m.%d"] } else { set par(Date) "1965.01.01" } foreach seat {North East South West} { set par($seat) "$seat" } set par(letter:north) N set par(letter:east) E set par(letter:west) W set par(word:doubled) X set par(word:redoubled) XX set par(word:) "" set par(lho:south) W set par(lho:west) N set par(lho:north) E set par(lho:east) S proc pbn_write_line {key value} { puts "\[$key \"$value\"\]" } proc getVul {} { variable par set vullist $par(vul) set num $par(num) set index [expr {($num-1)%[llength $vullist]}] lindex $vullist $index } proc dealerOrder {args} { variable par set par(dealer) $args } proc vulOrder {args} { variable par set par(vul) $args } proc getDealer {} { variable par set dlrlist $par(dealer) set num $par(num) set index [expr {($num-1)%[llength $dlrlist]}] lindex $dlrlist $index } proc pbn_contract {contract} { variable par set level [lindex $contract 0] set denom [lindex $contract 1] set dbl [lindex $contract 2] append level [par_first_upper $denom] $par(word:$dbl) } proc write_deal {} { variable par set num $par(num) set dealer [getDealer] set vul [getVul] incr par(num) $par(incr) puts stderr "Computing par for deal $num $dealer $vul" set mypar [parscore $dealer $vul] set contract [lindex $mypar 0] set declarer [lindex $mypar 1] set score [lindex $mypar 2] set tricks [lindex $mypar 3] set auction [lindex $mypar 4] pbn_write_line Date $par(Date) pbn_write_line Board $num foreach seat {West North East South} { pbn_write_line $seat $par($seat) } pbn_write_line Dealer [par_first_upper $dealer] pbn_write_line Vulnerable $vul foreach hand {north east south west} { set fmt($hand) "[$hand spades].[$hand hearts].[$hand diamonds].[$hand clubs]" } pbn_write_line Deal "N:$fmt(north) $fmt(east) $fmt(south) $fmt(west)" pbn_write_line Contract [pbn_contract $contract] pbn_write_line Declarer [par_first_upper $declarer] pbn_write_line Result $tricks pbn_write_line Score "NS $score" puts "{" ::formatter::write_deal foreach hand {north east south west} { foreach denom {clubs diamonds hearts spades notrump} { puts "$hand makes [::deal::tricks $hand $denom] tricks in $denom" } } puts "}" pbn_write_line Auction [par_first_upper $dealer] set count 0 foreach bid $auction { if {$count==4} { puts "" set count 0 } if {$count>0} { puts -nonewline " " } puts -nonewline $bid incr count } puts "" if {$declarer != ""} { pbn_write_line Play $par(lho:$declarer) puts "*" puts "" } } } proc write_deal {} { ::par::write_deal } deal319/ddsInterface.h0000644000175200017520000000213211224443222013026 0ustar cbecbe/* * Broken out from dds.h * This file is the essential external "C" face to the dds.cpp file */ #ifndef __DDSINTERFACE_H__ #define __DDSINTERFACE_H__ #if 0 #define BENCH #endif #if defined(_WIN32) # define DLLEXPORT __declspec(dllexport) # define STDCALL __stdcall #else #if !defined(DLLEXPORT) # define DLLEXPORT #endif # define STDCALL # define INT8 char #endif #ifdef __cplusplus # define EXTERN_C extern "C" #else # define EXTERN_C #endif typedef unsigned short int holding_t; struct diagram { holding_t cards[4][4]; }; struct deal { int trump; int first; int currentTrickSuit[3]; int currentTrickRank[3]; struct diagram remaining; }; struct futureTricks { int nodes; #ifdef BENCH int totalNodes; #endif int cards; int suit[13]; int rank[13]; int equals[13]; int score[13]; }; #include EXTERN_C int SolveBoard(struct deal dl, int target, int solutions, int mode, struct futureTricks *futp); EXTERN_C void DDSInitStart(); EXTERN_C holding_t distinctUnplayedCards(holding_t origHolding, holding_t played,holding_t *sequence); #endif deal319/dds.h0000644000175200017520000003335011224443222011213 0ustar cbecbe/* POrtability-macros header prefix */ #ifndef __DDS_H__ #define __DDS_H__ #ifdef __cplusplus #include using namespace std; #endif #include "ddsInterface.h" #include "ddsInline.h" #include "ddsLookup.h" #include "Holding.h" #define LONGLONG long long /* end of portability-macros section */ /*#define BENCH*/ #include #include #include #include /*#define STAT*/ /* Define STAT to generate a statistics log, stat.txt */ /*#define TTDEBUG*/ /* Define TTDEBUG to generate transposition table debug information */ /*#define CANCEL*/ /* Define CANCEL to get support for cancelling ongoing search */ #ifdef TTDEBUG #define SEARCHSIZE 20000 #else #define SEARCHSIZE 1 #endif #define CANCELCHECK 200000 #if defined(INFINITY) # undef INFINITY #endif #define INFINITY 32000 #define MAXNODE 1 #define MINNODE 0 #define TRUE 1 #define FALSE 0 #define MOVESVALID 1 #define MOVESLOCKED 2 #define NSIZE 100000 #define WSIZE 100000 #define LSIZE 20000 #define NINIT 2*250000/*400000*/ #define WINIT 2*700000/*1000000*/ #define LINIT 2*50000 #define Max(x, y) (((x) >= (y)) ? (x) : (y)) #define Min(x, y) (((x) <= (y)) ? (x) : (y)) struct relRanksType { int aggrRanks; int winMask; }; class RelativeRanksFinder { protected: struct { relRanksType suits[4]; } relative[8192]; struct diagram originalsBySuitFirst; public: inline RelativeRanksFinder() { for (int suit=0; suit<4; suit++) { for (int seat=0; seat<4; seat++) { originalsBySuitFirst.cards[suit][seat]=0; } } } inline const struct relRanksType &operator ()(int suit,holding_t index) const { return relative[index&8191].suits[suit]; } inline void initialize(const struct diagram &diagram) { int newDiagram = 0; int seat, suit; for (suit=0; suit<4; suit++) { for (seat=0; seat<4; seat++) { if (diagram.cards[seat][suit] != originalsBySuitFirst.cards[suit][seat]) { newDiagram = 1; } originalsBySuitFirst.cards[suit][seat]=diagram.cards[seat][suit]; } } if (newDiagram) { holding_t topBitRank = 1; for (int suit=0; suit<4; suit++) { relative[0].suits[suit].aggrRanks = 0; relative[0].suits[suit].winMask = 0; } for (int ind=1; ind<8192; ind++) { if (ind&(topBitRank<<1)) { topBitRank <<= 1; } compute(ind, topBitRank); } } } protected: inline void compute(const holding_t ind,const holding_t topBitRank) { int seat, suit; relative[ind] = relative[ind^topBitRank]; for (suit=0; suit<=3; suit++) { struct relRanksType &relRanks = relative[ind].suits[suit]; for (seat=0; seat<=3; seat++) { if (originalsBySuitFirst.cards[suit][seat] & topBitRank) { relRanks.aggrRanks = (relRanks.aggrRanks >> 2) | (seat << 24); relRanks.winMask = (relRanks.winMask >> 2) | (3 << 24); break; } } } } }; extern const RelativeRanksFinder &rel; struct gameInfo { /* All info of a particular deal */ int vulnerable; int declarer; int contract; int leadSeat; int leadSuit; int leadRank; int first; int noOfCards; struct diagram diagram; /* 1st index is seat id, 2nd index is suit id */ }; struct moveType { unsigned char suit; unsigned char rank; holding_t sequence; /* Whether or not this move is the first in a sequence */ short int weight; /* Weight used at sorting */ inline moveType() { suit=0; rank=0; sequence=0; weight=0; } }; struct movePlyType { struct moveType move[14]; int current; int last; }; struct highCardType { int rank; int seat; }; struct makeType { holding_t winRanks[4]; }; struct nodeCardsType { char ubound; /* ubound and lbound for the N-S side */ char lbound; char bestMoveSuit; char bestMoveRank; char leastWin[4]; }; struct posStackItem { int first; /* Seat that leads the trick for each ply*/ int high; /* Seat that is presently winning the trick */ struct moveType move; /* Presently winning move */ holding_t winRanks[4]; /* Cards that win by rank, index by suit */ }; struct pos { struct posStackItem stack[50]; struct diagram diagram; /* 1st index is seat, 2nd index is suit id */ int orderSet[4]; int winOrderSet[4]; int winMask[4]; int leastWin[4]; holding_t removedRanks[4]; /* Ranks removed from board, index is suit */ unsigned char length[4][4]; holding_t aggregate[4]; char ubound; char lbound; char bestMoveSuit; char bestMoveRank; int seatRelFirst; /* The current seat, relative first seat */ int tricksMAX; /* Aggregated tricks won by MAX */ struct highCardType winner[4]; /* Winning rank of the trick, index is suit id. */ struct highCardType secondBest[4]; /* Second best rank, index is suit id. */ inline void removeBitRank(int suit,holding_t bitRank) { removedRanks[suit] |= bitRank; } inline void removeRank(int suit,int rank) { removeBitRank(suit,BitRank(rank)); } inline void restoreBitRank(int suit, holding_t bitRank) { removedRanks[suit] &= (~bitRank); } inline void restoreRank(int suit,int rank) { restoreBitRank(suit,BitRank(rank)); } inline int isRemovedBitRank(int suit, holding_t bitRank) const { return (removedRanks[suit] & bitRank); } inline int isRemoved(int suit, int rank) const { return isRemovedBitRank(suit,BitRank(rank)); } inline int hasCardBitRank(int seat, int suit, holding_t bitRank) const { return (diagram.cards[seat][suit] & bitRank); } inline int hasCard(int seat,int suit, int rank) const { return hasCardBitRank(seat,suit,BitRank(rank)); } inline void getSuitLengths(LONGLONG &lengths,int relSeat = 0) const { int seat, suit; lengths = 0; for (suit=0; suit<=2; suit++) { for (seat=0; seat<=3; seat++) { lengths = lengths << 4; lengths |= length[(relSeat+seat)%4][suit]; } } } inline void computeOrderSet() { for (int suit=0; suit<4; suit++) { holding_t aggr = 0; for (int seat=0; seat<4; seat++) { aggr |= diagram.cards[seat][suit]; } aggregate[suit] = aggr; orderSet[suit] = rel(suit,aggr).aggrRanks; } } inline void computeWinData(int suit, holding_t winners) { holding_t aggr = 0; holding_t w = smallestRankInSuit(winners); int seat, wm; for (seat=0; seat<4; seat++) { aggr |= (diagram.cards[seat][suit] & (-w)); } winMask[suit] = rel(suit,aggr).winMask; winOrderSet[suit] = rel(suit,aggr).aggrRanks; wm = smallestBitInInteger(winMask[suit]); leastWin[suit] = InvWinMask(wm); } inline void winAdapt(const int depth, const struct nodeCardsType *cp, const holding_t aggr[]) { int ss; for (ss=0; ss<=3; ss++) { stack[depth].winRanks[ss] = getTopCards(aggr[ss],(int)cp->leastWin[ss]); } } }; struct posSearchType { struct winCardType * posSearchPoint; LONGLONG suitLengths; struct posSearchType * left; struct posSearchType * right; }; struct winCardType { int orderSet; int winMask; struct nodeCardsType * first; struct winCardType * prevWin; struct winCardType * nextWin; struct winCardType * next; }; struct evalType { int tricks; unsigned short int winRanks[4]; }; struct ttStoreType { struct nodeCardsType * cardsP; char tricksLeft; char target; char ubound; char lbound; unsigned char first; unsigned short int suit[4][4]; }; struct ContractInfo { const static int nextSuitArray[4][4]; int trumpContract; int trump; int _firstSuit; const int *_nextSuit; inline void initialize(int trumpContract,int trump) { this->trumpContract = trumpContract; this->trump = trump; if (!trumpContract ) { _firstSuit = 0; _nextSuit = nextSuitArray[0]; } else { _firstSuit = trump; _nextSuit = nextSuitArray[trump]; } } inline ContractInfo() { initialize(0,-1); } inline ContractInfo(const ContractInfo &contract) { trumpContract = contract.trumpContract; trump = contract.trump; _firstSuit = contract._firstSuit; _nextSuit = contract._nextSuit; } inline int isTrump(int suit) const { return (trumpContract && (trump==suit)); } inline int notTrumpWithTrump(int suit) const { return (trumpContract && (trump!=suit)); } inline int firstSuit() const { return _firstSuit; } inline int nextSuit(int suit) const { return _nextSuit[suit]; } inline int betterMove(const struct moveType &nextMove,const struct moveType &bestMove) const { if (bestMove.suit==nextMove.suit) { if (nextMove.rank>bestMove.rank) { return TRUE; } else { return FALSE; } } else if (isTrump(nextMove.suit)) { return TRUE; } else { return FALSE; } } }; struct GLOBALS { protected: public: ContractInfo _contract; RelativeRanksFinder rel; inline void setContract(int trump=-1) { _contract.initialize(trump>=0 && trump<=3,trump); } inline const ContractInfo &getContract() const { return _contract; } }; extern struct gameInfo game; extern struct gameInfo * gameStore; extern struct ttStoreType * ttStore; extern struct nodeCardsType * nodeCards; extern struct winCardType * winCards; extern struct pos lookAheadPos; /* extern struct moveType move[13]; */ extern struct movePlyType movePly[50]; extern struct posSearchType * posSearch; extern struct searchType searchData; extern struct moveType forbiddenMoves[14]; /* Initial depth moves that will be excluded from the search */ extern struct moveType initialMoves[4]; extern struct moveType highMove; extern struct moveType * bestMove; extern struct winCardType **pw; extern struct nodeCardsType **pn; extern struct posSearchType **pl; extern holding_t iniRemovedRanks[4]; extern holding_t relRankInSuit[4][4]; extern int sum; extern int score1Counts[50], score0Counts[50]; extern int c1[50], c2[50], c3[50], c4[50], c5[50], c6[50], c7[50], c8[50], c9[50]; extern int nodeTypeStore[4]; /* Look-up table for determining if node is MAXNODE or MINNODE */ #if 0 extern int lho[4], rho[4], partner[4]; #endif extern int nodes; /* Number of nodes searched */ extern int no[50]; /* Number of nodes searched on each depth level */ extern int payOff; extern int iniDepth; extern int treeDepth; extern int tricksTarget; /* No of tricks for MAX in order to meet the game goal, e.g. to make the contract */ extern int tricksTargetOpp; /* Target no of tricks for MAX opponent */ extern int targetNS; extern int targetEW; extern int seatToPlay; extern int nodeSetSize; extern int winSetSize; extern int lenSetSize; extern int lastTTstore; extern int searchTraceFlag; extern int countMax; extern int depthCount; extern int highSeat; extern int nodeSetSizeLimit; extern int winSetSizeLimit; extern int lenSetSizeLimit; extern int estTricks[4]; extern int recInd; extern int suppressTTlog; extern unsigned char suitChar[4]; extern unsigned char rankChar[15]; extern unsigned char seatChar[4]; extern int cancelOrdered; extern int cancelStarted; extern int threshold; extern unsigned char cardRank[15], cardSuit[5], cardSeat[4]; extern FILE * fp2, *fp7, *fp11; /* Pointers to logs */ void InitStart(void); void InitGame(int gameNo, int moveTreeFlag, int first, int seatRelFirst,struct pos &position); void InitSearch(struct pos * posPoint, int depth, struct moveType startMoves[], int first, int mtd); int ABsearch(struct pos * posPoint, int target, int depth); struct makeType Make(struct pos * posPoint, int depth); int MoveGen(const struct pos * posPoint, int depth); void InsertSort(int n, int depth); void UpdateWinner(struct pos * posPoint, int suit); void UpdateSecondBest(struct pos * posPoint, int suit); inline int WinningMove(const struct moveType &mvp1,const struct moveType &mvp2); inline unsigned short int CountOnes(unsigned short int b); int AdjustMoveList(void); int QuickTricks(struct pos * posPoint, int seat, int depth, int target, int *result); int LaterTricksMIN(struct pos *posPoint, int seat, int depth, int target); int LaterTricksMAX(struct pos *posPoint, int seat, int depth, int target); struct nodeCardsType * CheckSOP(struct pos * posPoint, struct nodeCardsType * nodep, int target, int tricks, int * result, int *value); struct nodeCardsType * UpdateSOP(struct pos * posPoint, struct nodeCardsType * nodep); struct nodeCardsType * FindSOP(struct pos * posPoint, struct winCardType * nodeP, int firstSeat, int target, int tricks, int * valp); struct nodeCardsType * BuildPath(struct pos * posPoint, struct posSearchType *nodep, int * result); void BuildSOP(struct pos * posPoint, int tricks, int firstSeat, int target, int depth, int scoreFlag, int score); struct posSearchType * SearchLenAndInsert(struct posSearchType * rootp, LONGLONG key, int insertNode, int *result); void Undo(struct pos * posPoint, int depth); int CheckDeal(struct moveType * cardp); inline int InvBitMapRank(holding_t bitMap); int InvWinMask(int mask); void ReceiveTTstore(struct pos *posPoint, struct nodeCardsType * cardsP, int target, int depth); int NextMove(struct pos *posPoint, int depth); int DumpInput(int errCode, struct deal dl, int target, int solutions, int mode); void Wipe(void); void AddNodeSet(void); void AddLenSet(void); void AddWinSet(void); #endif deal319/tcl_dist.h0000644000175200017520000000155611062564550012261 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "tcl_incl.h" extern int Dist_Init PROTO((Tcl_Interp *)); extern void printDistTable PROTO((void)); deal319/makecounttable.c0000644000175200017520000000417211062564550013442 0ustar cbecbe/* * makecounttable.c - This is a standalone utility which, when run, * creates the file counttable.c. counttable.c is just a lookup * table method to count the bits in a holding. * * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include /* * This is a speed consideration issue. * I've added "bit representations" of the * suits holding for each hand. AQT7, for example, * is represented as: * * 1 0 1 0 1 0 0 1 0 0 0 0 0 * * the "counttable" is just a lookup table which holds * the number of bits set, that is, the number of cards * held in the suit. This table has 2^13=8192 entries, so instead * of shipping a 33k file with the source kit, I ship * this smaller source file which creates the source file on the * fly. * * This sort of table could also be used to compute losers in * a suit or HCP in a suit. In the case of HCP, just examine * the table in "deal.c", in the hcp_count function. * */ int counttable[8192]; /* Fast lookup for suit lengths */ void make_counttable() { int i,j; for (i=0; i<8192; i++) { counttable[i]=0; for (j=0; j<13; j++) { if (i & (1< #include "deck.h" #include "tcl.h" typedef struct _HandH { int suit[4]; } RawHand; typedef struct _DealH { RawHand hand[4]; } RawDeal,RawDist; extern RawDeal globalDeal; extern RawDist globalDist; #define HoldingHas(holding,rank) (holding & (1<<(12-(rank)))) #define HANDHASCARD(hand,card) HoldingHas(hand.suit[SUIT(card)],RANK(card)) #define DEALHANDHASCARD(deal,hnum,card) HANDHASCARD(deal.hand[hum],card) #define HAS(hand,suit,rank) DEALHANDHASCARD(globalDeal,hand,suit,rank) #define HASCARD(hand,card) HAS(hand,SUIT(card),RANK(card)) #define HASCARD2(hptr,card) HoldingHas(hptr[SUIT(card)],RANK(card)) #define count_suit(hnum,suitnum) globalDist.hand[hnum].suit[suitnum] extern char suits[]; extern char cards[]; extern const unsigned short int counttable[]; /* These exist for backward compatibility, and are initialized with pointers into globalDeal and globalDist. */ extern int *distributions[]; extern int *holdings[]; int reset_deck(); int deal_deck(); int read_deal(); /* char *format_deal(); */ char *format_deal_compact(); char *format_deal_verbose(); int start_deal(); void finish_deal(); void deal_hand PROTO((int /*hand*/)); /* * Lookup tables which key on characters to return * the associated hand, suit, and card numbers */ extern int hand_name_table[256]; extern int suit_name_table[256]; extern int card_name_table[256]; void init_name_tables(); int Dist_Init PROTO((Tcl_Interp *)); int Vector_Init PROTO((Tcl_Interp *)); int HandCmd_Init PROTO((Tcl_Interp *)); int DealControl_Init PROTO((Tcl_Interp *)); int DDS_Init PROTO((Tcl_Interp *)); int count_controls PROTO((int /* holding */, void */* dummy */)); int count_hcp PROTO((int /* holding */, void */* dummy */)); int count_losers PROTO((int /* holding */, void * /* dummy */)); int put_card PROTO((int, int)); int put_hand PROTO((int, char *)); int put_holdings PROTO((int, int*)); int put_holding PROTO((int hand, int suit, int card)); extern int count_deals; extern int verbose; int card_num PROTO((char *)); void rotate_deal PROTO((int)); void get_stacked_cards PROTO((int,int*)); struct deck_stacker { int card[52]; /* What card is in the position */ int whom[52]; /* To whom is this card slated to go? */ int where[52]; /* Is card placed, and where? */ int handcount[4]; /* How man cards placed to hand so far */ int dealt; /* Placed cards */ }; struct deck { int card[52]; /* The ith card in the deck */ int whom[52]; /* To whom does the card go? */ int where[52]; /* Where in the deal is the card? whom is the inverse of card */ int dealt; int handcount[4]; int finished[4]; }; int to_whom PROTO ((int card)); extern struct deck_stacker stacker; extern struct deck complete_deal; #define FINISH(hand) if (complete_deal.finished[hand]==0) {deal_hand(hand);} #define IDEAL_VERSION "0.9.0" #endif void __srandom PROTO((unsigned)); long __random(); #define srandom __srandom #define random __random #define RANDOM_MAX LONG_MAX deal319/vector.c0000644000175200017520000000750011062564550011744 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Vectors are a basic sort of "additive evaluation" * which occurs often in bridge. * * Two common vectors are "Controls", where we count A=2 * and K=1, and "High card points," where A=4, K=3, Q=2, * and J=1. * * See also 'additive.c' and 'holdings.c.' * * This file defines a number of different elements and * objects to support vectors in Tcl. * * Vectors are defined in Tcl with a 'defvector' call: * * defvector AKQpoints 3 2 1 * * Internally that defines a 'Lazy Vector' function - * one which only remembers the arguments passed in. * * The first time the vector is used, the 'Lazy Vector' * procedure builds up a table, in this case of 8 elements: * * table[0]=0 - No AKQ * table[1]=1 - Q * table[2]=2 - K * table[3]=3 - KQ * table[4]=3 - A * table[5]=4 - AQ * table[6]=5 - AK * table[7]=6 - AKQ * * After building this table, it converts itself from a * lazy procedure to an active procedure. * * This lets the user define a library of vectors without * concern for the expense of defining them - defining * is a lightweight operation. The table is only built * when first used. * * Vectors only support integer values. For doubles, * see holdings.c to handle other types. * */ #include #include "deck.h" #include "tcl_incl.h" #include "deal.h" #include "vector.h" #include "additive.h" LazyVectorData newLazyVector() { LazyVectorData vec=(LazyVectorData)Tcl_Alloc(sizeof(struct lazy_vector_data)); vec->num=0; return vec; } int tcl_vector_lazy PROTO((TCLOBJ_PARAMS)); int tcl_vector_define PROTO((TCL_PARAMS)); int tcl_vector_define ( TCL_PARAMS ) TCL_DECL { int i; CONST84 char *name=argv[1]; LazyVectorData vec; if (argc<=1) { Tcl_AppendResult(interp,"usage: ",argv[0], " ...",NULL); return TCL_ERROR; } if (argc>15) { Tcl_AppendResult(interp,"too many args: ",argv[0],NULL); return TCL_ERROR; } argc--; argv++; vec=newLazyVector(); for (i=1; ivalue[i-1]=atoi(argv[i]); } vec->num=argc-1; Tcl_CreateObjCommand(interp,name,tcl_vector_lazy,(ClientData)vec,Tcl_AllocDelete); return TCL_OK; } static int vector_eval(int holding,void *data) { VectorTable vec=data; return VectorTableLookup(vec,holding); } int tcl_vector_lazy( TCLOBJ_PARAMS ) TCLOBJ_DECL { LazyVectorData lazyvec=(LazyVectorData)cd; int num=lazyvec->num; int *val=lazyvec->value; VectorTable table; void *func; int i,j; int *tb; table=(int *)Tcl_Alloc(sizeof(int)*(1+(1 << num))); table[0]=13-num; tb=table+1; for (i=0; i< (1<sumsquared,xy=sd->sum; double weight=sd->weight; return sdev_data(weight,xy,xx); } double sdevAverage(sd) SDev *sd; { return sd->sum/sd->weight; } void sdevAddData(sd,weight,data) SDev *sd; double weight; double data; { if (sd->count==0) { sd->max=data; sd->min=data; } else { if ((sd->max) < data) { (sd->max)=data; } if ((sd->min) > data) { (sd->min)=data; } } sd->count++; sd->weight += weight; sd->sum += (weight*data); sd->sumsquared += (weight*data*data); } void sdevFree(ClientData sdev) { Tcl_Free((char *)sdev); } void sdevReset(SDev *sdev) { sdev->sum=0.0; sdev->sumsquared=0.0; sdev->weight=0.0; sdev->count=0; } SDev *sdevNew() { SDev *sdev=(SDev *)Tcl_Alloc(sizeof(SDev)); sdevReset(sdev); return sdev; } void corrAddData(corr,weight,x,y) Correlation *corr; double weight; double x,y; { corr->count++; corr->weight += weight; corr->sumx += (weight*x); corr->sumxx += (weight*x*x); corr->sumy += (weight*y); corr->sumyy += (weight*y*y); corr->sumxy += (weight*x*y); } static double deviationsq(double weight, double sumu, double sumv, double sumuv) { return (sumuv*weight-sumu*sumv); } double corrResult(Correlation *corr) { double x,y,xy; if (corr->count==0) { return -2; } x=deviationsq(corr->weight,corr->sumx,corr->sumx,corr->sumxx); y=deviationsq(corr->weight,corr->sumy,corr->sumy,corr->sumyy); xy=deviationsq(corr->weight,corr->sumx,corr->sumy,corr->sumxy); return (xy/sqrt(x*y)); } Correlation *correlationNew() { Correlation *corr=(Correlation *)Tcl_Alloc(sizeof(Correlation)); corrReset(corr); return corr; } void corrReset(Correlation *corr) { corr->count=0; corr->weight=0.0; corr->sumx=0.0; corr->sumxx=0.0; corr->sumy=0.0; corr->sumyy=0.0; corr->sumxy=0.0; } void correlationFree(ClientData corr) { Tcl_Free((char *)corr); } int count(sd) SDev *sd; { return sd->count; } int tcl_sdev_command ( TCLOBJ_PARAMS ) TCLOBJ_DECL { SDev *sd=(SDev *)cd; static int addCommandID=-1, addwCommandID=-1, averageCommandID=-1, deviationCommandID=-1, countCommandID=-1, weightCommandID=-1, rmsCommandID=-1, minCommandID=-1, maxCommandID=-1, initialize=1; int cmd; if (initialize) { initialize=0; addCommandID=Keyword_addKey("add"); addwCommandID=Keyword_addKey("addw"); weightCommandID=Keyword_addKey("weight"); averageCommandID=Keyword_addKey("average"); deviationCommandID=Keyword_addKey("sdev"); countCommandID=Keyword_addKey("count"); rmsCommandID=Keyword_addKey("rms"); minCommandID=Keyword_addKey("min"); maxCommandID=Keyword_addKey("max"); } cmd=Keyword_getIdFromObj(interp,objv[1]); if (cmd==addCommandID && objc>=3) { double data; int i; for (i=2; i=4) { double weight,data; int i; if (TCL_OK!=Tcl_GetDoubleFromObj(interp,objv[2],&weight)) { return TCL_ERROR; } if (weight<0.0) { return TCL_ERROR; } for (i=3; imax); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (cmd==minCommandID && objc == 2) { Tcl_Obj *obj=Tcl_NewDoubleObj(sd->min); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (cmd==weightCommandID && objc == 2) { Tcl_Obj *obj=Tcl_NewDoubleObj(sd->weight); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (sd->count==0 || sd->weight==0.0) { Tcl_AddErrorInfo(interp,"Can not do statistical computation without data"); return TCL_ERROR; } if (cmd==rmsCommandID && objc==2) { Tcl_Obj *obj=Tcl_NewDoubleObj(rms_data(sd->weight,sd->sum,sd->sumsquared)); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (cmd==averageCommandID && objc==2) { double result=sdevAverage(sd); Tcl_Obj *obj=Tcl_NewDoubleObj(result); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (sd->count==1) { Tcl_AddErrorInfo(interp,"Cannot compute deviation on one point of data"); return TCL_ERROR; } if (cmd==deviationCommandID && objc==2) { double result=sdev(sd); Tcl_Obj *obj=Tcl_NewDoubleObj(result); Tcl_SetObjResult(interp,obj); return TCL_OK; } return TCL_ERROR; } int tcl_correlate_command (TCLOBJ_PARAMS) TCLOBJ_DECL { static int addCommandID=-1, addwCommandID=-1, correlateCommandID=-1, averageCommandID=-1, weightCommandID=-1, sdevCommandID=-1, rmsCommandID=-1, xID=-1, yID=-1, countCommandID=-1, initialize=1; int command; Correlation *corr=(Correlation *)cd; if (initialize) { initialize=0; addCommandID=Keyword_addKey("add"); addwCommandID=Keyword_addKey("addw"); correlateCommandID=Keyword_addKey("correlate"); averageCommandID=Keyword_addKey("average"); sdevCommandID=Keyword_addKey("sdev"); countCommandID=Keyword_addKey("count"); weightCommandID=Keyword_addKey("weight"); rmsCommandID=Keyword_addKey("rms"); correlateCommandID=Keyword_addKey("correlate"); xID=Keyword_addKey("x"); yID=Keyword_addKey("y"); } if (objc==1) { goto corrusage; } command=Keyword_getIdFromObj(interp,objv[1]); if (KEYWORD_INVALID_ID==command) { goto corrusage; } if (command==addCommandID && objc>=3) { double value1; double value2; int i; if (objc%2==1) { Tcl_AddErrorInfo(interp,"Data must be added in pairs - got an odd number of datapoints"); return TCL_ERROR; } for (i=2; i=4) { double weight; double value1; double value2; int i; if (TCL_OK!=Tcl_GetDoubleFromObj(interp,objv[2],&weight)) { return TCL_ERROR; } if (weight<0.0) { return TCL_ERROR; } if (objc%2==0) { Tcl_AddErrorInfo(interp,"Data must be added in pairs - got an odd number of datapoints"); return TCL_ERROR; } for (i=3; icount); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (command==weightCommandID && objc==2) { Tcl_Obj *obj=Tcl_NewDoubleObj(corr->weight); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (corr->count==0) { Tcl_AddErrorInfo(interp,"Cannot compute values without data"); return TCL_ERROR; } if (command==averageCommandID && objc==3) { double value; int var=Keyword_getIdFromObj(interp,objv[2]); if (var==xID) { value=corr->sumx/corr->count; } else if (var==yID) { value=corr->sumy/corr->count; } else { goto corrusage; } Tcl_SetObjResult(interp,Tcl_NewDoubleObj(value)); return TCL_OK; } if (command==rmsCommandID && objc==3) { double value; int var=Keyword_getIdFromObj(interp,objv[2]); if (var==xID) { value=rms_data(corr->count,corr->sumx,corr->sumxx); } else if (var==yID) { value=rms_data(corr->count,corr->sumy,corr->sumyy); } else { goto corrusage; } Tcl_SetObjResult(interp,Tcl_NewDoubleObj(value)); return TCL_OK; } if (corr->count<=1) { Tcl_AddErrorInfo(interp,"Cannot compute correlation or standard deviation\n"); Tcl_AddErrorInfo(interp,"Without at least two points of data"); return TCL_ERROR; } if (command==correlateCommandID && objc==2) { double value=corrResult(corr); Tcl_Obj *obj=Tcl_NewDoubleObj(value); Tcl_SetObjResult(interp,obj); return TCL_OK; } if (command==sdevCommandID && objc==3) { double value; int var=Keyword_getIdFromObj(interp,objv[2]); if (var==xID) { value=sdev_data(corr->count,corr->sumx,corr->sumxx); } else if (var==yID) { value=sdev_data(corr->count,corr->sumy,corr->sumyy); } else { goto corrusage; } Tcl_SetObjResult(interp,Tcl_NewDoubleObj(value)); return TCL_OK; } corrusage: return TCL_ERROR; } int tcl_sdev_define ( TCL_PARAMS ) TCL_DECL { CONST84 char *name=argv[1]; SDev *sd; argc--; argv++; sd=sdevNew(); Tcl_CreateObjCommand(interp,name,tcl_sdev_command,(ClientData)sd,sdevFree); return TCL_OK; } int tcl_correlation_define ( TCLOBJ_PARAMS ) TCLOBJ_DECL { char *name=Tcl_GetString(objv[1]); Correlation *corr; corr=correlationNew(); Tcl_CreateObjCommand(interp,name,tcl_correlate_command,(ClientData)corr,correlationFree); return TCL_OK; } deal319/holdings.c0000644000175200017520000006630511341247400012251 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This file allows the user to define holding procedures in general - * a step beyond the type allowed by 'defvector' in 'vector.c' * * The user simply defines a procedure, say: * * holdingProc solidsuit {A K Q J len} { * expr {($len>=7)&&$A&&$K&&$Q&&($J||($len>=8))} * } * * or * * holdingProc AKQpoints {A K Q} { expr {3*$A+2*$K+$Q } } * * * This, in turn, defines a normal Tcl procedure with the * same name and signature in the ::SlowHoldingProcedures * namespace: * * proc ::SlowHoldingProcedures::solidsuit {A K Q J len} { * expr {($len>=7)&&$A&&$K&&$Q&&($J||($len>=8))} * } * * Finally, the user calls the procedure like: * * AKQpts south * AKQpts hand {AJ54 642 KQ64 95} * * or * * solidsuit south clubs * solidsuit holding AKQ7432 * * This call checks a lookup table. In the case of 'AKQpoints' above, the * lookup table consists of 8 elements. In the case 'solidsuit,' the * table has 10*16 entries. If the lookup entry is NULL, it * calls the SlowHoldingProcedure with the appropriate args. * * A benefit of using this method is that one holding procedure * can call another: * * holdingProc foo {A K Q len} { ... } * * holdingProc bar {A K Q J T len} { * set f [foo $A $K $Q $len] * ... * } * * For the curious, it is possible to dump these tables by calling them * without arguments: * * puts [solidsuit dump] * * That's rather crude, and I might not support it in the future. * * By default, holdingProc assumes the type of the return value is an * integer, so if you say: * * AKQpts south * * it computes the values for each suit and adds them up. * * But you can also declare the type. For example, you might define: * * holdingProc -double losers {A K Q J T 9 len} { * ... * } * * so that you could count partial losers. * * holdingProc -string ... * * defines a procedure which, when applied to a hand or multiple suits, * aggregates the results by putting them in a list. * * The 'boolean' type is the last one, and it is somewhat tricky. * It treats the return value as a boolean value. When evaluating * one suit, it returns the boolean value, but when evaluating a hand * or several suits, it returns a list of the suits for which * the function was true. For example, you might define: * * holdingProc -boolean biddableSuit {A K Q J T len} { ... } * * Then you call: * * biddableSuit south spades * * to determine if south has biddable spades. To get a * list of all biddable suits in the south hand, call: * * biddableSuit south * * This would return {spades diamonds} if south had biddable * spade and diamond suits. * */ #include "tcl_incl.h" #include "keywords.h" #include "holdings.h" #include "dealtypes.h" #include "string.h" #define LENGTH_ARGUMENT 13 #define STRING_ARGUMENT 14 extern int atoi(const char*); /* * Aggregators are crude ways of encapsulating different operations * when "adding" the evaluations accross suits. The aggregator * can add them together as integers or doubles, append them together * in a list or whatever. */ typedef struct _aggregation { int (*fn)(Tcl_Interp *interp,int objc, Tcl_Obj **objv,Tcl_Obj * CONST *suitnames); } Aggregator; /* * Structure contain a full holdingProc definition and data */ typedef struct holdingProcData { Tcl_Obj **lookupTable; /* table of result objects */ Aggregator *aggregator; /* What to do when processing multiple holdings */ int tableLength; /* size of lookupTable */ int argumentCount; /* # of args to pass */ int sigBitCount; /* Number of cards from Ace to smallest significant card */ int fPassLength; /* Pass the length? */ int signature[14]; /* Sequence of variables declared */ Tcl_Obj *slowNameObj; /* Name of the "slow" routine defined */ } *HoldingProcedure; #if (TCL_MINOR_VERSION==0) static int Tcl_EvalObjv(Tcl_Interp *interp,int objc,Tcl_Obj **objv,int dummy) { Tcl_Obj *list=Tcl_NewListObj(objc,objv); if (list==NULL) { return TCL_ERROR; } return Tcl_GlobalEvalObj(interp,list); } #endif /* Replace this with something which caches values 0..13 */ static Tcl_Obj *getIntObj(int val) { static Tcl_Obj *cached[8192]; if (val<8192 && val>=0) { if (cached[val]==NULL) { Tcl_IncrRefCount(cached[val]=Tcl_NewIntObj(val)); } return cached[val]; } else { return Tcl_NewIntObj(val); } } /* * Allocate and initialize the memory for a lookup table */ Tcl_Obj **allocateLookupTable(HoldingProcedure proc) { int entries=proc->tableLength; int i; proc->lookupTable=(Tcl_Obj **)Tcl_Alloc(entries*sizeof(Tcl_Obj*)); for (i=0; ilookupTable[i]=NULL; } return proc->lookupTable; } /* * The namespace where slow procedures will be defined */ static const char *tclNamespace="SlowHoldingProcedures"; /* * Add up result values across several suits as integer values */ static int integerAggregator( Tcl_Interp *interp, int objc, Tcl_Obj **objv, Tcl_Obj * CONST *suits ) { int i; int total=0; for (i=0; i 1 * foo north hearts => 0 * foo north diamonds => 1 * foo north clubs => 0 * But * foo north => "spades diamonds" */ if (objc==1) { Tcl_SetObjResult(interp,objv[0]); } else { /* * Create and build the list */ Tcl_Obj *result=Tcl_NewListObj(0,NULL); int value; for (i=0; ilookupTable=0; proc->argumentCount=0; proc->sigBitCount=0; proc->fPassLength=0; proc->signature[0]=-1; proc->slowNameObj=NULL; proc->aggregator=NULL; return proc; } /** * If holdingProc was called as: * * holdingProc foo { a k q ... } { ... } * * this routine defines a procedure: * * proc ::SlowHoldingProc::foo { a k q ... } { ... } * * This is the "slow" procedure - it should be called at most * once per entry in the lookup table. * * Returns a Tcl_Obj* representing the name of the slow procedure. * */ static Tcl_Obj * defSlowHoldingProc( Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Obj *argList, Tcl_Obj *code ) { int length; Tcl_Obj *objv[4]; int retval; char *name=Tcl_GetStringFromObj(nameObj,&length); char *slowName; if (name==NULL) { return NULL; } slowName=(char *)Tcl_Alloc(4+length+strlen(tclNamespace)); if (slowName==NULL) { return NULL; } sprintf(slowName,"%s::%s",tclNamespace,name); objv[0]=Tcl_NewStringObj("proc",4); objv[1]=Tcl_NewStringObj(slowName,strlen(slowName)); objv[2]=argList; objv[3]=code; Tcl_Free(slowName); if (objv[1]==NULL) { return NULL; } Tcl_IncrRefCount(objv[1]); retval=Tcl_EvalObjv(interp,4,objv,TCL_EVAL_GLOBAL); if (retval!=TCL_OK) { Tcl_DecrRefCount(objv[1]); return NULL; } return objv[1]; } static Aggregator integerAggr={integerAggregator}; static Aggregator doubleAggr={doubleAggregator}; static Aggregator stringAggr={stringAggregator}; static Aggregator booleanAggr={booleanAggregator}; /** * Return the index into the HoldingProcedure table given a * holding. */ static int encode_holding( HoldingProcedure procedure, int holdingBits ) { int realHolding=holdingBits&8191; int realbits=counttable[realHolding]; int spots; int significantBits=realHolding >> (13 - procedure->sigBitCount); if (procedure->fPassLength) { int result; spots=realbits-counttable[significantBits]; result=significantBits | (spots<<(procedure->sigBitCount)); if (result>=procedure->tableLength) { return -1; } return result; } else { return significantBits; } } /* * Simple delete procedure for a holding procedure. * Should clean out lookup table before deleting. */ static void deleteHoldingProcedure(ClientData cd) { HoldingProcedure proc=(HoldingProcedure)cd; if (proc->lookupTable!=NULL) { Tcl_Free((char*)proc->lookupTable); } Tcl_Free((char*)proc); } /* * Evaluate a holding procedure for a single holding */ static Tcl_Obj * evalHoldingProcedure( Tcl_Interp *interp, HoldingProcedure procedure, int holdingBits ) { int retval; Tcl_Obj **lookupTable=procedure->lookupTable; /* Determine index in the lookup table */ int lookupIndex=encode_holding(procedure,holdingBits); if (lookupIndex<0) { return NULL; } /* Allocate the table if it hasn't been allocated yet */ if (lookupTable==NULL) { lookupTable=allocateLookupTable(procedure); if (lookupTable==NULL) { return NULL; } } /* * If the entry for this particular value has not already * been calculated, calculate it by calling original Tcl code */ if (lookupTable[lookupIndex]==NULL) { int i; /* Build object list */ int objc=1+procedure->argumentCount; Tcl_Obj **objv=(Tcl_Obj **) Tcl_Alloc(objc*sizeof(Tcl_Obj *)); objv[0]=procedure->slowNameObj; /* slow procedure name */ /* For every argument in the signature, add an appropriate * argument to the list */ for (i=1; isignature[i-1]) { case LENGTH_ARGUMENT: objv[i]=getIntObj(counttable[holdingBits&8191]); break; case STRING_ARGUMENT: { int stringSpots=(lookupIndex>>procedure->sigBitCount); int fakeHolding= (lookupIndex<<(13-procedure->sigBitCount))+((1<12) { Tcl_Free((char *)objv); Tcl_AddErrorInfo(interp,"Card value out of range"); return NULL; } /* * Set card parameter to zero or 1 depending on whether the * card is held in this holding */ objv[i]=getIntObj(1&(holdingBits>>(12-card))); break; } } /** * Once done, evaluate this list in a global context */ retval=Tcl_EvalObjv(interp,objc,objv,TCL_EVAL_GLOBAL); Tcl_Free((char *)objv); if (retval!=TCL_OK) { return NULL; } lookupTable[lookupIndex]=Tcl_GetObjResult(interp); Tcl_IncrRefCount(lookupTable[lookupIndex]); } return lookupTable[lookupIndex]; } /* * Determine a variables meaning by it's first letter(s) */ static int lookupArgumentName(Tcl_Obj *varName) { int length, rank; char *string=Tcl_GetStringFromObj(varName,&length); switch (*string) { case 'a': case 'A': return ACE; case 'k': case 'K': return KING; case 'Q': case 'q': return QUEEN; case 'J': case 'j': return JACK; case 'T': case 't': return TEN; case 'x': case 'X': rank=atoi(string+1); if (rank<2 || rank>13) { return -1; } return 14-rank; case 'l': case 'L': return LENGTH_ARGUMENT; case 's': case 'S': return STRING_ARGUMENT; default: return -1; } } static HoldingProcedure newHoldingProcedure( Tcl_Interp *interp, Tcl_Obj *slowNameObj, Tcl_Obj *argsList ) { HoldingProcedure procedure=allocateHoldingProcedure(); int argsLength; int retval,index; int flagArguments=0; Tcl_Obj *varName; int maxArg=-1; /* Smallest significant card */ if (procedure==NULL) { return NULL; } /* Determine how many arguments there are */ retval=Tcl_ListObjLength(interp,argsList,&argsLength); if (retval!=TCL_OK) { Tcl_Free((char *)procedure); return NULL; } procedure->argumentCount=argsLength; /* Create the signature by looking up the arguments in the argument list */ procedure->sigBitCount=0; for (index=0; indexsignature[index]=argNum; /* Make sure each argument type occurs only once (why?) */ if (flagArguments&(1<fPassLength=1; } else { if (argNum>maxArg) { maxArg=argNum; } } } /* Significant bits is one more than maxArg */ maxArg++; procedure->sigBitCount=maxArg; /* Determine table length */ procedure->tableLength=(1<fPassLength) { procedure->tableLength *= (14-maxArg); } /* Store the slow function name */ Tcl_IncrRefCount(procedure->slowNameObj=slowNameObj); return procedure; } /* * Evaluate a set of holdings passed in an array * of integers. */ static int evalHoldingNums( Tcl_Interp *interp, HoldingProcedure procedure, int count, int *holdings, Tcl_Obj * CONST *suits ) { int i; int retval; Tcl_Obj **values= (Tcl_Obj **)Tcl_Alloc(count*sizeof(Tcl_Obj *)); if (values==NULL) { return TCL_ERROR; } /* * Evaluate for each individual holding */ for (i=0; iaggregator->fn)(interp,count,values,suits); } Tcl_Free((char *)values); return retval; } static int IDealHoldingProcedure(TCLOBJ_PARAMS) TCLOBJ_DECL { static int subCmdInit=1, holdingSubCmdID=-1, handSubCmdID=-1, dumpSubCmdID=-1; int hand,subCmd; HoldingProcedure procedure=(HoldingProcedure)cd; if (subCmdInit) { handSubCmdID=Keyword_addKey("hand"); holdingSubCmdID=Keyword_addKey("holding"); dumpSubCmdID=Keyword_addKey("dump"); subCmdInit=0; } if (objc>7 || objc<=1) { goto usage; } if (NOSEAT!=(hand=getHandNumFromObj(interp,objv[1]))) { FINISH(hand); if (objc==2) { return evalHoldingNums(interp, procedure, 4,globalDeal.hand[hand].suit, getAllSuitObjs()); } else { int i,array[4]; for (i=2; itableLength; holding++) { int spots=(holding>>procedure->sigBitCount); int fakeHolding=(holding<<(13-procedure->sigBitCount))+((1<7) { Tcl_WrongNumArgs(interp,2,objv,"hand [ ...]"); goto usage; } if (TCL_OK!=getHandHoldingsFromObj(interp,objv[2],allHoldingNums)) { Tcl_SetResult(interp,"Badly formatted hand",TCL_STATIC); return TCL_ERROR; } allSuits = getAllSuitObjs(); if (objc == 3) { hnum = allHoldingNums; countHoldings = 4; suits = allSuits; } else { int i; countHoldings = 0; for (i=3; i"); return TCL_ERROR; } hnum=getHoldingNumFromObj(interp,objv[2]); return evalHoldingNums(interp,procedure,1,&hnum,NULL); } usage: /* error condition */ { char *command; command=Tcl_GetString(objv[0]); Tcl_AppendResult(interp,command, ": Bad first argument ",Tcl_GetString(objv[1]), "\nUsage:\n", command," [ ...]\n", command," hand [ ...]\n", command," holding [ ...]\n", (char *)NULL); return TCL_ERROR; } } static int IDeal_DefHoldingProc(TCLOBJ_PARAMS) TCLOBJ_DECL { static int initKeywords=1, doubleFlag=-1, integerFlag=-1, stringFlag=-1, booleanFlag=-1; Tcl_Obj *nameObj, *argsList, *code; Tcl_Obj *slowNameObj; char *name; int len; HoldingProcedure procedure; Aggregator *aggr=&integerAggr; if (initKeywords) { doubleFlag=Keyword_addKey("-double"); integerFlag=Keyword_addKey("-integer"); stringFlag=Keyword_addKey("-string"); booleanFlag=Keyword_addKey("-boolean"); initKeywords=0; } if (objc!=4 && objc!=5) { goto usage; } nameObj=objv[1]; name=Tcl_GetString(nameObj); if (*name=='-') { int flag=Keyword_getIdFromObj(interp,nameObj); if (flag==integerFlag) { aggr=&integerAggr; } else if (flag==doubleFlag) { aggr=&doubleAggr; } else if (flag==booleanFlag) { aggr=&booleanAggr; } else if (flag==stringFlag) { aggr=&stringAggr; } else { goto usage; } objc--; objv++; } nameObj=objv[1]; argsList=objv[2]; code=objv[3]; slowNameObj=defSlowHoldingProc(interp,nameObj,argsList,code); if (slowNameObj==NULL) { return TCL_ERROR; } procedure=newHoldingProcedure(interp,slowNameObj,argsList); if (procedure==NULL) { return TCL_ERROR; } procedure->aggregator=(Aggregator *)aggr; name=Tcl_GetStringFromObj(nameObj,&len); Tcl_CreateObjCommand(interp,name,IDealHoldingProcedure, (ClientData)procedure,deleteHoldingProcedure); return TCL_OK; usage: Tcl_SetResult(interp, "holdingProc [ -integer|-double|-string ] ", NULL); return TCL_ERROR; } /* * This routine implements the "holding" command, which implements * various subcommands for processing Deal holding objects. */ static int IDeal_HoldingCmd(TCLOBJ_PARAMS) TCLOBJ_DECL { static int lengthCmd, disjointCmd, unionCmd, randomCmd, listCmd, encodeCmd, decodeCmd, subsetCmd, matchesCmd, lengthFlag, spotFlag, initKeywords=1; int cmd; if (initKeywords) { lengthCmd=Keyword_addKey("length"); disjointCmd=Keyword_addKey("disjoint"); unionCmd=Keyword_addKey("union"); randomCmd=Keyword_addKey("random"); encodeCmd=Keyword_addKey("encode"); decodeCmd=Keyword_addKey("decode"); subsetCmd=Keyword_addKey("contains"); matchesCmd=Keyword_addKey("matches"); listCmd=Keyword_addKey("list"); /* Flags for the list subcommand */ lengthFlag=Keyword_addKey("-length"); spotFlag=Keyword_addKey("-spot"); initKeywords=0; } if (objc==1) { Tcl_WrongNumArgs(interp,1,objv," ..."); return TCL_ERROR; } cmd=Keyword_getIdFromObj(interp,objv[1]); if (cmd==lengthCmd) { int holding; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,""); return TCL_ERROR; } holding=getHoldingNumFromObj(interp,objv[2]); if (holding<0) { return TCL_ERROR; } Tcl_SetObjResult(interp,getIntObj(counttable[holding&8191])); return TCL_OK; } if (cmd==encodeCmd) { int holding; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,""); return TCL_ERROR; } holding=getHoldingNumFromObj(interp,objv[2]); if (holding<0) { return TCL_ERROR; } Tcl_SetObjResult(interp,getIntObj(holding)); return TCL_OK; } if (cmd==decodeCmd) { int result,num; Tcl_Obj *obj; if (objc!=3) { Tcl_WrongNumArgs(interp,2,objv,""); return TCL_ERROR; } result=Tcl_GetIntFromObj(interp,objv[2],&num); if (result!=TCL_OK) { return result; } obj=Tcl_NewHoldingObj(num); if (obj==(Tcl_Obj*)0) { return TCL_ERROR; } Tcl_SetObjResult(interp,obj); return TCL_OK; } /* * Construct the union of one or more holdings: * holding union AJT3 KT42 => AKJT432 */ if (cmd==unionCmd) { int result=0,holding,i; if (objc<3) { Tcl_WrongNumArgs(interp,2,objv," [ ... ]"); return TCL_ERROR; } for (i=2; i8191) { return TCL_ERROR; } result |= holding; } Tcl_SetObjResult(interp,Tcl_NewHoldingObj(result)); return TCL_OK; } /* * Check to see whether the first holding passed contains all * of the other holdings passed: * holding contains AJT832 J832 => 1 (true) * holding contains AJT832 J 8 3 2 => 1 (true) * holding contains AJT832 K => 0 (false) */ if (cmd==subsetCmd) { int holding,subset,i; if (objc<4) { Tcl_WrongNumArgs(interp,2,objv," [ ... ]"); return TCL_ERROR; } holding=getHoldingNumFromObj(interp,objv[2]); if (holding<0 || holding>8191) { return TCL_ERROR; } for (i=3;i8191) { return TCL_ERROR; } if ((subset&holding)!=subset) { Tcl_SetObjResult(interp,getIntObj(0)); return TCL_OK; } } Tcl_SetObjResult(interp,getIntObj(1)); return TCL_OK; } /* * Determine if the list of passed in holdings are disjoint: * * holding disjoint AT32 KJ84 Q9 => 1 (true) * holding disjoint AT32 972 => 0 (false) */ if (cmd==disjointCmd) { int cumulative=0,i; for (i=2; i8191) { return TCL_ERROR; } if (cumulative&holding) { Tcl_SetObjResult(interp,getIntObj(0)); return TCL_OK; } cumulative |= holding; } Tcl_SetObjResult(interp,getIntObj(1)); return TCL_OK; } /* * Determines whether a holding pattern matches a holding: * holding matches AKxxx AK843 => 1 (true) * holding matches AKxxx AKJ92 => 0 (false) */ if (cmd==matchesCmd) { Tcl_AddErrorInfo(interp,"'holding matches' not implemented yet"); return TCL_ERROR; /* The *lowest spot* that is not a spot in the x should be the limit */ } Tcl_AppendResult(interp, "Invalid subcommand '", Tcl_GetString(objv[1]) , "' passed to '", Tcl_GetString(objv[0]), "' command.",NULL); return TCL_ERROR; } int IDealHolding_Init(Tcl_Interp *interp) { /* Only way to create a namespace? */ int retval=Tcl_Eval(interp,"namespace eval ::SlowHoldingProcedures {expr 1}"); if (retval!=TCL_OK) { return retval; } Tcl_CreateObjCommand(interp,"::holdingProc", IDeal_DefHoldingProc,(ClientData)&integerAggr,NULL); Tcl_CreateObjCommand(interp,"::holding", IDeal_HoldingCmd,NULL,NULL); return TCL_OK; } deal319/Make.dep0000644000175200017520000000000011341325570011626 0ustar cbecbedeal319/ex/0000755000175200017520000000000011341325570010705 5ustar cbecbedeal319/ex/3-shapeclass.tcl0000644000175200017520000000267111062564550013710 0ustar cbecbe# You hold the south hand: 764 J4 J753 AQJ2 # and the auction has gone: 1S(W)-1NT-2NT-3NT by the opponents, # who are playing 2/1. # Choose a lead. # In this example, I've assumed west has no side 4-card suit, # and that he holds exactly 5 spades and 16-19 HCP. # I've also assumed that East had some way to show a 5-card heart # suit over 2NT, and hence, that he doesn't hold one, and also that # east does not have spade support. south is 764 J4 J753 AQJ2 shapecond balanced5S {$s==5&&($h*$d*$c==18)} main { reject unless {[balanced5S west]} set w [hcp west] reject if {$w<16} {$w>19} reject if {[hearts east]>4} {[spades east]>2} set e [hcp east] reject if {$e<6} {$e>11} {[losers east]<6} accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/1.tcl0000644000175200017520000000304411062564550011555 0ustar cbecbe############################################## # Look for hand where north has 44 in the majors, a short minor, # and 11-15 HCP. # # Parts of this could be done more efficiently with a "shapeclass" # command. # # To execute: # deal -i ex/1.tcl [num] ############################################## main { # Pitch deals # where north does # not have four spades reject if {[spades north]!=4} # Pitch deals # where north does # not have four hearts reject if {[hearts north]!=4} # Pitch deals # where north has # 2 or 3 diamonds set d [diamonds north] reject if {$d==2} {$d==3} # Accept deals # where north has # 11-15 HCP. set hcp_n [hcp north] accept if {$hcp_n>=11 && $hcp_n<=15} } ############################################## # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/1-shapeclass.tcl0000644000175200017520000000230011062564550013673 0ustar cbecbe############################################## # Look for hand where north has 44 in the majors, a short minor, # and 11-15 HCP. # # To execute: # deal -i ex/1-shapeclass.tcl [num] ############################################## shapeclass roman_short_minor {expr {$h==4 && $s==4 && ($c<=1 || $d<=1)}} main { reject unless {[roman_short_minor north]} set hcp_n [hcp north] accept if {$hcp_n>=11 && $hcp_n<=15} } ############################################## # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/3nt-nostack.tcl0000644000175200017520000000276111062564550013566 0ustar cbecbe# # # To run: # # deal -i ex/3nt-nostack.tcl # # Find deals where south is "AK K52 98765 962" and north has a gambling # 3nt hand. # # This uses the definition: Solid 7-9 card minor suit, no 4-card major or # 5+ card in the other minor, no controls outside the solid suit. # # This is slower than the smart-stacking version by an order of magnitude # when requesting 1000 deals. # source format/none south is "AK K52 98765 962" source ex/3nt-common.tcl set diamonds 0 set clubs 0 main { reject unless {[gam3NT.shape north]} reject unless {0==[gam3NT.suit north]} if {[diamonds north]>=7} { incr diamonds } { incr clubs } puts "-- [north shape]" accept } deal_finished { #puts "Solid diamonds: $diamonds" #puts "Solid clubs : $clubs" } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/holdingProc.tcl0000644000175200017520000000302611062564550013665 0ustar cbecbe# # A simple 'holding procedure' to determine high card points # holdingProc HCP {A K Q J} { expr {$A*4+$K*3+$Q*2+$J} } # # The 'smartPoints' procedure incorporates two adjustments to # the standard high card points. # # 1) A point is added for every card over 4 in a single suit # 2) Honors in short suits are somewhat discounted # holdingProc smartPoints {length A K Q J} { if {$length>=5} { return [expr {$A*4+$K*3+$Q*2+$J+$length-4}] } if {$length==0} { return 0 } if {$length==1} { return [expr {$A*4+$K*2}] } if {$length==2} { return [expr {$A*4+$K*3+$Q}] } expr {$A*4+$K*3+$Q*2+$J} } # # Find deals where north has less than 13 HCP but are compensated over # 13 points by shape # main { reject if {[HCP north]>12} accept if {[smartPoints north]>12} } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/4.tcl0000644000175200017520000000234711062564550011565 0ustar cbecbe# # By agreement, you open a weak 2 with exactly 6 cards in your major, # fewer than 4 cards in the other major, 5-10 HCP and either 2 of the # top 3 or three of the top 5 in your suit. # defvector W2Q 2 2 2 1 1 main { set sh [hcp south] reject if {$sh>10} {$sh<5} {[clubs south]>3} {[diamonds south]>3} set s [spades south] if {$s == 6} { reject if {[hearts south]>3} {[W2Q south spades]<=3} accept } reject if {$s>3} set h [hearts south] reject if {$h!=6} {[W2Q south hearts]<=3} accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/4-stack.tcl0000644000175200017520000000246411062564550012670 0ustar cbecbe# # By agreement, you open a weak 2 with exactly 6 cards in your major, # fewer than 4 cards in the other major, 5-10 HCP and either 2 of the # top 3 or three of the top 5 in your suit. # holdingProc -boolean Weak2Quality {length A K Q J T} { accept if {$length<3} reject unless {$length==6} accept if {(($A+$K+$Q)>=2 || ($A+$K+$Q+$J+$T)>=3)} } shapecond Weak2Shape {$d<=3&&$c<=3&&(($h<=3&&$s==6)||($h==6&&$s<=3))} deal::input smartstack south Weak2Shape hcp 5 10 smartstack::restrictHolding spades Weak2Quality 1 1 smartstack::restrictHolding hearts Weak2Quality 1 1 # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/6b.tcl0000644000175200017520000000337411062564550011732 0ustar cbecbe# # File: ex/6b.tcl # # This implements the same search as ex/6a.tcl, using a simple # shape class. # # Basically, we use a shapeclass to immediately reject deals where # south doesn't have a void. This keeps us from doing unnecessary # work, and practically doubles the speed of the search. # # The shape class "hasvoid" returns one (True) if there is a void # somewhere in the hand and zero (False) otherwise. It would # seem like this is doing *more* work than example A, but the # lookup in a shapeclass is much better optimized, and we break # out of the loop if south doesn't have void, and move on to # the next. # # example6c is about the same speed but uses an idiom worth # seeing for other sorts of problems. # shapecond hasvoid {$s==0 || $h==0 || $d==0 || $c==0} main { reject unless [hasvoid south] accept if {[spades south]==0 && [spades north]==0} accept if {[hearts south]==0 && [hearts north]==0} accept if {[diamonds south]==0 && [diamonds north]==0} accept if {[clubs south]==0 && [clubs north]==0} reject } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/6d.tcl0000644000175200017520000000336011062564550011727 0ustar cbecbe# # File: ex/6d.tcl # # This file uses a "holding function" to optimize a search for hands # where north and south have voids in the same suit. # # The holding function "isVoid" returns a list of the suits in which # the hand given has a void. So if south is: # # S --- S AK5 S KJ8 # H 5432 H A982 H Q932 # D --- D 543 D AT9863 # C AQT986543 C T92 C ---- # # [voids south] will return: # # "spades diamonds" "" "clubs" # # This is the same output as in the "voids" procedure for ex/6c.tcl, # but it is implemented as a holding procedure rather than a shape # procedure. # # We then run through this list and check if north has any void in # common. # # This is considerably slower the 6b.tcl and 6c.tcl, though. holdingProc -boolean voids {len} { expr {$len==0} } main { foreach suit [voids south] { accept if {[$suit north]==0} } } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/5.tcl0000644000175200017520000000254311062564550011564 0ustar cbecbe############################# # When I first wrote this I was somewhat surprised. # # This deals hands where south opens a strong blue club and # north has a 3+ controls (that is, he has a strong positive # response.) # # I was surprised to find that slam was making 1/2 the time on these # hands. In other words, for Blue-clubbers, if the auction starts: # # 1C 1S/1NT/2C/2D # # there is a 50% chance that a slam should be bid... ############################# main { reject unless {[controls north]>=3} set w [hcp south] reject unless {$w >=17} if {[balanced south]} { reject if {$w==17} {$w>=22 && $w<=24} } accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/3nt-stack.tcl0000644000175200017520000000316611062564550013231 0ustar cbecbe# # Find deals where south is "AK K52 98765 962" and north has a gambling # 3nt hand. # # This was one of the first examples I gave of how "smart stacking" could # be used. # # Compare output from this with output from ex/3nt-nostack.tcl to make # sure that the relative odds are being obeyed, eg: # # deal -i ex/3nt-stack.tcl 1000 | sort | uniq -c | sort -nr > stack.txt # deal -i ex/3nt-nostack.tcl 1000 | sort | uniq -c | sort -nr > nostack.txt # # Obviously, they shouldn't be exactly the same, but they should be similar. source format/none source ex/3nt-common.tcl deal::input smartstack north gam3NT.shape gam3NT.suit 0 0 south is "AK K52 98765 962" # Dump the data table from the smart stacking routine #foreach line [smartstack::getdata] { # puts $line #} main { reject unless {[gam3NT.shape north]} reject unless {0==[gam3NT.suit north]} puts "-- [north shape]" accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/6c.tcl0000644000175200017520000000413611062564550011730 0ustar cbecbe# # File: ex/6c.tcl # # This file uses a "shape function" to optimize a search for hands # where north and south have voids in the same suit. # # The shape function "voids" returns a list of the suits in which # the hand given has a void. So if south is: # # S --- S AK5 S KJ8 # H 5432 H A982 H Q932 # D --- D 543 D AT9863 # C AQT986543 C T92 C ---- # # [voids south] will return: # # "spades diamonds" "" "clubs" # # We then run through this list and check if north has any void in # common. # # This doesn't seem like it would be faster, but it is, because # the shape function is computed up front as a table, and each call # after the first is a quick lookup. In fact, this is twice # as fast as the script in ex/6a.tcl . # # It is only slightly faster than ex/6b.tcl, though. The main # reason I include it is to show a technique that can be used elsewhere. # Another example which uses this is example7, a rather complicated routine... # shapefunc voids { set res "" if {$s==0} { lappend res spades } if {$h==0} { lappend res hearts } if {$d==0} { lappend res diamonds } if {$c==0} { lappend res clubs } return $res } main { foreach suit [voids south] { accept if {[$suit north]==0} } } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/1-stack.tcl0000644000175200017520000000343711062564550012666 0ustar cbecbe############################################## # Look for hand where north has 44 in the majors, a short minor, # and 11-15 HCP. # # To execute: # deal -i ex/1-stack.tcl [num] # # This example uses the smart stacking algorithm to generate the # same sorts of hands as example1 and example1-shapeclass. # The very first deal is slow - when the deal is requested a # large "factory" object is built in memory - but every other # deal generated after that first one is generated extremely quickly. # # In this example, you'd have to want about 1500 matches to the condition # for the investment to break even. But after 1500, the advantage of # the smart stacking is huge. # # The payoff is even greater for rarer hand conditions. ############################################## shapeclass roman_short_minor {expr $h==4 && $s==4 && ($c<=1 || $d<=1)} deal::input smartstack north roman_short_minor HCP 11 15 set start [clock seconds] set count 0 defvector HCP 4 3 2 1 proc flush_deal {} { global start global count set time [expr {[clock seconds]-$start}] } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/dds-trick.tcl0000644000175200017520000000100511062564550013274 0ustar cbecbe# Great 88 problem 1 - Avoidance set diagram { {A987 - A -} {Q5 987 - -} {64 K2 2 -} {K2 AQ3 - -} } puts [dds -leader south -diagram $diagram south notrump] # Should return 3 puts [dds -leader south -diagram $diagram -trick 4S south notrump] # Should return 3 puts [dds -leader west -diagram $diagram -trick {4S KS 7S 5S} south notrump] # Should return 3 puts [dds -leader north -diagram $diagram -trick {4S 2S AS 5S} -trick 7S south notrump] # Should return 2 exit 0 deal319/ex/7.tcl0000644000175200017520000000576611062564550011600 0ustar cbecbe# # A Certain poster to rec.games.bridge has been posting # a computer generated bidding system that, to most bridge # players eyes, looks somewhat deranged. # # bid.lib is a library of tcl routines which allow you # to define opening bids and later check to see if a hand # fits the conditions source lib/bid.tcl defvector AKQ 4 3 2 defvector Top4 1 1 1 1 defvector Aces 1 defvector None 0 proc top4spades {hand} { return [Top4 $hand spades] } # Usage: # describebid # # Don Quixote's system: # describebid 5D {$d>=8} AKQ 0 3 describebid 5C {$c>=8} controls 0 1 describebid 4S {$s==8} controls 0 3 describebid 4H {$h>=7} controls 0 1 describebid 4D {$d>=8} AKQ 5 7 describebid 4C {$h==8 && $d*$c*$s==3} Aces 1 1 describebid 3NT {$s==9 && ($h==2 || $d==2 || $c==2)} top4spades 2 4 describebid 3S {$s==7 && $d*$c*$h==6} AKQ 0 7 describebid 3H {$h==7} losers 16 17 describebid 3D {$d==7 && ($h==3 || $c==3 || $d==3)} hcp 3 3 describebid 3C {$c==7 && $d*$h*$s==4} AKQ 0 3 describebid 2NT {$s==7 && $c*$h*$d==8} hcp 4 5 describebid 2S {$s==7 && $c*$d*$h==4} hcp 3 5 describebid 2H {$h==7} Aces 0 0 describebid 2D {$d==7 && $h*$s*$c==6} hcp 2 5 describebid 2C {$c>=3 && $d>=3 && $h>=3 && $s>=3} hcp 22 23 ####################################### # # This uses the proceducre "getbidlist", which is really # a "shapefunc" defined in bid.lib . It returns a list # of all the possible described bids which can be made, given # only the shape of the hand. This turns out to be a very # good optimization - rather than looping through all the # bids, we only have to loop through a small subset. # # "checkcondition" then actually checks whether the hand # is fits the other condition (which does a computation # using the function provided and checks whether the hand is # in the correct range.) # # This search looks for (south) hands which would open # 2C under the above system. What kind of system # opens at the 2 level only 1/100 times, anyway? # Bizarre. # ####################################### foreach bid $bidlist { set count($bid) 0 } set accepted 0 set tried 0 main { incr tried foreach bid [getbidlist south] { if {[checkcondition $bid south]} { puts "$bid with [south]" incr count($bid) incr accepted accept } } reject } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/4-holding.tcl0000644000175200017520000000230711062564550013203 0ustar cbecbe# # By agreement, you open a weak 2 with exactly 6 cards in your major, # fewer than 4 cards in the other major, 5-10 HCP and either 2 of the # top 3 or three of the top 5 in your suit. # holdingProc -boolean Weak2Quality {length A K Q J T} { expr {$length==6 && (($A+$K+$Q)>=2 || ($A+$K+$Q+$J+$T)>=3)} } main { set sh [hcp south] reject if {$sh>10} {$sh<5} {[hearts south]>3} {[clubs south]>3} {[diamonds south]>3} accept if {[Weak2Quality south spades]} } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/6a.tcl0000644000175200017520000000411711062564550011725 0ustar cbecbe# # File: ex/6a.tcl # # This is a test which shows why you'd want to use a "shape class" # or "shape function", which are fast lookup tables... # # This is the slow version, which doesn't use the shape function # # It seeks hands where north and south have voids in the same # suit. (Alternatively, it finds hands where east and west have # a 13-card fit.) # # See ex/6b.tcl and ex/6c.tcl for faster versions of the same search # main { accept unless {[spades south]!=0} {[spades north]!=0} accept unless {[hearts south]!=0} {[hearts north]!=0} accept unless {[diamonds south]!=0} {[diamonds north]!=0} accept unless {[clubs south]!=0} {[clubs north]!=0} } # It should be noted that this script is written so that # the north hand is never even dealt unless the south hand # has a void. That's because, internally, 'deal' doesn't deal # a hand unless information is requested about that hand. # # If the lines were: # # accept if {[spades south]==0 && [spades north]==0} # # 'deal' would request information for *both* hands, and that would # double the amount of work. Hence the use of the slightly less clear # 'accept unless' idiom. # # How much of an optimization is it to not deal the north hand? # Profiling has shown me that a vast amount of time is spent in # the randomnization routines, so cutting down on these calls # is a significant time savings. # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/3.tcl0000644000175200017520000000270011062564550011555 0ustar cbecbe# You hold the south hand: 764 J4 J753 AQJ2 # and the auction has gone: 1S(W)-1NT-2NT-3NT by the opponents, # who are playing 2/1. # Choose a lead. # In this example, I've assumed west has no side 4-card suit, # and that he holds exactly 5 spades and 16-19 HCP. # I've also assumed that East had some way to show a 5-card heart # suit over 2NT, and hence, that he doesn't hold one, and also that # east does not have spade support. south is 764 J4 J753 AQJ2 main { reject unless {[spades west]==5} set w [hcp west] reject if {$w<16} {$w>19} {[hearts west]>3} {[diamonds west]>3} {[clubs west]>3} reject if {[hearts east]>4} {[spades east]>2} set e [hcp east] reject if {$e<6} {$e>11} {[losers east]<6} accept } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/3nt-common.tcl0000644000175200017520000000212011062564550013401 0ustar cbecbeshapecond gam3NT.shape {$s<=3&&$h<=3&&(($d>=7&&$c<=4)||($c>=7&&$d<=4))} # return '1' if not compatible with a gambling notrump hand, # '0' otherwise holdingProc gam3NT.suit {A K Q J len} { if {$len>=7} { if {$len<=9&&$A&&$K&&$Q} { return 0} return 1 } if {$len<=4} { if {$A||$K} { return 1 } return 0 } return 1 } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/ex/2.tcl0000644000175200017520000000202211062564550011551 0ustar cbecbe # I held the south hand given below, and east opened 2C. # I overcalled 2S red-on-red. This procedure deals hands # where east will open 2C in front of the south hand. south is "Q86432 T2 932 83" main { set h [hcp east] reject if {$h<18} accept if {$h>22} {[losers east]<4} } # # Copyright (C) 1996-2001, Thomas Andrews # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # deal319/keywords.c0000644000175200017520000001436711074376542012327 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* The procedures in this file create "keywords" is a new Tcl * type which associates word with integer ids. * * This is mostly used in C routines to speed up processing * certain types of Tcl arguments - implicitly creating "enum"-like * behavior. For example, the first time the code: * * hcp north * * is called, the internal representation of the argument, "north", is * converted to a Keyword Tcl type. Every further time the code * is called, no further lookup is required. This is a Tcl hack for * performance purposes. * * This is similar to the Tcl_GetIndexFromObj() routines, only there, * the keywords are local, not global. Also, the Tcl_GetIndexFromObj * routine doesn't allow aliases. * * int Keyword_addKey(char *key) adds the key to the key database, if * it is not there already, and then returns the integer id of the key. * Integer ids are allocated sequentially. * * Typically, code which used Keyword_addKey might write something like: * * static int lengthCmdID=-1, indexCmdID=-1, initialized=0; * int cmdID; * if (!initialized) { * lengthCmdID=Keyword_addKey("length"); * indexCmdID=Keyword_addKey("index"); * } * * cmdID=Keyword_getIdFromObj(interp,objv[1]); * if (cmd==lengthCmdID) { * ... do length sub-command ... * } else if (cmd==indexCmdID) { * ... do index sub-command ... * } else { * ... error code ... * } * */ #include "keywords.h" #include "string.h" Tcl_ObjType KeywordType; static Tcl_HashTable keywordsTable; static Tcl_HashTable backwardsLookup; static int entryCount=0; /** * If flags has KEYWORD_SET_DEFAULT, then makes this string * the default for this id. */ int Keyword_setId(const char *keyword,int id,int flags) { Tcl_HashEntry *entry=NULL; int isNew=0; char *dupKey; if (id==KEYWORD_INVALID_ID) { return KEYWORD_INVALID_ID; } dupKey=Tcl_Alloc(strlen(keyword)+1); strcpy(dupKey,keyword); entry=Tcl_CreateHashEntry(&keywordsTable,dupKey,&isNew); if (entry==NULL) { return KEYWORD_INVALID_ID; } if (!isNew) { id=(int)Tcl_GetHashValue(entry); } else { Tcl_SetHashValue(entry,id); } entry=NULL; /* Only the first occurence of an id gets a backwards lookup */ entry=Tcl_CreateHashEntry(&backwardsLookup,(char *)id,&isNew); if (entry==NULL) { return TCL_ERROR; } if (isNew || (flags&KEYWORD_SET_DEFAULT)) { char *oldKey=(char *)Tcl_GetHashValue(entry); if (oldKey!=NULL) { Tcl_Free(oldKey); } Tcl_SetHashValue(entry,(ClientData)dupKey); } return id; } int Keyword_getId(char *key) { Tcl_HashEntry *entry=Tcl_FindHashEntry(&keywordsTable,key); if (entry==NULL) { return KEYWORD_INVALID_ID; } return (int)Tcl_GetHashValue(entry); } const char *Keyword_getKey(int id) { char *key; Tcl_HashEntry *entry=Tcl_FindHashEntry(&backwardsLookup,(char *)id); if (entry==NULL) { return NULL; } key=(char *)Tcl_GetHashValue(entry); return key; } int Keyword_alias(char *alias,char *oldKey,int flags) { int id=Keyword_getId(oldKey); if (id==KEYWORD_INVALID_ID) { id=Keyword_addKey(oldKey); if (id==KEYWORD_INVALID_ID) { return id; } } if (TCL_OK!=Keyword_setId(alias,id,flags)) { return KEYWORD_INVALID_ID; } else { return id; } } int Keyword_addKey(char *key) { int result=Keyword_setId(key,entryCount,0); if (result==KEYWORD_INVALID_ID) { return KEYWORD_INVALID_ID; } else { if (entryCount==result) { entryCount++; } return result; } } static void kw_dupRepProc(Tcl_Obj *source, Tcl_Obj *dup) { dup->internalRep.longValue=source->internalRep.longValue; } static void kw_updateStringProc(Tcl_Obj *obj) { int id=obj->internalRep.longValue; const char *key=Keyword_getKey(id); #ifdef DEAL_MEMORY fprintf(stderr,"Getting string key for id %d - key %s\n",id,key); #endif if (key==NULL) { obj->bytes=Tcl_Alloc(1); (obj->bytes)[0]=0; } else { obj->length=strlen(key); obj->bytes=Tcl_Alloc(obj->length+1); strcpy(obj->bytes,key); } } static int kw_setFromAnyProc(Tcl_Interp *interp,Tcl_Obj *obj) { char *key=Tcl_GetString(obj); int id; if (key==NULL) { Tcl_AddErrorInfo(interp, "Cannot get string rep for object in kw_setFromAnyProc\n"); return TCL_ERROR; } #ifdef DEAL_MEMORY fprintf(stderr,"Getting Keyword id for key %s\n",key); #endif id=Keyword_getId(key); if (id==KEYWORD_INVALID_ID) { Tcl_AddErrorInfo(interp,"Unknown keyword: "); Tcl_AddErrorInfo(interp,key); return TCL_ERROR; } obj->typePtr=&KeywordType; obj->internalRep.longValue=id; return TCL_OK; } int Keyword_getIdFromObj(Tcl_Interp *interp,Tcl_Obj *obj) { if (obj->typePtr!=&KeywordType) { int res; res=Tcl_ConvertToType(interp,obj,&KeywordType); if (res!=TCL_OK) { return KEYWORD_INVALID_ID; } } return obj->internalRep.longValue; } Tcl_Obj *Keyword_NewObj(int id) { Tcl_Obj *obj; if (NULL==Keyword_getKey(id)) { return NULL; } obj=Tcl_NewObj(); if (NULL==obj) { return NULL; } obj->internalRep.longValue=id; obj->typePtr=&KeywordType; Tcl_InvalidateStringRep(obj); return obj; } int Keyword_Init(Tcl_Interp *interp) { Tcl_InitHashTable(&keywordsTable,TCL_STRING_KEYS); Tcl_InitHashTable(&backwardsLookup,TCL_ONE_WORD_KEYS); KeywordType.dupIntRepProc=&kw_dupRepProc; KeywordType.freeIntRepProc=NULL; KeywordType.name="Keywords"; KeywordType.setFromAnyProc=&kw_setFromAnyProc; KeywordType.updateStringProc=&kw_updateStringProc; Tcl_RegisterObjType(&KeywordType); return TCL_OK; } deal319/Make.ubuntu0000644000175200017520000000031611065072217012412 0ustar cbecbeCC=gcc DEBUG_FLAGS=-g -ansi -Wall -O2 CPPFLAGS = -fno-rtti -g -O2 # Ubuntu settings TCL_VERSION=8.5 TCL_INCL=/usr/include/tcl$(TCL_VERSION) TCL_LIB=/usr/lib LDFLAGS= -L$(TCL_LIB) -ltcl$(TCL_VERSION) -lm deal319/stringbox.h0000644000175200017520000000152011062564550012462 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "tcl_incl.h" extern int Stringbox_Init _ANSI_ARGS_((Tcl_Interp *)); deal319/deal.tcl0000644000175200017520000000261011063454127011703 0ustar cbecbe# # deal.tcl - this file is sourced at startup by Deal 3.0 or later # # Copyright (C) 1996-2001, Thomas Andrews # # $Id: deal.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Mac default value for tcl_library #set tcl_library /System/Library/Frameworks/Tcl.framework/Versions/8.4/Resources/Scripts # Windows default value for tcl_library if {[string first "Windows" $tcl_platform(os)]>=0} { set tcl_library C:/tcl/lib/tcl8.5 } catch { deal_init_tcl } source lib/features.tcl # If set to non-zero, and your terminal supports UTF-8, deal's default output format will write #the deal with unicode suit symbols. set deal::unicode 1 # Edit this line to make your default format any format source format/default deal319/keywords.h0000644000175200017520000000226111062564550012315 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "tcl_incl.h" #define KEYWORD_INVALID_ID -1 #define KEYWORD_SET_DEFAULT 1 #define KEYWORD_SET_NODUPLICATE 2 int Keyword_getId(char *key); int Keyword_alias(char *alias,char *oldKey,int flags); int Keyword_addKey(char *key); const char *Keyword_getKey(int id); Tcl_Obj *Keyword_NewObj(int id); int Keyword_Init(Tcl_Interp *interp); int Keyword_getIdFromObj(Tcl_Interp *interp,Tcl_Obj *obj); extern Tcl_ObjType KeywordType; deal319/formats.c0000644000175200017520000000247711062564550012125 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "formats.h" #include "dealtypes.h" #include "tcl_incl.h" Tcl_Obj *tcl_format_suit(holding,voidObj) int holding; Tcl_Obj *voidObj; { if ((holding&8191)==0 && voidObj!=NULL) { return voidObj; } else { return Tcl_NewHoldingObj(holding); } } Tcl_Obj *tcl_format_hand(hptrs,voidObj) int *hptrs; Tcl_Obj *voidObj; { int suit; Tcl_Obj *holdingElts[4]; for (suit=0; suit<4; suit++) { holdingElts[suit]=tcl_format_suit(hptrs[suit],voidObj); } return Tcl_NewListObj(4,holdingElts); } deal319/dealtypes.h0000644000175200017520000000310111062564550012432 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "tcl_incl.h" #include "keywords.h" #include "deal.h" extern Tcl_ObjType CardType, HoldingType; void initializeDealTypes(); void initializeLengths(); int getHandNumFromObj(Tcl_Interp *interp, Tcl_Obj *hand); Tcl_Obj *getHandKeywordObj(Tcl_Interp *interp, int num); Tcl_Obj *getLengthObj(int i); int getSuitNumFromObj(Tcl_Interp *interp, Tcl_Obj *suit); int getDenomNumFromObj(Tcl_Interp *interp, Tcl_Obj *suit); int getCardNumFromObj(Tcl_Interp *interp, Tcl_Obj *card); int getHoldingNumFromObj(Tcl_Interp *interp, Tcl_Obj *card); Tcl_Obj *Tcl_NewHoldingObj(int holding); Tcl_Obj * CONST *getAllSuitObjs(); char *getStringForHoldingNum(int holding,int *lenPtr); int getHandHoldingsFromObj(Tcl_Interp *interp,Tcl_Obj *obj, int *harray); int getHandHoldingsFromObjv(Tcl_Interp *interp,Tcl_Obj * CONST *objv, int *harray); deal319/dds.cpp0000644000175200017520000042257511224443222011561 0ustar cbecbe/* * * DDS 1.1.9 A bridge double dummy solver. * Copyright (C) 2006-2008 by Bo Haglund * Cleanups and porting to Linux and MacOSX (C) 2006 by Alex Martelli * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc, 51 Franklin Street, 5th Floor, Boston MA 02110-1301, USA. * */ #include "dds.h" const int ContractInfo::nextSuitArray[4][4] = { { 1, 2, 3, 4}, { 2, 0, 3, 4}, { 1, 3, 0, 4}, { 1, 2, 4, 0} }; GLOBALS Globals; int nodeTypeStore[4]; unsigned short int lowestWin[50][4]; int nodes; int trickNodes; int no[50]; int iniDepth; int seatToPlay; int payOff, val; struct pos lookAheadPos; /* Is initialized for starting alpha-beta search */ struct moveType forbiddenMoves[14]; struct moveType initialMoves[4]; struct moveType cd; struct movePlyType movePly[50]; int tricksTarget; struct gameInfo game; int estTricks[4]; FILE *fp2, *fp7, *fp11; struct moveType * bestMove; struct winCardType * temp_win; int hiwinSetSize=0, hinodeSetSize=0; int hilenSetSize=0; int MaxnodeSetSize=0; int MaxwinSetSize=0; int MaxlenSetSize=0; int nodeSetSizeLimit=0; int winSetSizeLimit=0; int lenSetSizeLimit=0; LONGLONG maxmem, allocmem, summem; int wmem, nmem, lmem; int maxIndex; int wcount, ncount, lcount; int clearTTflag=FALSE, windex=-1; int ttCollect=FALSE; int suppressTTlog=FALSE; /*int highestRank[8192]; struct adaptWinRanksType adaptWins[8192];*/ unsigned char cardRank[15], cardSuit[5], cardSeat[4]; LONGLONG suitLengths=0; struct posSearchType *rootnp[14][4]; struct winCardType **pw; struct nodeCardsType **pn; struct posSearchType **pl; #ifdef CANCEL int cancelOrdered=FALSE; int cancelStarted=FALSE; int threshold=CANCELCHECK; #endif #ifdef _MANAGED #pragma managed(push, off) #endif extern "C" inline holding_t distinctUnplayedCards(holding_t origHolding, holding_t played,holding_t *sequence) { holding_t bitRank; holding_t unplayed = origHolding & (~played); holding_t result = 0; int inSequence=0; *sequence = 0; if (unplayed) { for (bitRank = (1<<12); bitRank; bitRank >>= 1) { if (unplayed & bitRank) { if (inSequence) { *sequence |= bitRank; } else { result |= bitRank; inSequence = 1; } } else { if (!(played & bitRank)) { inSequence = 0; } } } } return result; } struct UnplayedCardsFinder { protected: struct diagram starting; public: UnplayedCardsFinder() {} void initialize(const struct diagram &diagram) { for (int seat=0; seat<4; seat++) { for (int suit=0; suit<4; suit++) { starting.cards[seat][suit] = diagram.cards[seat][suit]; } } } inline holding_t getUnplayed(int seat, int suit, holding_t played,holding_t &sequence) { holding_t holding = starting.cards[seat][suit]; return distinctUnplayedCards(holding,played,&sequence); } } unplayedFinder; #ifdef _MANAGED #pragma managed(pop) #endif int SolveBoard(struct deal dl, int target, int solutions, int mode, struct futureTricks *futp) { int k, n, cardCount, found, totalTricks, tricks, last, checkRes; int g, upperbound, lowerbound, first, i, j, forb, ind, flag, noMoves; int seat, suit; int mcurr; int noStartMoves; int seatRelFirst; int latestTrickSuit[4]; int latestTrickRank[4]; int maxSeat=0, maxSuit=0, maxRank; struct pos iniPosition; struct movePlyType temp; struct moveType mv; /*FILE *fp;*/ /*InitStart();*/ /* Include InitStart() if inside SolveBoard, but preferable InitStart should be called outside SolveBoard like in DllMain for Windows. */ for (k=0; k<=13; k++) { forbiddenMoves[k].rank=0; forbiddenMoves[k].suit=0; } if (target<-1) { DumpInput(-5, dl, target, solutions, mode); return -5; } if (target>13) { DumpInput(-7, dl, target, solutions, mode); return -7; } if (solutions<1) { DumpInput(-8, dl, target, solutions, mode); return -8; } if (solutions>3) { DumpInput(-9, dl, target, solutions, mode); return -9; } if (target==-1) { tricksTarget=99; } else { tricksTarget=target; } cardCount=0; for (seat=0; seat<=3; seat++) { for (suit=0; suit<=3; suit++) { game.diagram.cards[seat][suit]=dl.remaining.cards[seat][suit]; cardCount+=CountOnes(game.diagram.cards[seat][suit]); } } if (dl.currentTrickRank[2]) { if ((dl.currentTrickRank[2]<2)||(dl.currentTrickRank[2]>14) ||(dl.currentTrickSuit[2]<0)||(dl.currentTrickSuit[2]>3)) { DumpInput(-12, dl, target, solutions, mode); return -12; } seatToPlay=rho(dl.first); seatRelFirst=3; noStartMoves=3; if (cardCount<=4) { for (k=0; k<=3; k++) { if (game.diagram.cards[seatToPlay][k]!=0) { latestTrickSuit[seatToPlay]=k; latestTrickRank[seatToPlay]= InvBitMapRank(game.diagram.cards[seatToPlay][k]); break; } } latestTrickSuit[partner(dl.first)]=dl.currentTrickSuit[2]; latestTrickRank[partner(dl.first)]=dl.currentTrickRank[2]; latestTrickSuit[lho(dl.first)]=dl.currentTrickSuit[1]; latestTrickRank[lho(dl.first)]=dl.currentTrickRank[1]; latestTrickSuit[dl.first]=dl.currentTrickSuit[0]; latestTrickRank[dl.first]=dl.currentTrickRank[0]; } } else if (dl.currentTrickRank[1]) { if ((dl.currentTrickRank[1]<2)||(dl.currentTrickRank[1]>14) ||(dl.currentTrickSuit[1]<0)||(dl.currentTrickSuit[1]>3)) { DumpInput(-12, dl, target, solutions, mode); return -12; } seatToPlay=partner(dl.first); seatRelFirst=2; noStartMoves=2; if (cardCount<=4) { for (k=0; k<=3; k++) { if (game.diagram.cards[seatToPlay][k]!=0) { latestTrickSuit[seatToPlay]=k; latestTrickRank[seatToPlay]= InvBitMapRank(game.diagram.cards[seatToPlay][k]); break; } } for (k=0; k<=3; k++) { if (game.diagram.cards[rho(dl.first)][k]!=0) { latestTrickSuit[rho(dl.first)]=k; latestTrickRank[rho(dl.first)]= InvBitMapRank(game.diagram.cards[rho(dl.first)][k]); break; } } latestTrickSuit[lho(dl.first)]=dl.currentTrickSuit[1]; latestTrickRank[lho(dl.first)]=dl.currentTrickRank[1]; latestTrickSuit[dl.first]=dl.currentTrickSuit[0]; latestTrickRank[dl.first]=dl.currentTrickRank[0]; } } else if (dl.currentTrickRank[0]) { if ((dl.currentTrickRank[0]<2)||(dl.currentTrickRank[0]>14) ||(dl.currentTrickSuit[0]<0)||(dl.currentTrickSuit[0]>3)) { DumpInput(-12, dl, target, solutions, mode); return -12; } seatToPlay=lho(dl.first); seatRelFirst=1; noStartMoves=1; if (cardCount<=4) { for (k=0; k<=3; k++) { if (game.diagram.cards[seatToPlay][k]!=0) { latestTrickSuit[seatToPlay]=k; latestTrickRank[seatToPlay]= InvBitMapRank(game.diagram.cards[seatToPlay][k]); break; } } for (k=0; k<=3; k++) { if (game.diagram.cards[rho(dl.first)][k]!=0) { latestTrickSuit[rho(dl.first)]=k; latestTrickRank[rho(dl.first)]= InvBitMapRank(game.diagram.cards[rho(dl.first)][k]); break; } } for (k=0; k<=3; k++) { if (game.diagram.cards[partner(dl.first)][k]!=0) { latestTrickSuit[partner(dl.first)]=k; latestTrickRank[partner(dl.first)]= InvBitMapRank(game.diagram.cards[partner(dl.first)][k]); break; } } latestTrickSuit[dl.first]=dl.currentTrickSuit[0]; latestTrickRank[dl.first]=dl.currentTrickRank[0]; } } else { seatToPlay=dl.first; seatRelFirst=0; noStartMoves=0; if (cardCount<=4) { for (k=0; k<=3; k++) { if (game.diagram.cards[seatToPlay][k]!=0) { latestTrickSuit[seatToPlay]=k; latestTrickRank[seatToPlay]= InvBitMapRank(game.diagram.cards[seatToPlay][k]); break; } } for (k=0; k<=3; k++) { if (game.diagram.cards[rho(dl.first)][k]!=0) { latestTrickSuit[rho(dl.first)]=k; latestTrickRank[rho(dl.first)]= InvBitMapRank(game.diagram.cards[rho(dl.first)][k]); break; } } for (k=0; k<=3; k++) { if (game.diagram.cards[partner(dl.first)][k]!=0) { latestTrickSuit[partner(dl.first)]=k; latestTrickRank[partner(dl.first)]= InvBitMapRank(game.diagram.cards[partner(dl.first)][k]); break; } } for (k=0; k<=3; k++) { if (game.diagram.cards[lho(dl.first)][k]!=0) { latestTrickSuit[lho(dl.first)]=k; latestTrickRank[lho(dl.first)]= InvBitMapRank(game.diagram.cards[lho(dl.first)][k]); break; } } } } game.contract=100+10*(dl.trump+1); game.first=dl.first; first=dl.first; game.noOfCards=cardCount; if (dl.currentTrickRank[0]!=0) { game.leadSeat=dl.first; game.leadSuit=dl.currentTrickSuit[0]; game.leadRank=dl.currentTrickRank[0]; } else { game.leadSeat=0; game.leadSuit=0; game.leadRank=0; } for (k=0; k<=2; k++) { initialMoves[k].suit=255; initialMoves[k].rank=255; } for (k=0; k52) { DumpInput(-10, dl, target, solutions, mode); return -10; } if (totalTricksnodes=0; #ifdef BENCH futp->totalNodes=0; #endif futp->cards=1; futp->suit[0]=latestTrickSuit[seatToPlay]; futp->rank[0]=latestTrickRank[seatToPlay]; futp->equals[0]=0; if ((target==0)&&(solutions<3)) { futp->score[0]=0; } else if ((seatToPlay==maxSeat)|| (partner(seatToPlay)==maxSeat)) { futp->score[0]=1; } else { futp->score[0]=0; } return 1; } if (mode!=2) { Wipe(); winSetSizeLimit=WINIT; nodeSetSizeLimit=NINIT; lenSetSizeLimit=LINIT; allocmem=(WINIT+1)*sizeof(struct winCardType); allocmem+=(NINIT+1)*sizeof(struct nodeCardsType); allocmem+=(LINIT+1)*sizeof(struct posSearchType); winCards=pw[0]; nodeCards=pn[0]; posSearch=pl[0]; wcount=0; ncount=0; lcount=0; InitGame(0, FALSE, first, seatRelFirst,iniPosition); } else { InitGame(0, TRUE, first, seatRelFirst,iniPosition); } unplayedFinder.initialize(game.diagram); nodes=0; trickNodes=0; iniDepth=cardCount-4; hiwinSetSize=0; hinodeSetSize=0; if (mode==0) { MoveGen(&lookAheadPos, iniDepth); if (movePly[iniDepth].last==0) { futp->nodes=0; #ifdef BENCH futp->totalNodes=0; #endif futp->cards=1; futp->suit[0]=movePly[iniDepth].move[0].suit; futp->rank[0]=movePly[iniDepth].move[0].rank; futp->equals[0]= movePly[iniDepth].move[0].sequence<<2; futp->score[0]=-2; return 1; } } if ((target==0)&&(solutions<3)) { MoveGen(&lookAheadPos, iniDepth); futp->nodes=0; #ifdef BENCH futp->totalNodes=0; #endif for (k=0; k<=movePly[iniDepth].last; k++) { futp->suit[k]=movePly[iniDepth].move[k].suit; futp->rank[k]=movePly[iniDepth].move[k].rank; futp->equals[k]= movePly[iniDepth].move[k].sequence<<2; futp->score[k]=0; } if (solutions==1) futp->cards=1; else futp->cards=movePly[iniDepth].last+1; return 1; } if ((target!=-1)&&(solutions!=3)) { val=ABsearch(&lookAheadPos, tricksTarget, iniDepth); #ifdef CANCEL if (cancelStarted) { cancelOrdered=FALSE; cancelStarted=FALSE; return 2; } #endif temp=movePly[iniDepth]; last=movePly[iniDepth].last; noMoves=last+1; hiwinSetSize=winSetSize; hinodeSetSize=nodeSetSize; hilenSetSize=lenSetSize; if (nodeSetSize>MaxnodeSetSize) MaxnodeSetSize=nodeSetSize; if (winSetSize>MaxwinSetSize) MaxwinSetSize=winSetSize; if (lenSetSize>MaxlenSetSize) MaxlenSetSize=lenSetSize; if (val==1) payOff=tricksTarget; else payOff=0; futp->cards=1; ind=2; if (payOff<=0) { futp->suit[0]=movePly[game.noOfCards-4].move[0].suit; futp->rank[0]=movePly[game.noOfCards-4].move[0].rank; futp->equals[0]=(movePly[game.noOfCards-4].move[0].sequence)<<2; if (tricksTarget>1) futp->score[0]=-1; else futp->score[0]=0; } else { futp->suit[0]=bestMove[game.noOfCards-4].suit; futp->rank[0]=bestMove[game.noOfCards-4].rank; futp->equals[0]=(bestMove[game.noOfCards-4].sequence)<<2; futp->score[0]=payOff; } } else { g=estTricks[seatToPlay]; upperbound=(game.noOfCards+3)/4; lowerbound=0; do { if (g==lowerbound) { tricks=g+1; } else { tricks=g; } val=ABsearch(&lookAheadPos, tricks, iniDepth); #ifdef CANCEL if (cancelStarted) { cancelOrdered=FALSE; cancelStarted=FALSE; return 2; } #endif if (val==TRUE) { mv=bestMove[game.noOfCards-4]; } hiwinSetSize=Max(hiwinSetSize, winSetSize); hinodeSetSize=Max(hinodeSetSize, nodeSetSize); hilenSetSize=Max(hilenSetSize, lenSetSize); if (nodeSetSize>MaxnodeSetSize) MaxnodeSetSize=nodeSetSize; if (winSetSize>MaxwinSetSize) MaxwinSetSize=winSetSize; if (lenSetSize>MaxlenSetSize) MaxlenSetSize=lenSetSize; if (val==FALSE) { upperbound=tricks-1; g=upperbound; } else { lowerbound=tricks; g=lowerbound; } InitSearch(&iniPosition, game.noOfCards-4, initialMoves, first, TRUE); } while (lowerboundcards=1; if (payOff<=0) { futp->score[0]=0; futp->suit[0]=movePly[game.noOfCards-4].move[0].suit; futp->rank[0]=movePly[game.noOfCards-4].move[0].rank; futp->equals[0]=(movePly[game.noOfCards-4].move[0].sequence)<<2; } else { futp->score[0]=payOff; futp->suit[0]=bestMove[game.noOfCards-4].suit; futp->rank[0]=bestMove[game.noOfCards-4].rank; futp->equals[0]=(bestMove[game.noOfCards-4].sequence)<<2; } tricksTarget=payOff; } if ((solutions==2)&&(payOff>0)) { forb=1; ind=forb; while ((payOff==tricksTarget)&&(ind<(temp.last+1))) { forbiddenMoves[forb].suit=bestMove[game.noOfCards-4].suit; forbiddenMoves[forb].rank=bestMove[game.noOfCards-4].rank; forb++; ind++; /* All moves before bestMove in the move list shall be moved to the forbidden moves list, since none of them reached the target */ mcurr=movePly[iniDepth].current; for (k=0; k<=movePly[iniDepth].last; k++) if ((bestMove[iniDepth].suit==movePly[iniDepth].move[k].suit) &&(bestMove[iniDepth].rank==movePly[iniDepth].move[k].rank)) break; for (i=0; iMaxnodeSetSize) MaxnodeSetSize=nodeSetSize; if (winSetSize>MaxwinSetSize) MaxwinSetSize=winSetSize; if (lenSetSize>MaxlenSetSize) MaxlenSetSize=lenSetSize; if (val==TRUE) { payOff=tricksTarget; futp->cards=ind; futp->suit[ind-1]=bestMove[game.noOfCards-4].suit; futp->rank[ind-1]=bestMove[game.noOfCards-4].rank; futp->equals[ind-1]=(bestMove[game.noOfCards-4].sequence)<<2; futp->score[ind-1]=payOff; } else payOff=0; } } else if ((solutions==2)&&(payOff==0)&&((target==-1)||(tricksTarget==1))) { futp->cards=noMoves; /* Find the cards that were in the initial move list but have not been listed in the current result */ n=0; for (i=0; isuit[0])&& (temp.move[i].rank==futp->rank[0])) { found=TRUE; } if (!found) { futp->suit[1+n]=temp.move[i].suit; futp->rank[1+n]=temp.move[i].rank; futp->equals[1+n]=(temp.move[i].sequence)<<2; futp->score[1+n]=0; n++; } } } if ((solutions==3)&&(payOff>0)) { forb=1; ind=forb; for (i=0; iMaxnodeSetSize) MaxnodeSetSize=nodeSetSize; if (winSetSize>MaxwinSetSize) MaxwinSetSize=winSetSize; if (lenSetSize>MaxlenSetSize) MaxlenSetSize=lenSetSize; if (val==FALSE) { upperbound=tricks-1; g=upperbound; } else { lowerbound=tricks; g=lowerbound; } if (0) { InitSearch(&iniPosition, game.noOfCards-4, initialMoves, first, FALSE); } else { InitSearch(&iniPosition, game.noOfCards-4, initialMoves, first, TRUE); } } while (lowerboundcards=temp.last+1; for (j=0; j<=last; j++) { futp->suit[ind-1+j]=movePly[game.noOfCards-4].move[j].suit; futp->rank[ind-1+j]=movePly[game.noOfCards-4].move[j].rank; futp->equals[ind-1+j]=(movePly[game.noOfCards-4].move[j].sequence)<<2; futp->score[ind-1+j]=payOff; } break; } else { bestMove[game.noOfCards-4]=mv; futp->cards=ind; futp->suit[ind-1]=bestMove[game.noOfCards-4].suit; futp->rank[ind-1]=bestMove[game.noOfCards-4].rank; futp->equals[ind-1]=(bestMove[game.noOfCards-4].sequence)<<2; futp->score[ind-1]=payOff; } } } else if ((solutions==3)&&(payOff==0)) { futp->cards=noMoves; /* Find the cards that were in the initial move list but have not been listed in the current result */ n=0; for (i=0; isuit[0])&& (temp.move[i].rank==futp->rank[0])) { found=TRUE; } if (!found) { futp->suit[1+n]=temp.move[i].suit; futp->rank[1+n]=temp.move[i].rank; futp->equals[1+n]=(temp.move[i].sequence)<<2; futp->score[1+n]=0; n++; } } } for (k=0; k<=13; k++) { forbiddenMoves[k].suit=0; forbiddenMoves[k].rank=0; } futp->nodes=trickNodes; #ifdef BENCH futp->totalNodes=nodes; #endif /*if ((wcount>0)||(ncount>0)||(lcount>0)) { fp2=fopen("dyn.txt", "a"); fprintf(fp2, "wcount=%d, ncount=%d, lcount=%d\n", wcount, ncount, lcount); fprintf(fp2, "winSetSize=%d, nodeSetSize=%d, lenSetSize=%d\n", winSetSize, nodeSetSize, lenSetSize); fprintf(fp2, "\n"); fclose(fp2); }*/ return 1; } const RelativeRanksFinder &rel=Globals.rel; struct ttStoreType * ttStore; struct nodeCardsType * nodeCards; struct winCardType * winCards; struct posSearchType * posSearch; holding_t iniRemovedRanks[4]; int nodeSetSize=0; /* Index with range 0 to nodeSetSizeLimit */ int winSetSize=0; /* Index with range 0 to winSetSizeLimit */ int lenSetSize=0; /* Index with range 0 to lenSetSizeLimit */ int lastTTstore=0; int _initialized=0; extern "C" void DDSInitStart(void) { InitStart(); } void InitStart(void) { int k; if (_initialized) return; _initialized = 1; nodeSetSizeLimit=NINIT; winSetSizeLimit=WINIT; lenSetSizeLimit=LINIT; maxmem=(6000001*sizeof(struct nodeCardsType)+ 18000001*sizeof(struct winCardType)+ 240001*sizeof(struct posSearchType)); bestMove = (struct moveType *)calloc(50, sizeof(struct moveType)); /*bestMove = new moveType [50];*/ if (bestMove==NULL) { exit(1); } cardRank[2]='2'; cardRank[3]='3'; cardRank[4]='4'; cardRank[5]='5'; cardRank[6]='6'; cardRank[7]='7'; cardRank[8]='8'; cardRank[9]='9'; cardRank[10]='T'; cardRank[11]='J'; cardRank[12]='Q'; cardRank[13]='K'; cardRank[14]='A'; cardSuit[0]='S'; cardSuit[1]='H'; cardSuit[2]='D'; cardSuit[3]='C'; cardSuit[4]='N'; cardSeat[0]='N'; cardSeat[1]='E'; cardSeat[2]='S'; cardSeat[3]='W'; temp_win = (struct winCardType *)calloc(5, sizeof(struct winCardType)); if (temp_win==NULL) exit(1); summem=(WINIT+1)*sizeof(struct winCardType)+ (NINIT+1)*sizeof(struct nodeCardsType)+ (LINIT+1)*sizeof(struct posSearchType); wmem=(WSIZE+1)*sizeof(struct winCardType); nmem=(NSIZE+1)*sizeof(struct nodeCardsType); lmem=(LSIZE+1)*sizeof(struct posSearchType); maxIndex=(int)(maxmem-summem)/((WSIZE+1) * sizeof(struct winCardType)); pw = (struct winCardType **)calloc(maxIndex+1, sizeof(struct winCardType *)); if (pw==NULL) exit(1); pn = (struct nodeCardsType **)calloc(maxIndex+1, sizeof(struct nodeCardsType *)); if (pn==NULL) exit(1); pl = (struct posSearchType **)calloc(maxIndex+1, sizeof(struct posSearchType *)); if (pl==NULL) exit(1); for (k=0; k<=maxIndex; k++) { if (pw[k]) { free(pw[k]); } pw[k]=NULL; } for (k=0; k<=maxIndex; k++) { if (pn[k]) { free(pn[k]); } pn[k]=NULL; } for (k=0; k<=maxIndex; k++) { if (pl[k]) { free(pl[k]); } pl[k]=NULL; } pw[0] = (struct winCardType *)calloc(winSetSizeLimit+1, sizeof(struct winCardType)); if (pw[0]==NULL) exit(1); allocmem=(winSetSizeLimit+1)*sizeof(struct winCardType); winCards=pw[0]; pn[0] = (struct nodeCardsType *)calloc(nodeSetSizeLimit+1, sizeof(struct nodeCardsType)); if (pn[0]==NULL) exit(1); allocmem+=(nodeSetSizeLimit+1)*sizeof(struct nodeCardsType); nodeCards=pn[0]; pl[0] = (struct posSearchType *)calloc(lenSetSizeLimit+1, sizeof(struct posSearchType)); if (pl[0]==NULL) exit(1); allocmem+=(lenSetSizeLimit+1)*sizeof(struct posSearchType); posSearch=pl[0]; wcount=0; ncount=0; lcount=0; ttStore = (struct ttStoreType *)calloc(SEARCHSIZE, sizeof(struct ttStoreType)); /*ttStore = new ttStoreType[SEARCHSIZE];*/ if (ttStore==NULL) { exit(1); } initializeDDSLookup(); return; } void InitGame(int gameNo, int moveTreeFlag, int first, int seatRelFirst, struct pos &iniPosition) { int k, temp1, temp2,m; /*int points[4], tricks; int addNS, addEW, addMAX, trumpNS, trumpEW; struct gameInfo gm;*/ #ifdef STAT fp2=fopen("stat.txt","w"); #endif #ifdef TTDEBUG if (!suppressTTlog) { fp7=fopen("storett.txt","w"); fp11=fopen("rectt.txt", "w"); fclose(fp11); ttCollect=TRUE; } #endif for (k=0; k<=3; k++) { for (m=0; m<=3; m++) { iniPosition.diagram.cards[k][m]=game.diagram.cards[k][m]; } } iniPosition.stack[game.noOfCards-4].first=first; iniPosition.seatRelFirst=seatRelFirst; lookAheadPos=iniPosition; Globals.rel.initialize(game.diagram); temp1=game.contract/100; temp2=game.contract-100*temp1; int trump=temp2/10-1; Globals.setContract(trump); estTricks[1]=6; estTricks[3]=6; estTricks[0]=7; estTricks[2]=7; /*end: tricksest */ #ifdef STAT fprintf(fp2, "Estimated tricks for seat to play:\n"); fprintf(fp2, "seat=%d est tricks=%d\n", seatToPlay, estTricks[seatToPlay]); #endif InitSearch(&lookAheadPos, game.noOfCards-4, initialMoves, first, moveTreeFlag); return; } void InitSearch(struct pos * posPoint, int depth, struct moveType startMoves[], int first, int mtd) { int s, d, h, seatRelFirst; int k, noOfStartMoves; /* Number of start moves in the 1st trick */ int seat[3], suit[3], rank[3]; struct moveType move; unsigned short int startMovesBitMap[4][4]; /* Indices are seat and suit */ const ContractInfo contract = Globals.getContract(); for (h=0; h<=3; h++) for (s=0; s<=3; s++) startMovesBitMap[h][s]=0; seatRelFirst=posPoint->seatRelFirst; noOfStartMoves=seatRelFirst; for (k=0; k<=2; k++) { seat[k]=RelativeSeat(first,k); suit[k]=startMoves[k].suit; rank[k]=startMoves[k].rank; if (kstack[depth].first=first; posPoint->seatRelFirst=k; posPoint->tricksMAX=0; if (k>0) { posPoint->stack[depth+k].move=startMoves[k-1]; move=startMoves[k-1]; } posPoint->stack[depth+k].high=first; while (k>0) { movePly[depth+k].current=0; movePly[depth+k].last=0; movePly[depth+k].move[0].suit=startMoves[k-1].suit; movePly[depth+k].move[0].rank=startMoves[k-1].rank; if (kstack[depth+k].move.suit=startMoves[k-1].suit; posPoint->stack[depth+k].move.rank=startMoves[k-1].rank; posPoint->stack[depth+k].high=RelativeSeat(first,noOfStartMoves-k); move=posPoint->stack[depth+k].move; } else { posPoint->stack[depth+k].move=posPoint->stack[depth+k+1].move; posPoint->stack[depth+k].high=posPoint->stack[depth+k+1].high; } } k--; } for (s=0; s<=3; s++) { posPoint->removedRanks[s]=0; } for (s=0; s<=3; s++) { /* Suit */ for (h=0; h<=3; h++) { /* Seat */ posPoint->removedRanks[s] |= posPoint->diagram.cards[h][s]; } } for (s=0; s<=3; s++) { posPoint->removedRanks[s] = 8191 & ~(posPoint->removedRanks[s]); } for (s=0; s<=3; s++) { /* Suit */ for (h=0; h<=3; h++) { /* Seat */ posPoint->removedRanks[s] &= (~startMovesBitMap[h][s]); } } for (s=0; s<=3; s++) { iniRemovedRanks[s]=posPoint->removedRanks[s]; } /* Initialize winning rank */ holding_t aggSeat[4][4]; int maxSeat = -1; for (s=0; s<=3; s++) { holding_t maxAgg = 0; for (h=0; h<=3; h++) { aggSeat[h][s]=startMovesBitMap[h][s] | game.diagram.cards[h][s]; if (aggSeat[h][s]>maxAgg) { maxAgg=aggSeat[h][s]; maxSeat=h; } } if (maxAgg!=0) { posPoint->winner[s].seat=maxSeat; k=getHighestRank(aggSeat[maxSeat][s]); posPoint->winner[s].rank=k; maxAgg=0; for (h=0; h<=3; h++) { aggSeat[h][s]&=(~BitRank(k)); if (aggSeat[h][s]>maxAgg) { maxAgg=aggSeat[h][s]; maxSeat=h; } } if (maxAgg>0) { posPoint->secondBest[s].seat=maxSeat; posPoint->secondBest[s].rank=getHighestRank(aggSeat[maxSeat][s]); } else { posPoint->secondBest[s].seat=-1; posPoint->secondBest[s].rank=0; } } else { posPoint->winner[s].seat=-1; posPoint->winner[s].rank=0; posPoint->secondBest[s].seat=-1; posPoint->secondBest[s].rank=0; } } for (s=0; s<=3; s++) { for (h=0; h<=3; h++) { posPoint->length[h][s]= (unsigned char)CountOnes(posPoint->diagram.cards[h][s]); } } #ifdef STAT for (d=0; d<=49; d++) { score1Counts[d]=0; score0Counts[d]=0; c1[d]=0; c2[d]=0; c3[d]=0; c4[d]=0; c5[d]=0; c6[d]=0; c7[d]=0; c8[d]=0; no[d]=0; } #endif if (!mtd) { lenSetSize=0; for (k=0; k<=13; k++) { for (h=0; h<=3; h++) { rootnp[k][h]=&posSearch[lenSetSize]; posSearch[lenSetSize].suitLengths=0; posSearch[lenSetSize].posSearchPoint=NULL; posSearch[lenSetSize].left=NULL; posSearch[lenSetSize].right=NULL; lenSetSize++; } } nodeSetSize=0; winSetSize=0; } #ifdef TTDEBUG if (!suppressTTlog) lastTTstore=0; #endif recInd=0; return; } int mexists, ready, hfirst; int mcurrent, qtricks, out, sout, hout; int res; unsigned char cind; int minimum, sopFound, nodeFound; int score1Counts[50], score0Counts[50]; int sumScore1Counts, sumScore0Counts; int c1[50], c2[50], c3[50], c4[50], c5[50], c6[50], c7[50], c8[50], c9[50]; int sumc1, sumc2, sumc3, sumc4, sumc5, sumc6, sumc7, sumc8, sumc9; int scoreFlag; int tricks, n; int hh, ss, rr, mm, dd, fh; int mcount, /*seat, */suit, rank, order; int k, cardFound, currSeat, a, found; struct evalType evalData; struct winCardType * np; struct posSearchType * pp; struct nodeCardsType * sopP; struct nodeCardsType * tempP; holding_t aggr[4]; holding_t tricksLeft; holding_t ranks; int ABsearch(struct pos * posPoint, int target, int depth) { /* posPoint points to the current look-ahead position, target is number of tricks to take for the player, depth is the remaining search length, must be positive, the value of the subtree is returned. */ int moveExists, value; struct makeType makeData; struct nodeCardsType * cardsP; const ContractInfo contract = Globals.getContract(); struct evalType Evaluate(const struct pos * posPoint); struct makeType Make(struct pos * posPoint, int depth); void Undo(struct pos * posPoint, int depth); #ifdef CANCEL if (nodes > threshold) { if (cancelOrdered) { cancelStarted=TRUE; return FALSE; } else { threshold+=CANCELCHECK; } } #endif /*cardsP=NULL;*/ const int seat=RelativeSeat(posPoint->stack[depth].first,posPoint->seatRelFirst); nodes++; if (posPoint->seatRelFirst==0) { trickNodes++; if (posPoint->tricksMAX>=target) { for (ss=0; ss<=3; ss++) posPoint->stack[depth].winRanks[ss]=0; #ifdef STAT c1[depth]++; score1Counts[depth]++; if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif return TRUE; } if (((posPoint->tricksMAX+(depth>>2)+1)0)) { for (ss=0; ss<=3; ss++) posPoint->stack[depth].winRanks[ss]=0; #ifdef STAT c2[depth]++; score0Counts[depth]++; if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif return FALSE; } if (nodeTypeStore[seat]==MAXNODE) { qtricks=QuickTricks(posPoint, seat, depth, target, &res); if (res) { if (qtricks==0) { /* Tricks for MIN side gave cutoff */ return FALSE; } else { return TRUE; } #ifdef STAT c3[depth]++; score1Counts[depth]++; if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif } if (!LaterTricksMIN(posPoint,seat,depth,target)) { return FALSE; } } else { qtricks=QuickTricks(posPoint, seat, depth, target, &res); if (res) { if (qtricks==0) { /* Tricks for MAX side gave cutoff */ return TRUE; } else { return FALSE; } #ifdef STAT c4[depth]++; score0Counts[depth]++; if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif } if (LaterTricksMAX(posPoint,seat,depth,target)) { return TRUE; } } } else if (posPoint->seatRelFirst==1) { ss=posPoint->stack[depth+1].move.suit; ranks=posPoint->diagram.cards[seat][ss] | posPoint->diagram.cards[partner(seat)][ss]; found=FALSE; rr=0; qtricks=0; if ( ranks >(BitRank(posPoint->stack[depth+1].move.rank) | posPoint->diagram.cards[lho(seat)][ss])) { /* Own side has highest card in suit */ if (!contract.trumpContract || ((ss==contract.trump) || (posPoint->diagram.cards[lho(seat)][contract.trump]==0) || (posPoint->diagram.cards[lho(seat)][ss]!=0))) { rr=getHighestRank(ranks); if (rr!=0) { found=TRUE; qtricks=1; } else { found=FALSE; } } } else if (contract.notTrumpWithTrump(ss) && (((posPoint->diagram.cards[seat][ss]==0) && (posPoint->diagram.cards[seat][contract.trump]!=0))|| ((posPoint->diagram.cards[partner(seat)][ss]==0) && (posPoint->diagram.cards[partner(seat)][contract.trump]!=0)))) { /* Own side can ruff */ if ((posPoint->diagram.cards[lho(seat)][ss]!=0)|| (posPoint->diagram.cards[lho(seat)][contract.trump]==0)) { found=TRUE; qtricks=1; } } if (nodeTypeStore[seat]==MAXNODE) { if ((posPoint->tricksMAX+qtricks>=target)&&(found)&& (depth!=iniDepth)) { for (k=0; k<=3; k++) posPoint->stack[depth].winRanks[k]=0; if (rr!=0) posPoint->stack[depth].winRanks[ss] |= BitRank(rr); return TRUE; } } else { if (((posPoint->tricksMAX+((depth)>>2)+3-qtricks)<=target)&& (found)&&(depth!=iniDepth)) { for (k=0; k<=3; k++) posPoint->stack[depth].winRanks[k]=0; if (rr!=0) posPoint->stack[depth].winRanks[ss] |= BitRank(rr); return FALSE; } } } if (posPoint->seatRelFirst==0) { posPoint->computeOrderSet(); tricks=depth>>2; posPoint->getSuitLengths(suitLengths); pp=SearchLenAndInsert(rootnp[tricks][seat], suitLengths, FALSE, &res); /* Find node that fits the suit lengths */ if (pp!=NULL) { np=pp->posSearchPoint; if (np==NULL) { cardsP=NULL; } else { cardsP=FindSOP(posPoint, np, seat, target, tricks, &scoreFlag); } if ((cardsP!=NULL)&&(depth!=iniDepth)) { if (scoreFlag==1) { posPoint->winAdapt(depth, cardsP, posPoint->aggregate); if (cardsP->bestMoveRank!=0) { bestMove[depth].suit=cardsP->bestMoveSuit; bestMove[depth].rank=cardsP->bestMoveRank; } #ifdef STAT c5[depth]++; if (scoreFlag==1) { score1Counts[depth]++; } else { score0Counts[depth]++; } if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif #ifdef TTDEBUG if (!suppressTTlog) { if (lastTTstorewinAdapt(depth, cardsP, posPoint->aggregate); if (cardsP->bestMoveRank!=0) { bestMove[depth].suit=cardsP->bestMoveSuit; bestMove[depth].rank=cardsP->bestMoveRank; } #ifdef STAT c6[depth]++; if (scoreFlag==1) { score1Counts[depth]++; } else { score0Counts[depth]++; } if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif #ifdef TTDEBUG if (!suppressTTlog) { if (lastTTstore=target) { value=TRUE; } else { value=FALSE; } for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=evalData.winRanks[ss]; #ifdef STAT c7[depth]++; if (value==1) { score1Counts[depth]++; } else { score0Counts[depth]++; } if (depth==iniDepth) { fprintf(fp2, "score statistics:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "d=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); } } #endif } return value; } else { /* Not at maximum depth */ moveExists=MoveGen(posPoint, depth); if ((posPoint->seatRelFirst==3)&&(depth>=/*29*/33/*37*/)&&(depth!=iniDepth)) { movePly[depth].current=0; mexists=TRUE; ready=FALSE; while (mexists) { makeData=Make(posPoint, depth); depth--; posPoint->computeOrderSet(); tricks=depth/4; hfirst=posPoint->stack[depth].first; posPoint->getSuitLengths(suitLengths); pp=SearchLenAndInsert(rootnp[tricks][hfirst], suitLengths, FALSE, &res); /* Find node that fits the suit lengths */ if (pp!=NULL) { np=pp->posSearchPoint; if (np==NULL) { tempP=NULL; } else { tempP=FindSOP(posPoint, np, hfirst, target, tricks, &scoreFlag); } if (tempP!=NULL) { if ((nodeTypeStore[seat]==MAXNODE)&&(scoreFlag==1)) { posPoint->winAdapt(depth+1, tempP, posPoint->aggregate); if (tempP->bestMoveRank!=0) { bestMove[depth+1].suit=tempP->bestMoveSuit; bestMove[depth+1].rank=tempP->bestMoveRank; } for (ss=0; ss<=3; ss++) { posPoint->stack[depth+1].winRanks[ss] |= makeData.winRanks[ss]; } Undo(posPoint, depth+1); return TRUE; } else if ((nodeTypeStore[seat]==MINNODE)&&(scoreFlag==0)) { posPoint->winAdapt(depth+1, tempP, posPoint->aggregate); if (tempP->bestMoveRank!=0) { bestMove[depth+1].suit=tempP->bestMoveSuit; bestMove[depth+1].rank=tempP->bestMoveRank; } for (ss=0; ss<=3; ss++) { posPoint->stack[depth+1].winRanks[ss] |= makeData.winRanks[ss]; } Undo(posPoint, depth+1); return FALSE; } else { movePly[depth+1].move[movePly[depth+1].current].weight+=100; ready=TRUE; } } } depth++; Undo(posPoint, depth); if (ready) { break; } if (movePly[depth].currentstack[depth].winRanks[ss]=0; } while (moveExists) { makeData=Make(posPoint, depth); /* Make current move */ value=ABsearch(posPoint, target, depth-1); #ifdef CANCEL if (cancelStarted) { return FALSE; } #endif Undo(posPoint, depth); /* Retract current move */ if (value==TRUE) { /* A cut-off? */ for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss] = posPoint->stack[depth-1].winRanks[ss] | makeData.winRanks[ss]; } mcurrent=movePly[depth].current; bestMove[depth]=movePly[depth].move[mcurrent]; goto ABexit; } for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss] |= posPoint->stack[depth-1].winRanks[ss] | makeData.winRanks[ss]; } moveExists=NextMove(posPoint, depth); } } else { /* A minnode */ value=TRUE; for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=0; } while (moveExists) { makeData=Make(posPoint, depth); /* Make current move */ value=ABsearch(posPoint, target, depth-1); #ifdef CANCEL if (cancelStarted) { return FALSE; } #endif Undo(posPoint, depth); /* Retract current move */ if (value==FALSE) { /* A cut-off? */ for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=posPoint->stack[depth-1].winRanks[ss] | makeData.winRanks[ss]; } mcurrent=movePly[depth].current; bestMove[depth]=movePly[depth].move[mcurrent]; goto ABexit; } for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss] |= posPoint->stack[depth-1].winRanks[ss] | makeData.winRanks[ss]; } moveExists=NextMove(posPoint, depth); } } } ABexit: if (depth>=4) { if(posPoint->seatRelFirst==0) { tricks=depth>>2; /*seat=posPoint->first[depth-1];*/ if (value) { k=target; } else { k=target-1; } BuildSOP(posPoint, tricks, seat, target, depth,value, k); if (clearTTflag) { /* Wipe out the TT dynamically allocated structures except for the initially allocated structures. Set the TT limits to the initial values. Reset TT array indices to zero. Reset memory chunk indices to zero. Set allocated memory to the initial value. */ Wipe(); winSetSizeLimit=WINIT; nodeSetSizeLimit=NINIT; lenSetSizeLimit=LINIT; lcount=0; allocmem=(lenSetSizeLimit+1)*sizeof(struct posSearchType); lenSetSize=0; posSearch=pl[lcount]; for (k=0; k<=13; k++) { for (hh=0; hh<=3; hh++) { rootnp[k][hh]=&posSearch[lenSetSize]; posSearch[lenSetSize].suitLengths=0; posSearch[lenSetSize].posSearchPoint=NULL; posSearch[lenSetSize].left=NULL; posSearch[lenSetSize].right=NULL; lenSetSize++; } } nodeSetSize=0; winSetSize=0; wcount=0; ncount=0; allocmem+=(winSetSizeLimit+1)*sizeof(struct winCardType); winCards=pw[wcount]; allocmem+=(nodeSetSizeLimit+1)*sizeof(struct nodeCardsType); nodeCards=pn[ncount]; clearTTflag=FALSE; windex=-1; } } } #ifdef STAT c8[depth]++; if (value==1) { score1Counts[depth]++; } else { score0Counts[depth]++; } if (depth==iniDepth) { if (fp2==NULL) { exit(0); } fprintf(fp2, "\n"); fprintf(fp2, "top level cards:\n"); for (hh=0; hh<=3; hh++) { fprintf(fp2, "seat=%c\n", cardSeat[hh]); for (ss=0; ss<=3; ss++) { fprintf(fp2, "suit=%c", cardSuit[ss]); for (rr=14; rr>=2; rr--) if (posPoint->diagram.cards[hh][ss] & BitRank(rr)) fprintf(fp2, " %c", cardRank[rr]); fprintf(fp2, "\n"); } fprintf(fp2, "\n"); } fprintf(fp2, "top level winning cards:\n"); for (ss=0; ss<=3; ss++) { fprintf(fp2, "suit=%c", cardSuit[ss]); for (rr=14; rr>=2; rr--) { if (posPoint->stack[depth].winRanks[ss] & BitRank(rr)) { fprintf(fp2, " %c", cardRank[rr]); } } fprintf(fp2, "\n"); } fprintf(fp2, "\n"); fprintf(fp2, "\n"); fprintf(fp2, "score statistics:\n"); sumScore0Counts=0; sumScore1Counts=0; sumc1=0; sumc2=0; sumc3=0; sumc4=0; sumc5=0; sumc6=0; sumc7=0; sumc8=0; sumc9=0; for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "depth=%d s1=%d s0=%d c1=%d c2=%d c3=%d c4=%d", dd, score1Counts[dd], score0Counts[dd], c1[dd], c2[dd], c3[dd], c4[dd]); fprintf(fp2, " c5=%d c6=%d c7=%d c8=%d\n", c5[dd], c6[dd], c7[dd], c8[dd]); sumScore0Counts=sumScore0Counts+score0Counts[dd]; sumScore1Counts=sumScore1Counts+score1Counts[dd]; sumc1=sumc1+c1[dd]; sumc2=sumc2+c2[dd]; sumc3=sumc3+c3[dd]; sumc4=sumc4+c4[dd]; sumc5=sumc5+c5[dd]; sumc6=sumc6+c6[dd]; sumc7=sumc7+c7[dd]; sumc8=sumc8+c8[dd]; sumc9=sumc9+c9[dd]; } fprintf(fp2, "\n"); fprintf(fp2, "score sum statistics:\n"); fprintf(fp2, "\n"); fprintf(fp2, "sumScore0Counts=%d sumScore1Counts=%d\n", sumScore0Counts, sumScore1Counts); fprintf(fp2, "nodeSetSize=%d winSetSize=%d\n", nodeSetSize, winSetSize); fprintf(fp2, "sumc1=%d sumc2=%d sumc3=%d sumc4=%d\n", sumc1, sumc2, sumc3, sumc4); fprintf(fp2, "sumc5=%d sumc6=%d sumc7=%d sumc8=%d sumc9=%d\n", sumc5, sumc6, sumc7, sumc8, sumc9); fprintf(fp2, "\n"); fprintf(fp2, "\n"); fprintf(fp2, "No of searched nodes per depth:\n"); for (dd=iniDepth; dd>=0; dd--) { fprintf(fp2, "depth=%d nodes=%d\n", dd, no[dd]); } fprintf(fp2, "\n"); fprintf(fp2, "Total nodes=%d\n", nodes); } #endif return value; } struct makeType Make(struct pos * posPoint, int depth) { int r, s, t, u, w, firstSeat; int suit, /*rank, */count, mcurr, h, q, done; struct makeType trickCards; struct moveType mo1, mo2; const ContractInfo contract = Globals.getContract(); struct posStackItem ¤t = posPoint->stack[depth]; const struct posStackItem &previous = posPoint->stack[depth+1]; for (suit=0; suit<=3; suit++) { trickCards.winRanks[suit]=0; } firstSeat=current.first; r=movePly[depth].current; if (posPoint->seatRelFirst==3) { /* This seat is last seat */ mo1 = movePly[depth].move[r]; mo2 = previous.move; if (contract.betterMove(mo1,mo2)) { current.move=mo1; current.high=rho(firstSeat); } else { current.move=mo2; current.high=previous.high; } /* Is the trick won by rank? */ suit=current.move.suit; /*rank=posPoint->stack[depth+h].stack[depth].move.rank;*/ count=0; for (h=0; h<=3; h++) { mcurr=movePly[depth+h].current; if (movePly[depth+h].move[mcurr].suit==suit) { count++; } } if (nodeTypeStore[current.high]==MAXNODE) posPoint->tricksMAX++; posPoint->stack[depth-1].first=current.high; /* Defines who is first in the next move */ t=rho(firstSeat); posPoint->seatRelFirst=0; /* Seat pointed to by posPoint->first will lead the next trick */ done=FALSE; for (s=3; s>=0; s--) { q=RelativeSeat(firstSeat,3-s); /* Add the moves to removed ranks */ r=movePly[depth+s].current; w=movePly[depth+s].move[r].rank; u=movePly[depth+s].move[r].suit; posPoint->removeRank(u,w); if (s==0) posPoint->diagram.cards[t][u] &= (~BitRank(w)); if (w==posPoint->winner[u].rank) { UpdateWinner(posPoint, u); } else if (w==posPoint->secondBest[u].rank) { UpdateSecondBest(posPoint, u); } /* Determine win-ranked cards */ if ((q==current.high)&&(!done)) { done=TRUE; if (count>=2) { trickCards.winRanks[u]=BitRank(w); /* Mark ranks as winning if they are part of a sequence */ trickCards.winRanks[u] |= movePly[depth+s].move[r].sequence; } } } } else if (posPoint->seatRelFirst==0) { /* Is it the 1st seat? */ posPoint->stack[depth-1].first=firstSeat; /* First seat is not changed in next move */ current.high=firstSeat; current.move=movePly[depth].move[r]; t=firstSeat; posPoint->seatRelFirst=1; r=movePly[depth].current; u=movePly[depth].move[r].suit; w=movePly[depth].move[r].rank; posPoint->diagram.cards[t][u] &= (~BitRank(w)); } else { /* Second or third seat in trick */ mo1=movePly[depth].move[r]; mo2=previous.move; r=movePly[depth].current; u=movePly[depth].move[r].suit; w=movePly[depth].move[r].rank; if (contract.betterMove(mo1,mo2)) { current.move=mo1; current.high=RelativeSeat(firstSeat,posPoint->seatRelFirst); } else { current.move=previous.move; current.high=previous.high; } t=RelativeSeat(firstSeat,posPoint->seatRelFirst); posPoint->seatRelFirst++; /* Current seat is stepped */ posPoint->stack[depth-1].first=firstSeat; /* First seat is not changed in next move */ r=movePly[depth].current; u=movePly[depth].move[r].suit; w=movePly[depth].move[r].rank; posPoint->diagram.cards[t][u] &= (~BitRank(w)); } posPoint->length[t][u]--; no[depth]++; return trickCards; } void Undo(struct pos * posPoint, int depth) { int r, s, t, u, w, firstSeat; firstSeat=posPoint->stack[depth].first; switch (posPoint->seatRelFirst) { case 3: case 2: case 1: posPoint->seatRelFirst--; break; case 0: posPoint->seatRelFirst=3; } if (posPoint->seatRelFirst==0) { /* 1st seat which won the previous trick */ t=firstSeat; r=movePly[depth].current; u=movePly[depth].move[r].suit; w=movePly[depth].move[r].rank; } else if (posPoint->seatRelFirst==3) { /* Last seat */ for (s=3; s>=0; s--) { /* Delete the moves from removed ranks */ r=movePly[depth+s].current; w=movePly[depth+s].move[r].rank; u=movePly[depth+s].move[r].suit; //posPoint->removedRanks[u]=posPoint->removedRanks[u] & (~BitRank(w)); posPoint->restoreRank(u,w); if (w>posPoint->winner[u].rank) { posPoint->secondBest[u].rank=posPoint->winner[u].rank; posPoint->secondBest[u].seat=posPoint->winner[u].seat; posPoint->winner[u].rank=w; posPoint->winner[u].seat=RelativeSeat(firstSeat,3-s); } else if (w>posPoint->secondBest[u].rank) { posPoint->secondBest[u].rank=w; posPoint->secondBest[u].seat=RelativeSeat(firstSeat,3-s); } } t=rho(firstSeat); if (nodeTypeStore[posPoint->stack[depth-1].first]==MAXNODE) { /* First seat of next trick is winner of the current trick */ posPoint->tricksMAX--; } } else { t=RelativeSeat(firstSeat,posPoint->seatRelFirst); r=movePly[depth].current; u=movePly[depth].move[r].suit; w=movePly[depth].move[r].rank; } posPoint->diagram.cards[t][u] |= BitRank(w); posPoint->length[t][u]++; return; } struct evalType Evaluate(const struct pos * posPoint) { int s, smax=0, k, firstSeat, count; unsigned short int max; struct evalType eval; const ContractInfo contract = Globals.getContract(); firstSeat=posPoint->stack[0].first; for (s=0; s<=3; s++) { eval.winRanks[s]=0; } /* Who wins the last trick? */ if (contract.trumpContract) { /* Highest trump card wins */ max=0; count=0; for (s=0; s<=3; s++) { if (posPoint->diagram.cards[s][contract.trump]!=0) { count++; } if (posPoint->diagram.cards[s][contract.trump]>max) { smax=s; max=posPoint->diagram.cards[s][contract.trump]; } } if (max>0) { /* Trumpcard wins */ if (count>=2) { eval.winRanks[contract.trump]=max; } if (nodeTypeStore[smax]==MAXNODE) { goto maxexit; } else { goto minexit; } } } /* Who has the highest card in the suit played by 1st seat? */ k=0; while (k<=3) { /* Find the card the 1st seat played */ if (posPoint->diagram.cards[firstSeat][k]!=0) { /* Is this the card? */ break; } k++; } count=0; max=0; for (s=0; s<=3; s++) { if (posPoint->diagram.cards[s][k]!=0) { count++; } if (posPoint->diagram.cards[s][k]>max) { smax=s; max=posPoint->diagram.cards[s][k]; } } if (count>=2) { eval.winRanks[k]=max; } if (nodeTypeStore[smax]==MAXNODE) { goto maxexit; } else { goto minexit; } maxexit: eval.tricks=posPoint->tricksMAX+1; return eval; minexit: eval.tricks=posPoint->tricksMAX; return eval; } void UpdateWinner(struct pos * posPoint, int suit) { int k, h, hmax=0; unsigned short int sb, sbmax; posPoint->winner[suit]=posPoint->secondBest[suit]; sbmax=0; for (h=0; h<=3; h++) { sb=posPoint->diagram.cards[h][suit] & (~BitRank(posPoint->winner[suit].rank)); if (sb>sbmax) { hmax=h; sbmax=sb; } } k=getHighestRank(sbmax); if (k!=0) { posPoint->secondBest[suit].seat=hmax; posPoint->secondBest[suit].rank=k; } else { posPoint->secondBest[suit].seat=-1; posPoint->secondBest[suit].rank=0; } return; } void UpdateSecondBest(struct pos * posPoint, int suit) { int k, h, hmax=0; unsigned short int sb, sbmax; sbmax=0; for (h=0; h<=3; h++) { sb=posPoint->diagram.cards[h][suit] & (~BitRank(posPoint->winner[suit].rank)); if (sb>sbmax) { hmax=h; sbmax=sb; } } k=getHighestRank(sbmax); if (k!=0) { posPoint->secondBest[suit].seat=hmax; posPoint->secondBest[suit].rank=k; } else { posPoint->secondBest[suit].seat=-1; posPoint->secondBest[suit].rank=0; } return; } /* void UpdateWinner(struct pos * posPoint, int suit) { int k; int h, hmax=0, flag; posPoint->winner[suit]=posPoint->secondBest[suit]; k=posPoint->secondBest[suit].rank-1; while (k>=2) { flag=TRUE; for (h=0; h<=3; h++) if ((posPoint->diagram.cards[h][suit] & BitRank(k)) != 0) { hmax=h; flag=FALSE; break; } if (flag) { k--; } else { break; } } if (k<2) { posPoint->secondBest[suit].rank=0; posPoint->secondBest[suit].seat=0; } else { posPoint->secondBest[suit].rank=k; posPoint->secondBest[suit].seat=hmax; } return; } void UpdateSecondBest(struct pos * posPoint, int suit) { int k; int h, hmax=0, flag; k=posPoint->secondBest[suit].rank-1; while (k>=2) { flag=TRUE; for (h=0; h<=3; h++) { if ((posPoint->diagram.cards[h][suit] & BitRank(k)) != 0) { hmax=h; flag=FALSE; break; } } if (flag) { k--; } else { break; } } if (k<2) { posPoint->secondBest[suit].rank=0; posPoint->secondBest[suit].seat=0; } else { posPoint->secondBest[suit].rank=k; posPoint->secondBest[suit].seat=hmax; } return; } */ int QuickTricks(struct pos * posPoint, const int seat, const int depth, const int target, int *result) { holding_t ranks; int suit, sum, qtricks, commPartner, commRank=0, commSuit=-1, found=FALSE; int opps; int countLho, countRho, countPart, countOwn, lhoTrumpRanks=0, rhoTrumpRanks=0; int cutoff, k, lowestQtricks=0, count=0; const ContractInfo contract = Globals.getContract(); *result=TRUE; qtricks=0; for (suit=0; suit<=3; suit++) { posPoint->stack[depth].winRanks[suit]=0; } if ((depth<=0)||(depth==iniDepth)) { *result=FALSE; return qtricks; } if (nodeTypeStore[seat]==MAXNODE) { cutoff=target-posPoint->tricksMAX; } else { cutoff=posPoint->tricksMAX-target+(depth>>2)+2; } commPartner=FALSE; for (suit=0; suit<=3; suit++) { if (contract.notTrumpWithTrump(suit)) { /* Trump contract, suit is not trump */ if (posPoint->winner[suit].seat==partner(seat)) { /* Partner has winning card */ if (posPoint->diagram.cards[seat][suit]!=0) { /* Own seat has card in suit */ if (((posPoint->diagram.cards[lho(seat)][suit]!=0) || /* LHO not void */ (posPoint->diagram.cards[lho(seat)][contract.trump]==0)) /* LHO has no trump */ && ((posPoint->diagram.cards[rho(seat)][suit]!=0) || /* RHO not void */ (posPoint->diagram.cards[rho(seat)][contract.trump]==0))) { /* RHO has no trump */ commPartner=TRUE; commSuit=suit; commRank=posPoint->winner[suit].rank; break; } } } else if (posPoint->secondBest[suit].seat==partner(seat)) { if ((posPoint->winner[suit].seat==seat)&& (posPoint->length[seat][suit]>=2)&&(posPoint->length[partner(seat)][suit]>=2)) { if (((posPoint->diagram.cards[lho(seat)][suit]!=0) || (posPoint->diagram.cards[lho(seat)][contract.trump]==0)) && ((posPoint->diagram.cards[rho(seat)][suit]!=0) || (posPoint->diagram.cards[rho(seat)][contract.trump]==0))) { commPartner=TRUE; commSuit=suit; commRank=posPoint->secondBest[suit].rank; break; } } } } else if (!contract.trumpContract) { if (posPoint->winner[suit].seat==partner(seat)) { /* Partner has winning card */ if (posPoint->diagram.cards[seat][suit]!=0) { /* Own seat has card in suit */ commPartner=TRUE; commSuit=suit; commRank=posPoint->winner[suit].rank; break; } } else if (posPoint->secondBest[suit].seat==partner(seat)) { if ((posPoint->winner[suit].seat==seat)&& (posPoint->length[seat][suit]>=2)&&(posPoint->length[partner(seat)][suit]>=2)) { commPartner=TRUE; commSuit=suit; commRank=posPoint->secondBest[suit].rank; break; } } } } //int s; if (contract.trumpContract && (!commPartner) && (posPoint->diagram.cards[seat][contract.trump]!=0) && (posPoint->winner[contract.trump].seat==partner(seat))) { commPartner=TRUE; commSuit=contract.trump; commRank=posPoint->winner[contract.trump].rank; } if (contract.trumpContract) { lhoTrumpRanks=posPoint->length[lho(seat)][contract.trump]; rhoTrumpRanks=posPoint->length[rho(seat)][contract.trump]; } for (suit=contract.firstSuit(); suit<4; suit=contract.nextSuit(suit)) { countOwn=posPoint->length[seat][suit]; countLho=posPoint->length[lho(seat)][suit]; countRho=posPoint->length[rho(seat)][suit]; countPart=posPoint->length[partner(seat)][suit]; opps=countLho | countRho; if (!opps && (countPart==0)) { if (countOwn==0) { continue; } if (contract.notTrumpWithTrump(suit)) { if ((lhoTrumpRanks==0) && /* LHO has no trump */ (rhoTrumpRanks==0)) { /* RHO has no trump */ qtricks=qtricks+countOwn; if (qtricks>=cutoff) { return qtricks; } continue; } else { continue; } } else { qtricks=qtricks+countOwn; if (qtricks>=cutoff) { return qtricks; } continue; } } else { if (!opps && contract.isTrump(suit)) { sum=Max(countOwn, countPart); for (int suit2=0; suit2<=3; suit2++) { if ((sum>0)&&(suit2!=contract.trump)&&(countOwn>=countPart)&&(posPoint->length[seat][suit2]>0)&& (posPoint->length[partner(seat)][suit2]==0)) { sum++; break; } } if (sum>=cutoff) { return sum; } } else if (!opps) { sum=Min(countOwn,countPart); if (!contract.trumpContract) { if (sum>=cutoff) { return sum; } } else if ((suit!=contract.trump)&&(lhoTrumpRanks==0)&&(rhoTrumpRanks==0)) { if (sum>=cutoff) { return sum; } } } if (commPartner) { if (!opps && (countOwn==0)) { if (contract.notTrumpWithTrump(suit)) { if ((lhoTrumpRanks==0) && /* LHO has no trump */ (rhoTrumpRanks==0)) { /* RHO has no trump */ qtricks=qtricks+countPart; posPoint->stack[depth].winRanks[commSuit] |= BitRank(commRank); if (qtricks>=cutoff) { return qtricks; } continue; } else { continue; } } else { qtricks=qtricks+countPart; posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); if (qtricks>=cutoff) return qtricks; continue; } } else { if (!opps && contract.isTrump(suit)) { sum=Max(countOwn, countPart); for (int suit2=0; suit2<=3; suit2++) { if ((sum>0)&&(suit2!=contract.trump)&&(countOwn<=countPart)&&(posPoint->length[partner(seat)][suit2]>0)&& (posPoint->length[seat][suit2]==0)) { sum++; break; } } if (sum>=cutoff) { posPoint->stack[depth].winRanks[commSuit] |= BitRank(commRank); return sum; } } else if (!opps) { sum=Min(countOwn,countPart); if (!contract.trumpContract) { if (sum>=cutoff) return sum; } else if ((suit!=contract.trump)&&(lhoTrumpRanks==0)&&(rhoTrumpRanks==0)) { if (sum>=cutoff) return sum; } } } } } /* 08-01-30 */ if (posPoint->winner[suit].rank==0) { continue; } if (posPoint->winner[suit].seat==seat) { /* Winner found in own seat */ if (contract.notTrumpWithTrump(suit)) { if (((countLho!=0) || /* LHO not void */ (lhoTrumpRanks==0)) /* LHO has no trump */ && ((countRho!=0) || /* RHO not void */ (rhoTrumpRanks==0))) { /* RHO has no trump */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->winner[suit].rank); qtricks++; /* A trick can be taken */ /* 06-12-14 */ if (qtricks>=cutoff) return qtricks; if ((countLho<=1)&&(countRho<=1)&&(countPart<=1)&& (lhoTrumpRanks==0)&&(rhoTrumpRanks==0)) { qtricks=qtricks+countOwn-1; if (qtricks>=cutoff) { return qtricks; } continue; } } if (posPoint->secondBest[suit].seat==seat) { /* Second best found in own seat */ if ((lhoTrumpRanks==0)&& (rhoTrumpRanks==0)) { /* Opponents have no trump */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->secondBest[suit].rank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&(countPart<=2)) { qtricks=qtricks+countOwn-2; if (qtricks>=cutoff) return qtricks; continue; } } } else if ((posPoint->secondBest[suit].seat==partner(seat)) &&(countOwn>1)&&(countPart>1)) { /* Second best at partner and suit length of own seat and partner > 1 */ if ((lhoTrumpRanks==0)&& (rhoTrumpRanks==0)) { /* Opponents have no trump */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->secondBest[suit].rank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&((countPart<=2)||(countOwn<=2))) { /* 07-06-10 */ qtricks=qtricks+Max(countOwn-2, countPart-2); if (qtricks>=cutoff) { return qtricks; } continue; } } } } else { posPoint->stack[depth].winRanks[suit] |= BitRank(posPoint->winner[suit].rank); qtricks++; /* 06-12-14 */ if (qtricks>=cutoff) { return qtricks; } if ((countLho<=1)&&(countRho<=1)&&(countPart<=1)) { qtricks=qtricks+countOwn-1; if (qtricks>=cutoff) { return qtricks; } continue; } if (posPoint->secondBest[suit].seat==seat) { /* Second best found in own seat */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->secondBest[suit].rank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&(countPart<=2)) { qtricks=qtricks+countOwn-2; if (qtricks>=cutoff) { return qtricks; } continue; } } else if ((posPoint->secondBest[suit].seat==partner(seat)) &&(countOwn>1)&&(countPart>1)) { /* Second best at partner and suit length of own seat and partner > 1 */ posPoint->stack[depth].winRanks[suit] |= BitRank(posPoint->secondBest[suit].rank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&((countPart<=2)||(countOwn<=2))) { /* 07-06-10 */ qtricks=qtricks+Max(countOwn-2,countPart-2); if (qtricks>=cutoff) { return qtricks; } continue; } } } } else { /* It was not possible to take a quick trick by own winning card in the suit */ /* Partner winning card? */ if ((posPoint->winner[suit].seat==partner(seat))&&(countPart>0)) { /* Winner found at partner*/ if (commPartner) { /* There is communication with the partner */ if (contract.notTrumpWithTrump(suit)) { if (((countLho!=0) || /* LHO not void */ (lhoTrumpRanks==0)) /* LHO has no trump */ && ((countRho!=0) || /* RHO not void */ (rhoTrumpRanks==0))) /* RHO has no trump */ { posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->winner[suit].rank); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; /* A trick can be taken */ /* 06-12-14 */ if (qtricks>=cutoff) { return qtricks; } if ((countLho<=1)&&(countRho<=1)&&(countOwn<=1)&& (lhoTrumpRanks==0)&& (rhoTrumpRanks==0)) { qtricks=qtricks+countPart-1; continue; } } if (posPoint->secondBest[suit].seat==partner(seat)) { /* Second best found in partners seat */ if ((lhoTrumpRanks==0)&& (rhoTrumpRanks==0)) { /* Opponents have no trump */ posPoint->stack[depth].winRanks[suit] |= BitRank(posPoint->secondBest[suit].rank); posPoint->stack[depth].winRanks[commSuit] |= BitRank(commRank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&(countOwn<=2)) { continue; } } } else if ((posPoint->secondBest[suit].seat==seat)&& (countPart>1)&&(countOwn>1)) { /* Second best found in own seat and suit lengths of own seat and partner > 1*/ if ((lhoTrumpRanks==0)&& (rhoTrumpRanks==0)) { /* Opponents have no trump */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->secondBest[suit].rank); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; if ((countLho<=2)&&(countRho<=2)&& ((countOwn<=2)||(countPart<=2))) { /* 07-06-10 */ qtricks=qtricks+ Max(countPart-2,countOwn-2); if (qtricks>=cutoff) { return qtricks; } continue; } } } /* 06-08-24 */ else if ((suit==commSuit)&&(posPoint->secondBest[suit].seat ==lho(seat))&&((countLho>=2)||(lhoTrumpRanks==0))&& ((countRho>=2)||(rhoTrumpRanks==0))) { ranks=0; for (k=0; k<=3; k++) ranks=ranks | posPoint->diagram.cards[k][suit]; for (rr=posPoint->secondBest[suit].rank-1; rr>=2; rr--) { /* 3rd best at partner? */ if ((ranks & BitRank(rr))!=0) { if ((posPoint->diagram.cards[partner(seat)][suit] & BitRank(rr))!=0) { found=TRUE; break; } else { found=FALSE; break; } } found=FALSE; } if (found) { posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(rr); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; if ((countOwn<=2)&&(countLho<=2)&&(countRho<=2)&& (lhoTrumpRanks==0)&&(rhoTrumpRanks==0)) qtricks=qtricks+countPart-2; } } } else { posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->winner[suit].rank); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; /* 06-12-14 */ if (qtricks>=cutoff) { return qtricks; } if ((countLho<=1)&&(countRho<=1)&&(countOwn<=1)) { qtricks=qtricks+countPart-1; if (qtricks>=cutoff) { return qtricks; } continue; } if ((posPoint->secondBest[suit].seat==partner(seat))&&(countPart>0)) { /* Second best found in partners seat */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->secondBest[suit].rank); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&(countOwn<=2)) { qtricks=qtricks+countPart-2; if (qtricks>=cutoff) return qtricks; continue; } } /* 06-08-19 */ else if ((posPoint->secondBest[suit].seat==seat) &&(countPart>1)&&(countOwn>1)) { /* Second best found in own seat and own and partner's suit length > 1 */ posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(posPoint->secondBest[suit].rank); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; if ((countLho<=2)&&(countRho<=2)&&((countOwn<=2)||(countPart<=2))) { /* 07-06-10 */ qtricks=qtricks+Max(countPart-2,countOwn-2); if (qtricks>=cutoff) { return qtricks; } continue; } } /* 06-08-24 */ else if ((suit==commSuit)&&(posPoint->secondBest[suit].seat ==lho(seat))) { ranks=0; for (k=0; k<=3; k++) ranks=ranks | posPoint->diagram.cards[k][suit]; for (rr=posPoint->secondBest[suit].rank-1; rr>=2; rr--) { /* 3rd best at partner? */ if ((ranks & BitRank(rr))!=0) { if ((posPoint->diagram.cards[partner(seat)][suit] & BitRank(rr))!=0) { found=TRUE; break; } else { found=FALSE; break; } } found=FALSE; } if (found) { posPoint->stack[depth].winRanks[suit]=posPoint->stack[depth].winRanks[suit] | BitRank(rr); posPoint->stack[depth].winRanks[commSuit]=posPoint->stack[depth].winRanks[commSuit] | BitRank(commRank); qtricks++; if ((countOwn<=2)&&(countLho<=2)&&(countRho<=2)) { qtricks=qtricks+countPart-2; } } } } } } } if (contract.notTrumpWithTrump(suit) &&(countOwn>0)&&(lowestQtricks==0)&& ((qtricks==0)||((posPoint->winner[suit].seat!=seat)&& (posPoint->winner[suit].seat!=partner(seat))&& (posPoint->winner[contract.trump].seat!=seat)&& (posPoint->winner[contract.trump].seat!=partner(seat))))) { if ((countPart==0)&&(posPoint->length[partner(seat)][contract.trump]>0)) { if (((countRho>0)||(posPoint->length[rho(seat)][contract.trump]==0))&& ((countLho>0)||(posPoint->length[lho(seat)][contract.trump]==0))) { lowestQtricks=1; if (1>=cutoff) { return 1; } continue; } else if ((countRho==0)&&(countLho==0)) { if ((posPoint->diagram.cards[lho(seat)][contract.trump] | posPoint->diagram.cards[rho(seat)][contract.trump]) < posPoint->diagram.cards[partner(seat)][contract.trump]) { lowestQtricks=1; rr=getHighestRank(posPoint->diagram.cards[partner(seat)][contract.trump]); if (rr!=0) { posPoint->stack[depth].winRanks[contract.trump]|=BitRank(rr); if (1>=cutoff) { return 1; } } } continue; } else if (countLho==0) { if (posPoint->diagram.cards[lho(seat)][contract.trump] < posPoint->diagram.cards[partner(seat)][contract.trump]) { lowestQtricks=1; for (rr=14; rr>=2; rr--) { if ((posPoint->diagram.cards[partner(seat)][contract.trump] & BitRank(rr))!=0) { posPoint->stack[depth].winRanks[contract.trump] |= BitRank(rr); break; } } if (1>=cutoff) { return 1; } } continue; } else if (countRho==0) { if (posPoint->diagram.cards[rho(seat)][contract.trump] < posPoint->diagram.cards[partner(seat)][contract.trump]) { lowestQtricks=1; for (rr=14; rr>=2; rr--) { if ((posPoint->diagram.cards[partner(seat)][contract.trump] & BitRank(rr))!=0) { posPoint->stack[depth].winRanks[contract.trump] |= BitRank(rr); break; } } if (1>=cutoff) { return 1; } } continue; } } } if (qtricks>=cutoff) { return qtricks; } } if (qtricks==0) { if ((!contract.trumpContract)||(posPoint->winner[contract.trump].rank==0)) { found=FALSE; for (ss=0; ss<=3; ss++) { if (posPoint->winner[ss].rank==0) continue; hh=posPoint->winner[ss].seat; if (nodeTypeStore[hh]==nodeTypeStore[seat]) { if (posPoint->length[seat][ss]>0) { found=TRUE; break; } } else if ((posPoint->length[partner(seat)][ss]>0)&& (posPoint->length[seat][ss]>0)&& (posPoint->length[partner(hh)][ss]>0)) { count++; } } if (!found) { if (nodeTypeStore[seat]==MAXNODE) { if ((posPoint->tricksMAX+(depth>>2)-Max(0,count-1))length[seat][ss]>0) &&(nodeTypeStore[posPoint->winner[ss].seat]==MINNODE)) posPoint->stack[depth].winRanks[ss]= BitRank(posPoint->winner[ss].rank); else posPoint->stack[depth].winRanks[ss]=0; } return 0; } } else { if ((posPoint->tricksMAX+1+Max(0,count-1))>=target) { for (ss=0; ss<=3; ss++) { if ((posPoint->length[seat][ss]>0) &&(nodeTypeStore[posPoint->winner[ss].seat]==MAXNODE)) posPoint->stack[depth].winRanks[ss]= BitRank(posPoint->winner[ss].rank); else posPoint->stack[depth].winRanks[ss]=0; } return 0; } } } } } *result=FALSE; return qtricks; } int LaterTricksMIN(struct pos *posPoint, const int seat, const int depth, const int target) { int hh, ss, sum=0; const ContractInfo contract = Globals.getContract(); if ((!contract.trumpContract)||(posPoint->winner[contract.trump].rank==0)) { for (ss=0; ss<=3; ss++) { hh=posPoint->winner[ss].seat; if (nodeTypeStore[hh]==MAXNODE) sum+=Max(posPoint->length[hh][ss], posPoint->length[partner(hh)][ss]); } if ((posPoint->tricksMAX+sum0)&&(depth>0)&&(depth!=iniDepth)) { if ((posPoint->tricksMAX+(depth>>2)winner[ss].seat]==MINNODE) posPoint->stack[depth].winRanks[ss]=BitRank(posPoint->winner[ss].rank); else posPoint->stack[depth].winRanks[ss]=0; } return FALSE; } } } else if (contract.trumpContract && (posPoint->winner[contract.trump].rank!=0) && (nodeTypeStore[posPoint->winner[contract.trump].seat]==MINNODE)) { if ((posPoint->length[seat][contract.trump]==0)&& (posPoint->length[partner(seat)][contract.trump]==0)) { if (((posPoint->tricksMAX+(depth>>2)+1- Max(posPoint->length[lho(seat)][contract.trump], posPoint->length[rho(seat)][contract.trump]))0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=0; } return FALSE; } } else if (((posPoint->tricksMAX+(depth>>2))0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->stack[depth].winRanks[ss]=0; posPoint->stack[depth].winRanks[contract.trump]= BitRank(posPoint->winner[contract.trump].rank); return FALSE; } else { hh=posPoint->secondBest[contract.trump].seat; if ((nodeTypeStore[hh]==MINNODE)&&(posPoint->secondBest[contract.trump].rank!=0)) { if (((posPoint->length[hh][contract.trump]>1) || (posPoint->length[partner(hh)][contract.trump]>1))&& ((posPoint->tricksMAX+(depth>>2)-1)0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->stack[depth].winRanks[ss]=0; posPoint->stack[depth].winRanks[contract.trump]= BitRank(posPoint->winner[contract.trump].rank) | BitRank(posPoint->secondBest[contract.trump].rank) ; return FALSE; } } } } else if (contract.trumpContract) { hh=posPoint->secondBest[contract.trump].seat; if ((nodeTypeStore[hh]==MINNODE)&& (posPoint->length[hh][contract.trump]>1)&& (posPoint->winner[contract.trump].seat==rho(hh)) &&(posPoint->secondBest[contract.trump].rank!=0)) { if (((posPoint->tricksMAX+(depth>>2))0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=0; } posPoint->stack[depth].winRanks[contract.trump]= BitRank(posPoint->secondBest[contract.trump].rank) ; return FALSE; } } } return TRUE; } int LaterTricksMAX(struct pos *posPoint, const int seat, const int depth, const int target) { int hh, ss, sum=0; const ContractInfo contract = Globals.getContract(); if ((!contract.trumpContract)||(posPoint->winner[contract.trump].rank==0)) { for (ss=0; ss<=3; ss++) { hh=posPoint->winner[ss].seat; if (nodeTypeStore[hh]==MINNODE) sum+=Max(posPoint->length[hh][ss], posPoint->length[partner(hh)][ss]); } if ((posPoint->tricksMAX+(depth>>2)+1-sum>=target)&& (sum>0)&&(depth>0)&&(depth!=iniDepth)) { if ((posPoint->tricksMAX+1>=target)) { for (ss=0; ss<=3; ss++) { if (nodeTypeStore[posPoint->winner[ss].seat]==MAXNODE) posPoint->stack[depth].winRanks[ss]=BitRank(posPoint->winner[ss].rank); else posPoint->stack[depth].winRanks[ss]=0; } return TRUE; } } } else if (contract.trumpContract && (posPoint->winner[contract.trump].rank!=0) && (nodeTypeStore[posPoint->winner[contract.trump].seat]==MAXNODE)) { if ((posPoint->length[seat][contract.trump]==0)&& (posPoint->length[partner(seat)][contract.trump]==0)) { if (((posPoint->tricksMAX+Max(posPoint->length[lho(seat)][contract.trump], posPoint->length[rho(seat)][contract.trump]))>=target) &&(depth>0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->stack[depth].winRanks[ss]=0; return TRUE; } } else if (((posPoint->tricksMAX+1)>=target) &&(depth>0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=0; } posPoint->stack[depth].winRanks[contract.trump] = BitRank(posPoint->winner[contract.trump].rank); return TRUE; } else { hh=posPoint->secondBest[contract.trump].seat; if ((nodeTypeStore[hh]==MAXNODE)&&(posPoint->secondBest[contract.trump].rank!=0)) { if (((posPoint->length[hh][contract.trump]>1) || (posPoint->length[partner(hh)][contract.trump]>1))&& ((posPoint->tricksMAX+2)>=target)&&(depth>0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=0; } posPoint->stack[depth].winRanks[contract.trump]= BitRank(posPoint->winner[contract.trump].rank) | BitRank(posPoint->secondBest[contract.trump].rank) ; return TRUE; } } } } else if (contract.trumpContract) { hh=posPoint->secondBest[contract.trump].seat; if ((nodeTypeStore[hh]==MAXNODE)&& (posPoint->length[hh][contract.trump]>1)&&(posPoint->winner[contract.trump].seat==rho(hh)) &&(posPoint->secondBest[contract.trump].rank!=0)) { if (((posPoint->tricksMAX+1)>=target)&&(depth>0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->stack[depth].winRanks[ss]=0; posPoint->stack[depth].winRanks[contract.trump]= BitRank(posPoint->secondBest[contract.trump].rank) ; return TRUE; } } /*found=FALSE; for (ss=0; ss<=3; ss++) { if ((ss!=contract.trump)&&(posPoint->winner[ss].rank!=0)) { hh=posPoint->winner[ss].seat; if ((nodeTypeStore[hh]==MINNODE)|| (posPoint->length[seat][ss]==0)|| (posPoint->length[partner(seat)][ss]==0)) { found=TRUE; break; } } } if (!found) { sum=Max(posPoint->length[seat][contract.trump], posPoint->length[partner(seat)][contract.trump]); if ((posPoint->tricksMAX+(depth>>2)+1-sum>=target)&& (depth>0)&&(depth!=iniDepth)) { if ((posPoint->tricksMAX+1>=target)&&(sum>0)) { for (ss=0; ss<=3; ss++) { if (ss!=contract.trump) { if (nodeTypeStore[posPoint->winner[ss].seat]==MAXNODE) posPoint->stack[depth].winRanks[ss]=BitRank(posPoint->winner[ss].rank); else posPoint->stack[depth].winRanks[ss]=0; } else posPoint->stack[depth].winRanks[ss]=0; } return TRUE; } } }*/ } return FALSE; } int recInd=0; int MoveGen(const struct pos * posPoint, const int depth) { int suit, k, m, n, r, s, t; int scount[4]; int WeightAlloc(const struct pos *, struct moveType * mp, int depth, int notVoidInSuit,int q, int first); for (k=0; k<4; k++) lowestWin[depth][k]=0; m=0; r=posPoint->seatRelFirst; const int first=posPoint->stack[depth].first; const int q=RelativeSeat(first,r); s=movePly[depth+r].current; /* Current move of first seat */ t=movePly[depth+r].move[s].suit; /* Suit played by first seat */ const holding_t ris = posPoint->diagram.cards[q][t]; if ((r!=0)&&(ris!=0)) { /* Not first seat and not void in suit */ holding_t sequences; holding_t unplayedCardsRank; holding_t allCards, bitRank; holding_t sequence = 0; unplayedCardsRank = unplayedFinder.getUnplayed(q,t, (holding_t)posPoint->removedRanks[t], sequences); allCards = unplayedCardsRank | sequences; while (allCards) { //cerr << Holding(allCards) << endl; bitRank = smallestRankInSuit(allCards); allCards ^= bitRank; if (unplayedCardsRank & bitRank) { movePly[depth].move[m].suit=t; movePly[depth].move[m].rank=InvBitMapRank(bitRank); movePly[depth].move[m].sequence= sequence; sequence = 0; m++; } else { sequence |= bitRank; } } if (m!=1) { for (k=0; k<=m-1; k++) { movePly[depth].move[k].weight=WeightAlloc(posPoint, &movePly[depth].move[k], depth, ris,q,first); } } movePly[depth].last=m-1; if (m!=1) InsertSort(m, depth); if (depth!=iniDepth) { return m; } else { m=AdjustMoveList(); return m; } } else { /* First seat or void in suit */ holding_t sequences; holding_t unplayedCardsRank; holding_t bitRank; holding_t allCards; holding_t sequence = 0; for (suit=0; suit<=3; suit++) { unplayedCardsRank = unplayedFinder.getUnplayed(q,suit, (holding_t)(posPoint->removedRanks[suit]), sequences); allCards = unplayedCardsRank | sequences; while (allCards) { //cerr << Holding(allCards) << endl; bitRank = smallestRankInSuit(allCards); allCards ^= bitRank; if (unplayedCardsRank & bitRank) { movePly[depth].move[m].suit=suit; movePly[depth].move[m].rank=InvBitMapRank(bitRank); movePly[depth].move[m].sequence=sequence; sequence = 0; m++; } else { sequence |= bitRank; } } } for (k=0; k<=m-1; k++) { movePly[depth].move[k].weight=WeightAlloc(posPoint, &movePly[depth].move[k], depth, ris,q,first); } movePly[depth].last=m-1; InsertSort(m, depth); if (r==0) { for (n=0; n<=3; n++) { scount[n]=0; } for (k=0; k<=m-1; k++) { if (scount[movePly[depth].move[k].suit]==1 /* 2 */) continue; else { movePly[depth].move[k].weight+=500; scount[movePly[depth].move[k].suit]++; } } InsertSort(m, depth); } else { for (n=0; n<=3; n++) { scount[n]=0; } for (k=0; k<=m-1; k++) { if (scount[movePly[depth].move[k].suit]==1) { continue; } else { movePly[depth].move[k].weight+=500; scount[movePly[depth].move[k].suit]++; } } InsertSort(m, depth); } if (depth!=iniDepth) { return m; } else { m=AdjustMoveList(); return m; } } } int WeightAlloc(const struct pos * posPoint, struct moveType * mp, const int depth, const int notVoidInSuit,const int q, const int first) { int weight=0, suitAdd=0, leadSuit; holding_t k,l,kk,ll; int suitWeightDelta; int suitBonus=0; int winMove=FALSE; unsigned short suitCount, suitCountLH, suitCountRH; int countLH, countRH; const ContractInfo contract = Globals.getContract(); const int suit=mp->suit; if ((!notVoidInSuit)||(posPoint->seatRelFirst==0)) { suitCount=posPoint->length[q][suit]; suitAdd=suitCount+suitCount; } switch (posPoint->seatRelFirst) { case 0: suitCountLH=posPoint->length[lho(q)][suit]; suitCountRH=posPoint->length[rho(q)][suit]; if (contract.notTrumpWithTrump(suit) && (((posPoint->diagram.cards[lho(q)][suit]==0) && (posPoint->diagram.cards[lho(q)][contract.trump]!=0)) || ((posPoint->diagram.cards[rho(q)][suit]==0) && (posPoint->diagram.cards[rho(q)][contract.trump]!=0)))) suitBonus=-12/*15*/; if (suitCountLH!=0) { countLH=(suitCountLH<<2); } else { countLH=depth+4; } if (suitCountRH!=0) { countRH=(suitCountRH<<2); } else { countRH=depth+4; } suitWeightDelta=suitBonus-((countLH+countRH)<<1); if (posPoint->winner[suit].rank==mp->rank) { if (contract.notTrumpWithTrump(suit)) { if ((posPoint->length[partner(first)][suit]!=0)|| (posPoint->length[partner(first)][contract.trump]==0)) { if (((posPoint->length[lho(first)][suit]!=0)|| (posPoint->length[lho(first)][contract.trump]==0))&& ((posPoint->length[rho(first)][suit]!=0)|| (posPoint->length[rho(first)][contract.trump]==0))) winMove=TRUE; } else if (((posPoint->length[lho(first)][suit]!=0)|| (posPoint->diagram.cards[partner(first)][contract.trump]> posPoint->diagram.cards[lho(first)][contract.trump]))&& ((posPoint->length[rho(first)][suit]!=0)|| (posPoint->diagram.cards[partner(first)][contract.trump]> posPoint->diagram.cards[rho(first)][contract.trump]))) winMove=TRUE; } else winMove=TRUE; } else if (posPoint->diagram.cards[partner(first)][suit] > (posPoint->diagram.cards[lho(first)][suit] | posPoint->diagram.cards[rho(first)][suit])) { if (contract.notTrumpWithTrump(suit)) { if (((posPoint->length[lho(first)][suit]!=0)|| (posPoint->length[lho(first)][contract.trump]==0))&& ((posPoint->length[rho(first)][suit]!=0)|| (posPoint->length[rho(first)][contract.trump]==0))) winMove=TRUE; } else winMove=TRUE; } else if (contract.notTrumpWithTrump(suit)) { if ((posPoint->length[partner(first)][suit]==0)&& (posPoint->length[partner(first)][contract.trump]!=0)) { if ((posPoint->length[lho(first)][suit]==0)&& (posPoint->length[lho(first)][contract.trump]!=0)&& (posPoint->length[rho(first)][suit]==0)&& (posPoint->length[rho(first)][contract.trump]!=0)) { if (posPoint->diagram.cards[partner(first)][contract.trump]> (posPoint->diagram.cards[lho(first)][contract.trump] | posPoint->diagram.cards[rho(first)][contract.trump])) winMove=TRUE; } else if ((posPoint->length[lho(first)][suit]==0)&& (posPoint->length[lho(first)][contract.trump]!=0)) { if (posPoint->diagram.cards[partner(first)][contract.trump] > posPoint->diagram.cards[lho(first)][contract.trump]) winMove=TRUE; } else if ((posPoint->length[rho(first)][suit]==0)&& (posPoint->length[rho(first)][contract.trump]!=0)) { if (posPoint->diagram.cards[partner(first)][contract.trump] > posPoint->diagram.cards[rho(first)][contract.trump]) winMove=TRUE; } else winMove=TRUE; } } if (winMove) { if (((posPoint->winner[suit].seat==lho(first))&&(suitCountLH==1)) ||((posPoint->winner[suit].seat==rho(first))&&(suitCountRH==1))) weight=suitWeightDelta+40-(mp->rank); else if (posPoint->winner[suit].seat==first) { if (posPoint->secondBest[suit].seat==partner(first)&& (posPoint->secondBest[suit].rank!=0)) { weight=suitWeightDelta+50-(mp->rank); } else if (posPoint->winner[suit].rank==mp->rank) { weight=suitWeightDelta+31; } else { weight=suitWeightDelta+19-(mp->rank); } } else if (posPoint->winner[suit].seat==partner(first)) { /* If partner has winning card */ if (posPoint->secondBest[suit].seat==first) weight=suitWeightDelta+50-(mp->rank); else weight=suitWeightDelta+35-(mp->rank); } else if ((mp->sequence)&& (mp->rank==posPoint->secondBest[suit].rank)) weight=suitWeightDelta+40/*35*/-(mp->rank); else weight=suitWeightDelta+30-(mp->rank); if ((bestMove[depth].suit==mp->suit)&& (bestMove[depth].rank==mp->rank)) weight+=50/*45*//*35*/; } else { if (((posPoint->winner[suit].seat==lho(first))&&(suitCountLH==1)) ||((posPoint->winner[suit].seat==rho(first))&&(suitCountRH==1))) weight=suitWeightDelta+20-(mp->rank); else if (posPoint->winner[suit].seat==first&& (posPoint->secondBest[suit].rank!=0)) { if (posPoint->secondBest[suit].seat==partner(first)) { weight=suitWeightDelta+35-(mp->rank); } else if (posPoint->winner[suit].rank==mp->rank) { weight=suitWeightDelta+16; } else { weight=suitWeightDelta+4-(mp->rank); } } else if (posPoint->winner[suit].seat==partner(first)) { /* If partner has winning card */ if (posPoint->secondBest[suit].seat==first) { weight=suitWeightDelta+35-(mp->rank); } else { weight=suitWeightDelta+20-(mp->rank); } } else if ((mp->sequence)&& (mp->rank==posPoint->secondBest[suit].rank)) weight=suitWeightDelta+20-(mp->rank); else weight=suitWeightDelta+4-(mp->rank); if ((bestMove[depth].suit==mp->suit)&& (bestMove[depth].rank==mp->rank)) weight+=30/*25*//*35*/; } break; case 1: leadSuit=posPoint->stack[depth+1].move.suit; if (leadSuit==suit) { if (BitRank(mp->rank)> (BitRank(posPoint->stack[depth+1].move.rank) | posPoint->diagram.cards[partner(first)][suit])) { if (contract.notTrumpWithTrump(suit)) { if ((posPoint->length[partner(first)][suit]!=0)|| (posPoint->length[partner(first)][contract.trump]==0)) winMove=TRUE; else if ((posPoint->length[rho(first)][suit]==0) &&(posPoint->length[rho(first)][contract.trump]!=0) &&(posPoint->diagram.cards[rho(first)][contract.trump]> posPoint->diagram.cards[partner(first)][contract.trump])) winMove=TRUE; } else winMove=TRUE; } else if (posPoint->diagram.cards[rho(first)][suit]> (BitRank(posPoint->stack[depth+1].move.rank) | posPoint->diagram.cards[partner(first)][suit])) { if (contract.notTrumpWithTrump(suit)) { if ((posPoint->length[partner(first)][suit]!=0)|| (posPoint->length[partner(first)][contract.trump]==0)) { winMove=TRUE; } } else winMove=TRUE; } else if (BitRank(posPoint->stack[depth+1].move.rank) > (posPoint->diagram.cards[rho(first)][suit] | posPoint->diagram.cards[partner(first)][suit] | BitRank(mp->rank))) { if (contract.notTrumpWithTrump(suit)) { if ((posPoint->length[rho(first)][suit]==0)&& (posPoint->length[rho(first)][contract.trump]!=0)) { if ((posPoint->length[partner(first)][suit]!=0)|| (posPoint->length[partner(first)][contract.trump]==0)) { winMove=TRUE; } else if (posPoint->diagram.cards[rho(first)][contract.trump] > posPoint->diagram.cards[partner(first)][contract.trump]) { winMove=TRUE; } } } } else { /* winnerSeat is partner to first */ if (contract.notTrumpWithTrump(suit)) { if ((posPoint->length[rho(first)][suit]==0)&& (posPoint->length[rho(first)][contract.trump]!=0)) winMove=TRUE; } } } else { /* Leading suit differs from suit played by LHO */ if (contract.isTrump(suit)) { if (posPoint->length[partner(first)][leadSuit]!=0) winMove=TRUE; else if (BitRank(mp->rank)> posPoint->diagram.cards[partner(first)][contract.trump]) winMove=TRUE; else if ((posPoint->length[rho(first)][leadSuit]==0) &&(posPoint->length[rho(first)][contract.trump]!=0)&& (posPoint->diagram.cards[rho(first)][contract.trump] > posPoint->diagram.cards[partner(first)][contract.trump])) winMove=TRUE; } else if (contract.notTrumpWithTrump(leadSuit)) { /* Neither suit nor leadSuit is trump */ if (posPoint->length[partner(first)][leadSuit]!=0) { if (posPoint->diagram.cards[rho(first)][leadSuit] > (posPoint->diagram.cards[partner(first)][leadSuit] | BitRank(posPoint->stack[depth+1].move.rank))) winMove=TRUE; else if ((posPoint->length[rho(first)][leadSuit]==0) &&(posPoint->length[rho(first)][contract.trump]!=0)) winMove=TRUE; } /* Partner to leading seat is void in leading suit */ else if ((posPoint->length[rho(first)][leadSuit]==0) &&(posPoint->diagram.cards[rho(first)][contract.trump]> posPoint->diagram.cards[partner(first)][contract.trump])) winMove=TRUE; else if ((posPoint->length[partner(first)][contract.trump]==0) &&(posPoint->diagram.cards[rho(first)][leadSuit] > BitRank(posPoint->stack[depth+1].move.rank))) winMove=TRUE; } else { /* Either no trumps or leadSuit is trump, side with highest rank in leadSuit wins */ if (posPoint->diagram.cards[rho(first)][leadSuit] > (posPoint->diagram.cards[partner(first)][leadSuit] | BitRank(posPoint->stack[depth+1].move.rank))) winMove=TRUE; } } kk=posPoint->diagram.cards[partner(first)][leadSuit]; ll=posPoint->diagram.cards[rho(first)][leadSuit]; k=kk & (-kk); l=ll & (-ll); /* Only least significant 1 bit */ if (winMove) { if (!notVoidInSuit) { if (contract.isTrump(suit)) { weight=30-(mp->rank)+suitAdd; } else { weight=60-(mp->rank)+suitAdd; /* Better discard than ruff since rho wins anyway */ } } else if (k > BitRank(mp->rank)) { weight=45-(mp->rank); /* If lowest card for partner to leading seat is higher than lho played card, playing as low as possible will give the cheapest win */ } else if ((ll > BitRank(posPoint->stack[depth+1].move.rank))&& (posPoint->diagram.cards[first][leadSuit] > ll)) { weight=60-(mp->rank); /* If rho has a card in the leading suit that is higher than the trick leading card but lower than the highest rank of the leading seat, then lho playing the lowest card will be the cheapest win */ } else if (mp->rank > posPoint->stack[depth+1].move.rank) { if (BitRank(mp->rank) < ll) weight=75-(mp->rank); /* If played card is lower than any of the cards of rho, it will be the cheapest win */ else if (BitRank(mp->rank) > kk) weight=70-(mp->rank); /* If played card is higher than any cards at partner of the leading seat, rho can play low, under the condition that he has a lower card than lho played */ else { if (mp->sequence) weight=60-(mp->rank); else weight=45-(mp->rank); } } else if (posPoint->length[rho(first)][leadSuit]>0) { if (mp->sequence) weight=50-(mp->rank); /* Plyiang a card in a sequence may promote a winner */ else weight=45-(mp->rank); } else weight=45-(mp->rank); } else { if (!notVoidInSuit) { if (contract.isTrump(suit)) { /*if (ll > BitRank(posPoint->stack[depth+1].move.rank)) weight=-10-(mp->rank)+suitAdd; else*/ weight=15-(mp->rank)+suitAdd; /* Ruffing is preferred, makes the trick costly for the opponents */ } else weight=-(mp->rank)+suitAdd; } else if ((k > BitRank(mp->rank))|| (l > BitRank(mp->rank))) weight=-(mp->rank); /* If lowest rank for either partner to leading seat or rho is higher than played card for lho, lho should play as low card as possible */ else if (mp->rank > posPoint->stack[depth+1].move.rank) { if (mp->sequence) weight=20-(mp->rank); else weight=10-(mp->rank); } else weight=-(mp->rank); } break; case 2: leadSuit=posPoint->stack[depth+2].move.suit; if (WinningMove(*mp, (posPoint->stack[depth+1].move))) { if (suit==leadSuit) { if (contract.notTrumpWithTrump(leadSuit)) { if (((posPoint->length[rho(first)][suit]!=0)|| (posPoint->length[rho(first)][contract.trump]==0))&& (BitRank(mp->rank) > posPoint->diagram.cards[rho(first)][suit])) winMove=TRUE; } else if (BitRank(mp->rank) > posPoint->diagram.cards[rho(first)][suit]) winMove=TRUE; } else { /* Suit is trump */ if (posPoint->length[rho(first)][leadSuit]==0) { if (BitRank(mp->rank) > posPoint->diagram.cards[rho(first)][contract.trump]) winMove=TRUE; } else winMove=TRUE; } } else if (posPoint->stack[depth+1].high==first) { if (posPoint->length[rho(first)][leadSuit]!=0) { if (posPoint->diagram.cards[rho(first)][leadSuit] < BitRank(posPoint->stack[depth+2].move.rank)) winMove=TRUE; } else if (!contract.trumpContract) { winMove=TRUE; } else if (contract.isTrump(leadSuit)) { winMove=TRUE; } else if (contract.notTrumpWithTrump(leadSuit) && (posPoint->length[rho(first)][contract.trump]==0)) { winMove=TRUE; } } if (winMove) { if (!notVoidInSuit) { if (posPoint->stack[depth+1].high==first) { if (contract.isTrump(suit)) { weight=30-(mp->rank)+suitAdd; /* Ruffs partner's winner */ } else { weight=60-(mp->rank)+suitAdd; } } else if (WinningMove(*mp, (posPoint->stack[depth+1].move))) { /* Own seat on top by ruffing */ weight=70-(mp->rank)+suitAdd; } else if (contract.isTrump(suit)) { /* Discard a trump but still losing */ weight=15-(mp->rank)+suitAdd; } else { weight=30-(mp->rank)+suitAdd; } } else { weight=60-(mp->rank); } } else { if (!notVoidInSuit) { if (WinningMove(*mp, (posPoint->stack[depth+1].move))) /* Own seat on top by ruffing */ weight=40-(mp->rank)+suitAdd; else if (contract.isTrump(suit)) { /* Discard a trump but still losing */ weight=-15-(mp->rank)+suitAdd; } else { weight=-(mp->rank)+suitAdd; } } else { if (WinningMove(*mp, (posPoint->stack[depth+1].move))) { if (mp->rank==posPoint->secondBest[leadSuit].rank) weight=25/*35*/; else if (mp->sequence) weight=20/*30*/-(mp->rank); else weight=10/*20*/-(mp->rank); } else weight=-10/*0*/-(mp->rank); } } break; case 3: if (!notVoidInSuit) { if ((posPoint->stack[depth+1].high)==lho(first)) { /* If the current winning move is given by the partner */ if (contract.isTrump(suit)) { /* Ruffing partners winner? */ weight=14-(mp->rank)+suitAdd; } else { weight=30-(mp->rank)+suitAdd; } } else if (WinningMove(*mp, posPoint->stack[depth+1].move)) { /* Own seat ruffs */ weight=30-(mp->rank)+suitAdd; } else if (suit==contract.trump) { weight=-(mp->rank); } else { weight=14-(mp->rank)+suitAdd; } } else if ((posPoint->stack[depth+1].high)==(lho(first))) { /* If the current winning move is given by the partner */ if (contract.isTrump(suit)) { /* Ruffs partners winner */ weight=24-(mp->rank); } else { weight=30-(mp->rank); } } else if (WinningMove(*mp, posPoint->stack[depth+1].move)) { /* If present move is superior to current winning move and the current winning move is not given by the partner */ weight=30-(mp->rank); } else { /* If present move is not superior to current winning move and the current winning move is not given by the partner */ if (contract.isTrump(suit)) { /* Ruffs but still loses */ weight=-(mp->rank); } else { weight=14-(mp->rank); } } } return weight; } /* Shell-1 */ /* K&R page 62: */ /*void shellSort(int n, int depth) { int gap, i, j; struct moveType temp; if (n==2) { if (movePly[depth].move[0].weight>1; gap>0; gap>>=1) for (i=gap; i=0 && movePly[depth].move[j].weight< movePly[depth].move[j+gap].weight; j-=gap) { temp=movePly[depth].move[j]; movePly[depth].move[j]=movePly[depth].move[j+gap]; movePly[depth].move[j+gap]=temp; } } */ /* Shell-2 */ /*void shellSort(int n, int depth) { int i, j, increment; struct moveType temp; if (n==2) { if (movePly[depth].move[0].weight 0) { for (i=0; i < n; i++) { j = i; temp = movePly[depth].move[i]; while ((j >= increment) && (movePly[depth].move[j-increment].weight < temp.weight)) { movePly[depth].move[j] = movePly[depth].move[j - increment]; j = j - increment; } movePly[depth].move[j] = temp; } if ((increment>>1) != 0) increment>>=1; else if (increment == 1) increment = 0; else increment = 1; } } */ /* Insert-1 */ void InsertSort(int n, int depth) { int i, j; struct moveType a, temp; if (n==2) { if (movePly[depth].move[0].weighta.weight) { temp=a; a=movePly[depth].move[i]; movePly[depth].move[i]=temp; } movePly[depth].move[0]=a; for (i=2; i<=n-1; i++) { j=i; a=movePly[depth].move[i]; while (a.weight>movePly[depth].move[j-1].weight) { movePly[depth].move[j]=movePly[depth].move[j-1]; j--; } movePly[depth].move[j]=a; } } /* Insert-2 */ /*void InsertSort(int n, int depth) { int i, j; struct moveType a; if (n==2) { if (movePly[depth].move[0].weight=0)&&(movePly[depth].move[i].weightlbound==-1) { /* This bound values for this leading seat has not yet been determined */ *result=FALSE; return nodep; } else if ((posPoint->tricksMAX + nodep->lbound)>=target) { *value=TRUE; *result=TRUE; return nodep; } else if ((posPoint->tricksMAX + nodep->ubound)ubound==-1) { /* This bound values for this leading seat has not yet been determined */ *result=FALSE; return nodep; } else if ((posPoint->tricksMAX + (tricks + 1 - nodep->ubound))>=target) { *value=TRUE; *result=TRUE; return nodep; } else if ((posPoint->tricksMAX + (tricks + 1 - nodep->lbound))lbound > nodep->lbound) || (nodep->lbound==-1)) nodep->lbound=posPoint->lbound; if ((posPoint->ubound < nodep->ubound) || (nodep->ubound==-1)) nodep->ubound=posPoint->ubound; nodep->bestMoveSuit=posPoint->bestMoveSuit; nodep->bestMoveRank=posPoint->bestMoveRank; return nodep; } struct nodeCardsType * FindSOP(struct pos * posPoint, struct winCardType * nodeP, int firstSeat, int target, int tricks, int * valp) { struct nodeCardsType * sopP; struct winCardType * np; int s; np=nodeP; s=0; while ((np!=NULL)&&(s<4)) { if ((np->winMask & posPoint->orderSet[s])== np->orderSet) { /* Winning rank set fits position */ if (s==3) { sopP=CheckSOP(posPoint, np->first, target, tricks, &res, &val); *valp=val; if (res) { return sopP; } else { if (np->next!=NULL) { np=np->next; } else { np=np->prevWin; s--; if (np==NULL) { return NULL; } while (np->next==NULL) { np=np->prevWin; s--; if (np==NULL) { /* Previous node is header node? */ return NULL; } } np=np->next; } } } else if (s<4) { np=np->nextWin; s++; } } else { if (np->next!=NULL) { np=np->next; } else { np=np->prevWin; s--; if (np==NULL) { return NULL; } while (np->next==NULL) { np=np->prevWin; s--; if (np==NULL) { /* Previous node is header node? */ return NULL; } } np=np->next; } } } return NULL; } struct nodeCardsType * BuildPath(struct pos * posPoint, struct posSearchType *nodep, int * result) { /* If result is TRUE, a new SOP has been created and BuildPath returns a pointer to it. If result is FALSE, an existing SOP is used and BuildPath returns a pointer to the SOP */ int found, suit; struct winCardType * np, * p2, * nprev, * fnp, *pnp; struct winCardType temp; struct nodeCardsType * sopP=0, * p; np=nodep->posSearchPoint; nprev=NULL; suit=0; /* If winning node has a card that equals the next winning card deduced from the position, then there already exists a (partial) path */ if (np==NULL) { /* There is no winning list created yet */ /* Create winning nodes */ p2=&winCards[winSetSize]; AddWinSet(); p2->next=NULL; p2->nextWin=NULL; p2->prevWin=NULL; nodep->posSearchPoint=p2; p2->winMask=posPoint->winMask[suit]; p2->orderSet=posPoint->winOrderSet[suit]; p2->first=NULL; np=p2; /* Latest winning node */ suit++; while (suit<4) { p2=&winCards[winSetSize]; AddWinSet(); np->nextWin=p2; p2->prevWin=np; p2->next=NULL; p2->nextWin=NULL; p2->winMask=posPoint->winMask[suit]; p2->orderSet=posPoint->winOrderSet[suit]; p2->first=NULL; np=p2; /* Latest winning node */ suit++; } p=&nodeCards[nodeSetSize]; AddNodeSet(); np->first=p; *result=TRUE; return p; } else { /* Winning list exists */ while (1) { /* Find all winning nodes that correspond to current position */ found=FALSE; while (1) { /* Find node amongst alternatives */ if ((np->winMask==posPoint->winMask[suit])&& (np->orderSet==posPoint->winOrderSet[suit])) { /* Part of path found */ found=TRUE; nprev=np; break; } if (np->next!=NULL) { np=np->next; } else { break; } } if (found) { suit++; if (suit>3) { sopP=UpdateSOP(posPoint, np->first); if (np->prevWin!=NULL) { pnp=np->prevWin; fnp=pnp->nextWin; } else { fnp=nodep->posSearchPoint; } temp.orderSet=np->orderSet; temp.winMask=np->winMask; temp.first=np->first; temp.nextWin=np->nextWin; np->orderSet=fnp->orderSet; np->winMask=fnp->winMask; np->first=fnp->first; np->nextWin=fnp->nextWin; fnp->orderSet=temp.orderSet; fnp->winMask=temp.winMask; fnp->first=temp.first; fnp->nextWin=temp.nextWin; *result=FALSE; return sopP; } else { np=np->nextWin; /* Find next winning node */ continue; } } else break; /* Node was not found */ } /* End outer while */ /* Create additional node, coupled to existing node(s) */ p2=&winCards[winSetSize]; AddWinSet(); /*np->next=p2;*/ p2->prevWin=nprev; if (nprev!=NULL) { p2->next=nprev->nextWin; nprev->nextWin=p2; } else { p2->next=nodep->posSearchPoint; nodep->posSearchPoint=p2; } p2->nextWin=NULL; /*p2->next=NULL;*/ p2->winMask=posPoint->winMask[suit]; p2->orderSet=posPoint->winOrderSet[suit]; p2->first=NULL; np=p2; /* Latest winning node */ suit++; /* Rest of path must be created */ while (suit<4) { p2=&winCards[winSetSize]; AddWinSet();/*winSetSize++;*/ np->nextWin=p2; p2->prevWin=np; p2->next=NULL; p2->winMask=posPoint->winMask[suit]; p2->orderSet=posPoint->winOrderSet[suit]; p2->first=NULL; p2->nextWin=NULL; np=p2; /* Latest winning node */ suit++; } /* All winning nodes for SOP have been traversed and new created */ p=&nodeCards[nodeSetSize]; AddNodeSet(); np->first=p; *result=TRUE; return p; } } struct posSearchType * SearchLenAndInsert(struct posSearchType * rootp, LONGLONG key, int insertNode, int *result) { /* Search for node which matches with the suit length combination given by parameter key. If no such node is found, NULL is returned if parameter insertNode is FALSE, otherwise a new node is inserted with suitLengths set to key, the pointer to this node is returned. The algorithm used is defined in Knuth "The art of computer programming", vol.3 "Sorting and searching", 6.2.2 Algorithm T, page 424. */ struct posSearchType *np, *p; np=rootp; while (1) { if (key==np->suitLengths) { *result=TRUE; return np; } else if (key < np->suitLengths) { if (np->left!=NULL) { np=np->left; } else if (insertNode) { p=&posSearch[lenSetSize]; AddLenSet();/*lenSetSize++;*/ np->left=p; p->posSearchPoint=NULL; p->suitLengths=key; p->left=NULL; p->right=NULL; *result=TRUE; return p; } else { *result=FALSE; return NULL; } } else { /* key > suitLengths */ if (np->right!=NULL) { np=np->right; } else if (insertNode) { p=&posSearch[lenSetSize]; AddLenSet();/*lenSetSize++;*/ np->right=p; p->posSearchPoint=NULL; p->suitLengths=key; p->left=NULL; p->right=NULL; *result=TRUE; return p; } else { *result=FALSE; return NULL; } } } } /* New algo */ void BuildSOP(struct pos * posPoint, int tricks, int firstSeat, int target, const int depth, int scoreFlag, int score) { int ss, res; holding_t w; struct nodeCardsType * cardsP; struct posSearchType * np; for (ss=0; ss<=3; ss++) { w=posPoint->stack[depth].winRanks[ss]; if (w==0) { posPoint->winMask[ss]=0; posPoint->winOrderSet[ss]=0; posPoint->leastWin[ss]=0; } else { posPoint->computeWinData(ss,w); } } /* 07-04-22 */ if (scoreFlag) { if (nodeTypeStore[0]==MAXNODE) { posPoint->ubound=tricks+1; posPoint->lbound=target-posPoint->tricksMAX; } else { posPoint->ubound=tricks+1-target+posPoint->tricksMAX; posPoint->lbound=0; } } else { if (nodeTypeStore[0]==MAXNODE) { posPoint->ubound=target-posPoint->tricksMAX-1; posPoint->lbound=0; } else { posPoint->ubound=tricks+1; posPoint->lbound=tricks+1-target+posPoint->tricksMAX+1; } } posPoint->getSuitLengths(suitLengths); np=SearchLenAndInsert(rootnp[tricks][firstSeat], suitLengths, TRUE, &res); cardsP=BuildPath(posPoint, np, &res); if (res) { cardsP->ubound=posPoint->ubound; cardsP->lbound=posPoint->lbound; if (((nodeTypeStore[firstSeat]==MAXNODE)&&(scoreFlag))|| ((nodeTypeStore[firstSeat]==MINNODE)&&(!scoreFlag))) { cardsP->bestMoveSuit=bestMove[depth].suit; cardsP->bestMoveRank=bestMove[depth].rank; } else { cardsP->bestMoveSuit=0; cardsP->bestMoveRank=0; } posPoint->bestMoveSuit=bestMove[depth].suit; posPoint->bestMoveRank=bestMove[depth].rank; for (ss=0; ss<=3; ss++) cardsP->leastWin[ss]=posPoint->leastWin[ss]; } #ifdef STAT c9[depth]++; #endif #ifdef TTDEBUG if ((res) && (ttCollect) && (!suppressTTlog)) { fprintf(fp7, "cardsP=%d\n", (int)cardsP); fprintf(fp7, "nodeSetSize=%d\n", nodeSetSize); fprintf(fp7, "ubound=%d\n", cardsP->ubound); fprintf(fp7, "lbound=%d\n", cardsP->lbound); fprintf(fp7, "target=%d\n", target); fprintf(fp7, "first=%c nextFirst=%c\n", cardSeat[posPoint->stack[depth].first], cardSeat[posPoint->stack[depth-1].first]); fprintf(fp7, "bestMove: suit=%c rank=%c\n", cardSuit[bestMove.suit], cardRank[bestMove[depth].rank]); fprintf(fp7, "\n"); fprintf(fp7, "Last trick:\n"); fprintf(fp7, "1st seat=%c\n", cardSeat[posPoint-]); for (k=3; k>=0; k--) { mcurrent=movePly[depth+k+1].current; fprintf(fp7, "suit=%c rank=%c\n", cardSuit[movePly[depth+k+1].move[mcurrent].suit], cardRank[movePly[depth+k+1].move[mcurrent].rank]); } fprintf(fp7, "\n"); for (hh=0; hh<=3; hh++) { fprintf(fp7, "seat=%c\n", cardSeat[hh]); for (ss=0; ss<=3; ss++) { fprintf(fp7, "suit=%c", cardSuit[ss]); for (rr=14; rr>=2; rr--) if (posPoint->diagram.cards[hh][ss] & BitRank(rr)) fprintf(fp7, " %c", cardRank[rr]); fprintf(fp7, "\n"); } fprintf(fp7, "\n"); } fprintf(fp7, "\n"); for (hh=0; hh<=3; hh++) { fprintf(fp7, "seat=%c\n", cardSeat[hh]); for (ss=0; ss<=3; ss++) { fprintf(fp7, "suit=%c", cardSuit[ss]); for (rr=1; rr<=13; rr++) if (posPoint->relRankInSuit[hh][ss] & BitRank(15-rr)) fprintf(fp7, " %c", cardRank[rr]); fprintf(fp7, "\n"); } fprintf(fp7, "\n"); } fprintf(fp7, "\n"); } #endif } int CheckDeal(struct moveType * cardp) { int h, s, k, found; holding_t temp[4][4]; for (h=0; h<=3; h++) { for (s=0; s<=3; s++) { temp[h][s]=game.diagram.cards[h][s]; } } /* Check that all ranks appear only once within the same suit. */ for (s=0; s<=3; s++) for (k=2; k<=14; k++) { found=FALSE; for (h=0; h<=3; h++) { if ((temp[h][s] & BitRank(k))!=0) { if (found) { cardp->suit=s; cardp->rank=k; return 1; } else found=TRUE; } } } return 0; } /* New algo */ /* void WinAdapt(struct pos * posPoint, const int depth, const struct nodeCardsType * cp, holding_t aggr[]) { posPoint->winAdapt(depth,cp,aggr); return; int ss, rr, k; for (ss=0; ss<=3; ss++) { posPoint->stack[depth].winRanks[ss]=0; if (cp->leastWin[ss]==0) continue; k=1; for (rr=14; rr>=2; rr--) { if ((aggr[ss] & BitRank(rr))!=0) { if (k<=cp->leastWin[ss]) { posPoint->stack[depth].winRanks[ss]|=BitRank(rr); k++; } else break; } } } return; } */ int NextMove(struct pos *posPoint, const int depth) { int mcurrent; holding_t lw; struct moveType currMove; mcurrent=movePly[depth].current; currMove=movePly[depth].move[mcurrent]; if (lowestWin[depth][currMove.suit]==0) { lw=posPoint->stack[depth].winRanks[currMove.suit]; if (lw!=0) { lw=smallestRankInSuit(lw); /* LSB */ } else { lw=BitRank(15); } if (BitRank(currMove.rank)= lowestWin[depth][movePly[depth].move[mcurrent].suit]) return TRUE; } return FALSE; } else { while (movePly[depth].current<=movePly[depth].last-1) { movePly[depth].current++; mcurrent=movePly[depth].current; suit=movePly[depth].move[mcurrent].suit; if ((currMove.suit==suit) || (BitRank(movePly[depth].move[mcurrent].rank) >= lowestWin[depth][suit])) return TRUE; } return FALSE; } /* else if (movePly[depth].current<=movePly[depth].last-1) { movePly[depth].current++; return TRUE; } else return FALSE; */ } else { while (movePly[depth].current<=movePly[depth].last-1) { movePly[depth].current++; mcurrent=movePly[depth].current; if (BitRank(movePly[depth].move[mcurrent].rank) >= lowestWin[depth][movePly[depth].move[mcurrent].suit]) return TRUE; } return FALSE; } } int DumpInput(int errCode, struct deal dl, int target, int solutions, int mode) { FILE *fp; int i, j, k; fp=fopen("dump.txt", "w"); if (fp==NULL) return -1; fprintf(fp, "Error code=%d\n", errCode); fprintf(fp, "\n"); fprintf(fp, "Deal data:\n"); fprintf(fp, "trump=%d\n", dl.trump); fprintf(fp, "first=%d\n", dl.trump); for (k=0; k<=2; k++) { fprintf(fp, "index=%d currentTrickSuit=%d currentTrickRank=%d\n", k, dl.currentTrickSuit[k], dl.currentTrickRank[k]); } for (i=0; i<=3; i++) { for (j=0; j<=3; j++) { fprintf(fp, "seat=%d suit=%d remaining=%d\n", i, j, dl.remaining.cards[i][j]); } } fprintf(fp, "\n"); fprintf(fp, "target=%d\n", target); fprintf(fp, "solutions=%d\n", solutions); fprintf(fp, "mode=%d\n", mode); fclose(fp); return 0; } void Wipe(void) { int k; for (k=1; k<=wcount; k++) { if (pw[k]) { free(pw[k]); } pw[k]=NULL; } for (k=1; k<=ncount; k++) { if (pn[k]) { free(pn[k]); } pn[k]=NULL; } for (k=1; k<=lcount; k++) { if (pl[k]) { free(pl[k]); } pl[k]=NULL; } allocmem=summem/*(WINIT+1)*sizeof(struct winCardType)+ (NINIT+1)*sizeof(struct nodeCardsType)+ (LINIT+1)*sizeof(struct posSearchType)*/; return; } void AddWinSet(void) { if (clearTTflag) { windex++; winSetSize=windex; /*fp2=fopen("dyn.txt", "a"); fprintf(fp2, "windex=%d\n", windex); fclose(fp2);*/ winCards=&temp_win[windex]; } else if (winSetSize>=winSetSizeLimit) { /* The memory chunk for the winCards structure will be exceeded. */ if ((allocmem+wmem)>maxmem) { /* Already allocated memory plus needed allocation overshot maxmem */ windex++; winSetSize=windex; clearTTflag=TRUE; winCards=&temp_win[windex]; } else { wcount++; winSetSizeLimit=WSIZE; pw[wcount] = (struct winCardType *)calloc(winSetSizeLimit+1, sizeof(struct winCardType)); if (pw[wcount]==NULL) { clearTTflag=TRUE; windex++; winSetSize=windex; winCards=&temp_win[windex]; } else { allocmem+=(winSetSizeLimit+1)*sizeof(struct winCardType); winSetSize=0; winCards=pw[wcount]; } } } else winSetSize++; return; } void AddNodeSet(void) { if (nodeSetSize>=nodeSetSizeLimit) { /* The memory chunk for the nodeCards structure will be exceeded. */ if ((allocmem+nmem)>maxmem) { /* Already allocated memory plus needed allocation overshot maxmem */ clearTTflag=TRUE; } else { ncount++; nodeSetSizeLimit=NSIZE; pn[ncount] = (struct nodeCardsType *)calloc(nodeSetSizeLimit+1, sizeof(struct nodeCardsType)); if (pn[ncount]==NULL) { clearTTflag=TRUE; } else { allocmem+=(nodeSetSizeLimit+1)*sizeof(struct nodeCardsType); nodeSetSize=0; nodeCards=pn[ncount]; } } } else nodeSetSize++; return; } void AddLenSet(void) { if (lenSetSize>=lenSetSizeLimit) { /* The memory chunk for the nodeCards structure will be exceeded. */ if ((allocmem+lmem)>maxmem) { /* Already allocated memory plus needed allocation overshot maxmem */ clearTTflag=TRUE; } else { lcount++; lenSetSizeLimit=LSIZE; pl[lcount] = (struct posSearchType *)calloc(lenSetSizeLimit+1, sizeof(struct posSearchType)); if (pl[lcount]==NULL) { clearTTflag=TRUE; } else { allocmem+=(lenSetSizeLimit+1)*sizeof(struct posSearchType); lenSetSize=0; posSearch=pl[lcount]; } } } else { lenSetSize++; } return; } #ifdef TTDEBUG void ReceiveTTstore(struct pos *posPoint, struct nodeCardsType * cardsP, int target, int depth) { /* Stores current position information and TT position value in table ttStore with current entry lastTTStore. Also stores corresponding information in log rectt.txt. */ tricksLeft=0; for (hh=0; hh<=3; hh++) for (ss=0; ss<=3; ss++) tricksLeft=tricksLeft+posPoint->length[hh][ss]; tricksLeft=tricksLeft/4; ttStore[lastTTstore].tricksLeft=tricksLeft; ttStore[lastTTstore].cardsP=cardsP; ttStore[lastTTstore].first=posPoint->stack[depth].first; if ((seatToPlay==posPoint->stack[depth].first)|| (seatToPlay==partner(posPoint->stack[depth].first))) { ttStore[lastTTstore].target=target-posPoint->tricksMAX; ttStore[lastTTstore].ubound=cardsP->ubound[seatToPlay]; ttStore[lastTTstore].lbound=cardsP->lbound[seatToPlay]; } else { ttStore[lastTTstore].target=tricksLeft- target+posPoint->tricksMAX+1; } for (hh=0; hh<=3; hh++) for (ss=0; ss<=3; ss++) ttStore[lastTTstore].suit[hh][ss]= posPoint->diagram.cards[hh][ss]; fp11=fopen("rectt.txt", "a"); if (lastTTstoretricksMAX); fprintf(fp11, "leftTricks=%d\n", ttStore[lastTTstore].tricksLeft); fprintf(fp11, "cardsP=%d\n", ttStore[lastTTstore].cardsP); fprintf(fp11, "ubound=%d\n", ttStore[lastTTstore].ubound); fprintf(fp11, "lbound=%d\n", ttStore[lastTTstore].lbound); fprintf(fp11, "first=%c\n", cardSeat[ttStore[lastTTstore].first]); fprintf(fp11, "target=%d\n", ttStore[lastTTstore].target); fprintf(fp11, "\n"); for (hh=0; hh<=3; hh++) { fprintf(fp11, "seat=%c\n", cardSeat[hh]); for (ss=0; ss<=3; ss++) { fprintf(fp11, "suit=%c", cardSuit[ss]); for (rr=14; rr>=2; rr--) if (ttStore[lastTTstore].suit[hh][ss] & BitRank(rr)) fprintf(fp11, " %c", cardRank[rr]); fprintf(fp11, "\n"); } fprintf(fp11, "\n"); } for (hh=0; hh<=3; hh++) { fprintf(fp11, "seat=%c\n", cardSeat[hh]); for (ss=0; ss<=3; ss++) { fprintf(fp11, "suit=%c", cardSuit[ss]); for (rr=1; rr<=13; rr++) if (posPoint->relRankInSuit[hh][ss] & BitRank(15-rr)) fprintf(fp11, " %c", cardRank[rr]); fprintf(fp11, "\n"); } fprintf(fp11, "\n"); } } fclose(fp11); lastTTstore++; } #endif deal319/CHANGES0000644000175200017520000001674511341325532011277 0ustar cbecbeChanges in Deal 3.1.9 * Fix issue #14 - smartstack was broken on OS X * Fix issue #15 - holding procedures implementation incomplete * Added documentation of pattern functions to advanced.html * Minor documentation fix Changes in Deal 3.1.8 * Added patternfunc, patternclass, and patterncond, which are similar in function to the shapefunc, shapeclass, and shapecond routines. [In Deal, a shape is the ordered list of suit lengths: s-h-d-c. A pattern is sorted by lengths (decreasing.) So the 3-4-5-1 shape has the pattern 5431. * Added documentation to commands-body.html for the new pattern procedures * Added google analytics code to the documentation (for my web site only - local documentation does not have the google analytics) * [Internals] Changed occurances of "hand" in variable names to "seat" when it refers to a location at the table (North, East, South, West.) Changes in Deal 3.1.7 * Added code to pass argument values (argc, argv, argv0) when using the '-x' flag * Added code to allow for easier build against Tcl 8.3. * Updated binky points with newly computed values. The new version does not have binky::defense.suit or binky::defense.nt. Added documentation for Binky Points evaluators. * Fixed 64-bit builds using a fix found in Christoph Berg's Ubuntu package for Deal. * Added another fix by Christoph Berg which improves random number seeding * Added Make.ubuntu and Make.mac-osx to source release build * Clarified some build and install notes * Fixed docs to use './deal' rather than 'deal' Changes in Deal 3.1.6 * Added newLTC function * Merged in changes with DDS 1.1.9 (about 5% performance increase in double dummy solving in tests of average deals) * Moderate changes in documentation * Moved the source code to a Google Code project, at http://andrews-deal.googlecode.com/ Changes in Deal 3.1.5 * Changed "stringbox" procedures to allow Unicode characters * Small changes to DDS to clarify code and very slightly improve performance (fixing a 'bug' that I had created which required holding_t type to be unsigned int rather that unsigned short * Allow fully played tricks to be passed with the -trick option to 'dds' command * Documentation for 'dds' -trick option * Reorganization of commands documentation file to create a non-framed version Changes in Deal 3.1.4 * Added -trick flag to dds * Allowed for inclusion of Tcl release libraries * Moved most of deal.tcl to lib/features.tcl Changes in Deal 3.1.3 * Fixed performance issue in DDS that I introduced in Deal 3.1.0. * Added -x command line flag Changes in Deal 3.1.2 * Added dds command for more control over the double dummy solver * Added 'universal' target to Makefile for building Mac universal binaries * Added tests for double-dummy solver, including Great 88 file * Performance tweaks to the double-dummy solver * Fixed a typo bug in deal.tcl * Added full_deal command * Added unicode output option for default format (to put out suit symbols) * Changed to allow "-" as void in inputs * Fixed seeding with seed_deal command * Updated documentation and built a documentation-management system Changes in Deal 3.1.1 * Implemented deal::tricks for caching of double dummy data and uniform interface to double dummy tricks data * Changed call to Haglund's solver to re-use data when processing contracts in the same denomination and different declarers. Changes in Deal 3.1 * Added Bo Haglund's Double Dummy Solver Changes in Deal 3.0.8 [ No binary changes ] * Fixed "line" input format * Updates documentation Changes in Deal 3.0.7 [ No binary changes - all changes in the Tcl files. ] * Changed "score" to be a table lookup. * Fixed a bug in "parscore" which wrong-sided the contract sometimes. * Fixed documentation file "commands.html". Changes in Deal 3.0.6 [ No binary changes this release - all changes in the Tcl files. ] * Made changes to gib.tcl to work with the latest version of GIB. * Fixed a few bugs with various formatting procedures. Changes in Deal 3.0.5 * Fixed a bug - Deal 3.0.4 failed to recognize "-" as void in -S, -E, -N, -W options, as well as in "north is " commands. ----- Changes in Deal 3.0.4 * Update doc examples to match ex/ subdirectory. * Deleted util.c and util.h from distribution. ----- Changes in Deal 3.0.3 * Added GNU General Public License copyright to most files, and full GPL text to release. * Altered deal.c to improve performance of reset_deal() routine. Improved overall performance of 10%. * Re-implemented in Tcl the broken undocumented old procedures, intersectclass, negateclass, and joinclass. This lets you create new shape classes from old shape classes using standard boolean functions. Old code removed from dist.c, new code added to deal.tcl . * Deleted some unused code in deal.tcl which was left from early efforts at the smart stacking routines. * Updated the documentation ----- Changes in Deal 3.0.2 * Fixed a bug in the smartstack methods. * Altered zip builds to put files in deal302 directory (rather than deal3.0.2) * Polished the HTML docs (in docs/html directory.) * Many, many improved error messages when commands are misused * Cleaned up some code * Made dist.c use more Tcl_Obj pointers rather than strings - makes for faster compiles of shape classes. (I can't believe I left those sprintf calls for so long. :-) * Fixed some of the examples which called deal::stack_hand, a non-existant procedure. ----- Changes in Deal 3.0.1 The changes for Deal 3.0.1 (from Deal 3.0 beta 11) were made essentially for two reasons: (1) To finish the Deal 3.0 release - e.g., added documentation. (2) To add features needed for the "smartstack" routines. * Include HTML docs in docs/html directory. * Most library files in release moved to the lib directory * Added "smartstack" input class for fast building of hands which fit specific patterns * Added "stacked" procedure to find out the current state of the deck-stacking. Returns the list of cards stacked to the named hand. * Altered stacking methods. Added procedures "deck_stack_cards," "deck_stack_hand", "stack_cards," and "stack_hand." By default, "stack_hand" and "stack_cards" just call the "deck_" procedures, but the idea is that "stack_cards" and "stack_hands" can be overridden. Now when you call "south is AJ4 KJ54 9643 72" it in turn calls "stack_hand south AJ4 KJ54 9643 72." Similarly, "south gets ..." calls "stack_cards," although there the transformation is somewhat different. * Added "list" subcommand to shape classes. e.g., shapeclass hasVoid { expr {$s*$h*$d*$c==0} } foreach shape [hasVoid list] { ... } * Added "shape" subcommand to the shape classes and functions, e.g., shapefunc foo { ... } foo shape {4 2 4 3} So: foo north Is the same as: foo shape [north shape] * Added the "holding" utility procedure, with subcommands length, disjoint, ... holding length AKxxx => 5 holding disjoint AKJ4 QT94 => 0 [ false ] New to Deal 3.0: * Fast holding procedures definable with holdingProc. * GIB interfaces (gib::directory, gib::tricks, parscore) * Bridge utility routines - lho, rho, partner, score * Input format extensibility * Uses features of faster versions of Tcl (Tcl 8.x) deal319/tcl_incl.h0000644000175200017520000000462211337642707012246 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TCL_INCL__ #include #ifndef CONST84 #define CONST84 #endif #ifdef __STDC__ #define TCL_PARAMS ClientData cd,Tcl_Interp *interp,int argc, CONST84 char *argv[] #define TCLOBJ_PARAMS ClientData cd,Tcl_Interp *interp,int objc,Tcl_Obj * CONST objv[] #define TCL_DECL #define TCLOBJ_DECL #else #define TCL_PARAMS cd,interp,argc,argv #define TCLOBJ_PARAMS cd,interp,objc,objv #define TCL_DECL ClientData cd; Tcl_Interp *interp; int argc; char *argv[]; #define TCLOBJ_DECL ClientData cd; Tcl_Interp *interp; int objc; Tcl_Obj * CONST objv[]; /*int free();*/ #endif #define USAGE(s) argv[0]," usage:\n\t",argv[0]," ",s #define OBJUSAGE(s) Tcl_GetString(objv[0])," usage:\n\t",Tcl_GetString(objv[0])," ",s #define AUnixError \ Tcl_AppendResult(interp,argv[0]," failed due to error: ",\ Tcl_PosixError(interp),NULL); return TCL_ERROR; /* #define MyAlloc(string,bytes) (string)=(char *)Tcl_Alloc(bytes) */ #define tcl_error(interp) \ fprintf(stderr,"Tcl stack dump of error info:\n"); \ fprintf(stderr,"%s\n",Tcl_GetVar2(interp,"errorInfo",NULL,0)); \ exit(1); void Tcl_AllocDelete _ANSI_ARGS_((ClientData data)); void Tcl_ObjDelete _ANSI_ARGS_((ClientData data)); #ifdef _WINDOWS #define DEAL31_API __declspec(dllexport) #else #define DEAL31_API #endif #if (TCL_MAJOR_VERSION<8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION==0)) static int __dummyLength; #define Tcl_GetString(obj) Tcl_GetStringFromObj(obj,&__dummyLength) #endif #if (TCL_MINOR_VERSION==0) int My_EvalObjv _ANSI_ARGS_((Tcl_Interp *,int,Tcl_Obj **,int)); #define Tcl_EvalObjv(interp,objc,objv,dummy) My_EvalObjv(interp,objc,objv,dummy) #endif #define __TCL_INCL__ #endif deal319/input/0000755000175200017520000000000011341064053011424 5ustar cbecbedeal319/input/giblib.tcl0000644000175200017520000001114011063454127013363 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: giblib.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/gib.tcl # # The giblib implements the ability to read files of the # format of Matt Ginsberg's 'library.dat' file. The file contains # deals along with the double dummy results of all possible contracts # played from all directions. # # The date file is the "binary" file described at the bottom # http://www.cirl.uoregon.edu/ginsberg/gibresearch.html . # namespace eval giblib { ::deal::nostacking variable file "library.dat" variable trial 0 variable filehandle {} proc readNextData {} { variable filehandle set haveRead 0 set data "" while {$haveRead<26} { if {[eof $filehandle]} { return "" } append data [read $filehandle [expr 26-$haveRead]] set haveRead [string length $data] } return $data } set who(00) west set who(01) north set who(10) east set who(11) south set binary(0000) 0 set binary(0001) 1 set binary(0010) 2 set binary(0011) 3 set binary(0100) 4 set binary(0101) 5 set binary(0110) 6 set binary(0111) 7 set binary(1000) 8 set binary(1001) 9 set binary(1010) 10 set binary(1011) 11 set binary(1100) 12 set binary(1101) 13 set binary(1110) 14 set binary(1111) 15 variable cardNames [list A K Q J T 9 8 7 6 5 4 3 2] variable trial 1 variable deal variable suitOrder [list spades hearts diamonds clubs] proc parseData {data} { set count [binary scan $data "B32B32B32B32SSSSS" \ cards(spades) cards(hearts) cards(diamonds) cards(clubs) \ tricks(notrump) tricks(spades) tricks(hearts) tricks(diamonds) tricks(clubs) ] set suitno 0 variable cardNames variable who variable suitOrder set decoded [list] foreach hand {north east south west} { foreach suit $suitOrder { set holding($hand-$suit) "" } } foreach suit $suitOrder { binary scan $cards($suit) a6a2a2a2a2a2a2a2a2a2a2a2a2a2 dummy c(2) c(3) c(4) c(5) \ c(6) c(7) c(8) c(9) c(T) c(J) c(Q) c(K) c(A) foreach card $cardNames { set whom $who($c($card)) append holding($whom-$suit) $card } } reset_deck foreach hand {north east south west} { deck_stack_hand $hand $holding($hand-spades) $holding($hand-hearts) \ $holding($hand-diamonds) $holding($hand-clubs) } set ddresults [list] foreach contract "notrump $suitOrder" { # trick to turning small into unsigned int set trickvalue [expr {( $tricks($contract) + 0x10000 ) % 0x10000} ] set results [list $contract] foreach hand {south west north east} { set tr [expr {15&$trickvalue}] ::deal::metadata tricks.$hand.$contract { gib::rectify_tricks $hand $tr } set trickvalue [expr {$trickvalue/16}] } } } proc openlib {} { variable file set fh [open $file r] fconfigure $fh -translation binary return $fh } proc initialize {{filename unset}} { variable filehandle variable trial if {"$filehandle"!=""} { finalize } if {"$filename"!="unset"} { variable file set file $filename } set filehandle [openlib] set trial 0 } proc get_next_deal {} { variable trial set data [readNextData] if {[string length $data]!=26} { return 0 } parseData $data incr trial } proc finalize {} { variable filehandle if {"$filehandle"!=""} { close $filehandle set filehandle {} } } proc stackhand {name hand} { error "Can't stack hands when reading deals from files" } proc stackcards {name args} { error "Can't stack cards when reading deals from files" } namespace export get_next_deal initialize finalize proc set_input {{filename {}}} { variable file if {$filename==""} { set filename $file } initialize $filename deal_reset_cmds ::giblib::next } proc next {} { deal_reset_cmds ::giblib::next if {[catch {giblib::get_next_deal}]} { # All done return -code return } } } deal319/input/ddline.tcl0000644000175200017520000000406111063454127013376 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: ddline.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # namespace eval ddline { variable glob ::deal::nostacking proc set_input {{fname {}} {skip 0} {suitorder {spades hearts diamonds clubs}}} { variable glob if {$fname!=""} { set glob(filehandle) [open $fname r] } else { set glob(filehandle) stdin } while {$skip>0} { incr skip -1 gets $glob(filehandle) line } set glob(suitorder) $suitorder lappend glob(suitorder) notrump deal_reset_cmds ::ddline::next } proc next {} { deal_reset_cmds ::ddline::next if {[catch {::ddline::nextline}]} { return -code return } } proc nextline {} { variable glob set length -1 catch { set length [gets $glob(filehandle) line] } reset_deck if {$length<=0} { return -code return } foreach pname {north east south west ddnorth ddeast ddsouth ddwest} val [split $line "|"] { set part($pname) $val } foreach hand {north east south west} { set h [split $part($hand) "."] foreach suit $glob(suitorder) \ tricks $part(dd$hand) \ holding $h { set holdings($suit) $holding ::deal::metadata ddline.$hand.$suit {expr $tricks} } deck_stack_hand $hand [list $holdings(spades) $holdings(hearts) $holdings(diamonds) $holdings(clubs)] } } } set deal::tricksCache ddline deal319/input/symmetric.tcl0000644000175200017520000000467111063454127014162 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: symmetric.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # read the output from a line input # # This reads input in the same format as the -l output from deal. # namespace eval symmetric { ::deal::nostacking variable number 0 variable current 0 variable increment 1 variable endnumber variable cards {K Q J T 9 8 7 6 5 4 3 2} proc finalize {} { } proc initialize {start incr end} { variable number variable increment variable endnumber set number $start set increment $incr set endnumber $end deal_reset_cmds {::symmetric::next} } proc generate {num} { variable current variable cards reset_deck set holding(0) "A" set holding(1) "" set holding(2) "" set holding(3) "" set current $num foreach card $cards { set suit [expr {$num%4}] append holding($suit) $card set num [expr {($num-$suit)/4}] } deck_stack_hand south $holding(0) $holding(1) $holding(2) $holding(3) deck_stack_hand west $holding(1) $holding(2) $holding(3) $holding(0) deck_stack_hand north $holding(2) $holding(3) $holding(0) $holding(1) deck_stack_hand east $holding(3) $holding(0) $holding(1) $holding(2) deal_deck } proc next {} { variable number variable increment variable endnumber if {$number>=$endnumber} { return -code return } generate $number incr number $increment deal_reset_cmds {::symmetric::next} } proc set_input {{start 0} {increment 1} {end 16777216}} { initialize $start $increment $end } } deal319/input/line.tcl0000644000175200017520000000346311101413557013066 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: line.tcl 278 2008-10-27 19:33:03Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # read the output from a line input # # This reads input in the same format as the -l output from deal. # namespace eval line { ::deal::nostacking variable handle stdin proc finalize {} { variable handle close $handle } proc initialize {args} { variable handle if {"$handle"!="stdin"} { finalize } if {[llength $args]>0} { set file [lindex $args 0] set handle [open $file "r"] } } proc next {} { variable handle set length -1 catch { set length [gets $handle line] } reset_deck if {$length<=0} { catch { finalize } # Return "return" code, indicating we're done - no more dealing. return -code return } set hands [split $line "|"] foreach hand {north east south west} val [split $line "|"] { deck_stack_hand $hand [split $val " "] } deal_reset_cmds {::line::next} } proc set_input {{file {}}} { if {$file==""} { initialize } else { initialize $file } deal_reset_cmds {::line::next} } } deal319/input/test.tcl0000644000175200017520000000003311341055333013104 0ustar cbecbesource lib/handFactory.tcl deal319/input/smartstack.tcl0000644000175200017520000000747211341064053014316 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: smartstack.tcl 324 2010-02-23 23:43:39Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # source lib/handFactory.tcl namespace eval smartstack { variable info proc set_input {hand shapeclass {valuation zero} {min 0} args} { variable info proc ::stack_hand {handname hand} { foreach suit {spades hearts diamonds clubs} holding $hand { ::smartstack::stack $handname $suit $holding } } proc ::stack_cards {handname args} { foreach {suit holding} $args { ::smartstack::stack $handname $suit $holding } } if {[llength $args]>0} { set range [list $min [lindex $args 0]] } else { set range [list $min $min] } set info(hand) $hand set info(stackcmds) [list] set info(factory) [handFactory::create $shapeclass $valuation $range] foreach suit {spades hearts diamonds clubs} placed [stacked $hand] { $info(factory) restrictSuit $suit $placed contains set restrict($suit) {} } foreach other [list [lho $hand] [partner $hand] [rho $hand]] { set stackcmd [list deck_stack_cards $other] set count 0 foreach suit {spades hearts diamonds clubs} \ sletter {S H D C} \ cardset [stacked $other] { incr count [holding length $cardset] set restrict($suit) [::holding union $restrict($suit) $cardset] lappend stackcmd $suit $cardset } if ($count>0) { lappend info(stackcmds) $stackcmd } } foreach suit {spades hearts diamonds clubs} { $info(factory) restrictSuit $suit $restrict($suit) } reset_deck deal_reset_cmds {::smartstack::next} } proc next {} { variable info reset_deck foreach cmd $info(stackcmds) { set v [catch $cmd] if {$v} { global errorInfo puts stderr "Problem running smartstack: $errorInfo" return -code return } } set v [catch {$info(factory) sample} hand] if {$v} { global errorInfo puts stderr "Problem running smartstack: $errorInfo" return -code return } set v [catch {deck_stack_hand $info(hand) $hand}] if {$v} { global errorInfo puts stderr "Problem running smartstack: $errorInfo $info(hand) $hand" return -code return } deal_reset_cmds {::smartstack::next} } proc restrictHolding {suit valuation {min 0} args} { if {[llength $args]>0} { set max [lindex $args 0] } else { set max $min } variable info $info(factory) addHoldingCond "set v \[$valuation holding \$h\] ; expr {\$v>=$min&&\$v>=$max}" $suit } proc stack {hand suit holding} { variable info if {[holding length $holding]==0} { return } if {0==[string compare $info(hand) $hand]} { set rule contains } else { set rule disjoint lappend info(stackcmds) [list deck_stack_cards $hand $suit $holding] } $info(factory) addHoldingCond "holding $rule \$h $holding" $suit } proc getdata {{mult 1.0}} { variable info $info(factory) getdata $mult } } deal319/input/pbn.tcl0000644000175200017520000000306411063454127012720 0ustar cbecbe# # Copyright (C) 1996-2001, Thomas Andrews # # $Id: pbn.tcl 255 2008-09-15 12:43:02Z thomasoa $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # read the output from a line input # namespace eval pbn { ::deal::nostacking variable handle stdin proc finalize {} { variable handle close $handle } proc initialize {file} { variable handle if {"$handle"!="stdin"} { finalize } set handle [open $file "r"] puts stderr "file opened for $file" deal_reset_cmds {::pbn::next} } proc next {} { variable handle set length [gets $handle line] reset_deck if {$length==0} { finalize exit 0 } puts stderr "Input: $line" foreach hand {north east south west} val [split $line "|"] { deck_stack_hand $hand [split $val " "] } deal_reset_cmds {::pbn::next} } proc set_input {file} { initialize $file deal_reset_cmds {::pbn::next} } } deal319/dist.h0000644000175200017520000000345111062564550011413 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "tcl_incl.h" #include "deck.h" typedef unsigned char HandDist[4]; #define DIST_COUNT 560 extern HandDist dist_table[DIST_COUNT]; #define BitsPerChar 8 #define DistSetCharCount DIST_COUNT/BitsPerChar typedef struct distset { Tcl_Obj ***array[14]; Tcl_Obj **array1[105]; Tcl_Obj *array2[560]; Tcl_Obj *shapesList; } *DistSet; typedef struct distfunc { char *tclCode; Tcl_Obj ***array[14]; Tcl_Obj **array1[105]; Tcl_Obj *array2[560]; } *DistFunc; typedef struct _DistTableEntry { int index; double probability; } DistTableEntry; typedef struct _DistTable { int count; DistTableEntry entry[DIST_COUNT]; } DistTable; extern void computeDistTable _ANSI_ARGS_(()); extern DistSet newDistSet _ANSI_ARGS_((int)); extern DistFunc newDistFunc _ANSI_ARGS_((int)); #define DSElt(s,i) ((s)->array2[(i)]) #define DSAdd(s,i) Tcl_SetBooleanObj((s)->array2[(i)],1) #define DSDelete(s,i) Tcl_SetBooleanObj((s)->array2[(i)],0) #define DFVal(f,i) ((f)->array2[(i)]) #define DFSetValue(f,i,val) (((f)->array2[(i)])=val) deal319/Make.mac-osx0000644000175200017520000000044011341064373012436 0ustar cbecbeMAC_ARCH = MAC_ARCH_UNIVERSAL = -arch x86_64 -arch i386 -arch ppc #DEBUG_FLAGS=-g -ansi -Wall $(MAC_ARCH) DEBUG_FLAGS=-fast -ansi -Wall $(MAC_ARCH) CPPFLAGS = -fno-rtti -fast -Winline -Wall $(MAC_ARCH) TCL_INCL=/usr/local/include TCL_LIB=$(TCL_DIR)/lib LDFLAGS= -L$(TCL_LIB) -ltcl -lm deal319/tests/0000755000175200017520000000000011077200553011432 5ustar cbecbedeal319/tests/output/0000755000175200017520000000000011062564544013001 5ustar cbecbedeal319/tests/output/sample.ddline0000644000175200017520000002544511062564544015455 0ustar cbecbe8532.Q7.AK4.T952|.A962.JT932.AK43|A.JT8543.876.Q76|KQJT9764.K.Q5.J8|2 7 4 4 4|10 6 9 8 7|2 7 3 4 3|10 6 9 8 7 A.87.QJT642.Q752|QJ986.A.AK5.KT63|KT75432.JT6..AJ9|.KQ95432.9873.84|7 2 6 6 7|5 11 7 5 6|7 2 5 6 6|4 10 7 5 6 AT54.Q9.842.AT75|K87.KT876.Q9.KQ9|Q63.AJ.KJ753.J63|J92.5432.AT6.842|8 6 9 8 7|5 7 4 5 5|8 6 8 8 7|5 7 4 5 5 AQ64.42.QJ843.83|97.QT76.97.QJ975|J8532.J853.6.AT6|KT.AK9.AKT52.K42|8 5 6 3 6|5 8 7 9 7|8 5 6 3 6|5 8 7 9 7 AJ.K964.AQ65.J74|T973.J5.K94.A962|85.8.JT832.KT853|KQ642.AQT732.7.Q|3 3 9 9 6|10 10 3 4 6|3 3 9 9 6|10 10 3 4 6 AKT.KQ752.6.T643|Q9843..J9752.AQ9|652.T84.AQ8.J875|J7.AJ963.KT43.K2|4 7 3 7 4|9 6 10 5 7|4 7 3 7 5|9 6 10 6 8 AQ73.JT75.5.A862|86.KQ9.KJ87.KJT4|J2.A862.QT96.Q73|KT954.43.A432.95|6 9 6 7 6|7 4 7 5 7|6 8 6 7 6|7 4 7 5 6 AJ743.Q6.JT5.K65|96.J85.A86.JT943|KQT.AT42.Q43.A82|852.K973.K972.Q7|10 8 8 7 9|3 4 4 6 3|10 8 8 7 9|3 4 4 6 3 T5.T643.Q85.Q542|8643.92.JT742.76|AQJ92.8.K63.AT93|K7.AKQJ75.A9.KJ8|7 3 6 8 5|6 8 7 4 8|7 5 6 8 5|6 8 7 4 8 A874.94.AK93.QT3|T3.KJT7.QJT5.AJ2|J952.AQ53.842.K8|KQ6.862.76.97654|10 7 9 7 8|3 6 4 6 5|10 7 9 7 8|3 5 4 6 4 Q764.T5.AK2.KQ86|T95.7.QT9873.J74|2.AQJ86432.4.T32|AKJ83.K9.J65.A95|5 10 4 7 7|7 2 8 6 4|5 10 4 7 7|7 2 9 6 4 AT96.Q2.K73.AQJ4|Q3.AJT93.QJ2.K98|KJ52.K75.986.T53|874.864.AT54.762|9 6 7 9 7|3 7 6 4 5|9 6 7 9 7|3 7 6 4 5 AQ6.T8752.2.Q863|852.AQJ9.QJT96.4|J9743.63.3.KT972|KT.K4.AK8754.AJ5|5 3 0 8 2|4 8 11 4 8|5 3 0 8 2|6 9 12 5 11 654.Q982.T93.732|QT7.AKJ64.QJ.AQJ|AJ9.T73.A87542.9|K832.5.K6.KT8654|2 3 6 1 2|10 10 6 11 10|2 3 6 1 2|10 10 6 11 10 AKQJ.3.AJ95.Q864|72.762.T8.JT9753|84.AKJ984.K43.AK|T9653.QT5.Q762.2|12 12 13 10 13|1 1 0 3 0|12 12 13 10 13|1 1 0 3 0 JT987.753.J73.A4|K63.KT6.AKQ52.K5|AQ4.J92.T94.T832|52.AQ84.86.QJ976|6 2 3 2 4|7 10 10 10 9|6 2 3 2 4|7 10 10 10 7 KJ6.J52.4.T75432|AQ9.4.KT982.AKQ9|8432.KQT97.A75.J|T75.A863.QJ63.86|5 6 1 5 1|8 7 12 8 8|5 6 1 5 1|8 7 12 8 8 A5.T985.AQ872.K5|QJ74.K63.J9.Q963|92.QJ74.T43.AJ42|KT863.A2.K65.T87|6 10 10 7 7|7 3 3 6 5|6 10 10 7 7|7 3 3 6 5 AJ82.Q8.8.AKQJ76|54.KT.AQ97654.82|KT73.A7542.J.T53|Q96.J963.KT32.94|11 9 5 11 6|1 4 8 2 2|11 9 5 11 6|1 4 8 2 2 4.42.K32.T965432|AT952.J7.AJ84.K7|KQJ3.Q5.Q75.AQJ8|876.AKT9863.T96.|4 2 2 8 2|9 10 8 4 10|4 2 2 8 2|9 10 8 4 6 AKQ42.KT93..KT62|53.Q76.QT9632.93|J876.J84.AKJ5.87|T9.A52.874.AQJ54|11 10 7 8 9|2 3 6 5 4|11 10 7 8 9|2 3 6 5 4 8765.K7.AT53.853|QJT.J.Q842.JT976|K92.AT9652.97.KQ|A43.Q843.KJ6.A42|5 7 4 3 4|6 6 8 10 7|6 7 4 3 4|6 6 8 10 7 Q7.J9743.Q975.T8|JT94.KQT.A6.K972|K65.62.T832.QJ54|A832.A85.KJ4.A63|2 4 5 3 3|11 9 8 10 10|2 4 5 3 3|11 9 8 10 10 753.Q872.Q742.T3|AKT9642.T63.85.8|8.A4.AJ3.J976542|QJ.KJ95.KT96.AKQ|2 3 4 7 2|11 9 8 6 11|2 3 4 7 2|11 9 8 6 11 9843.8.J76542.AT|K76.A32.Q98.KJ32|AQ52.QJT64.AT.97|JT.K975.K3.Q8654|9 6 8 4 5|4 6 5 8 8|9 6 8 4 5|4 6 5 8 8 Q52.T94.A853.K92|AT974.KJ82.KJ.74|863.3.Q72.AQJT65|KJ.AQ765.T964.83|2 1 5 8 3|9 10 7 5 6|2 1 5 8 3|9 10 7 5 6 KT65.AT5.AKJ.J63|AJ7.Q32.QT7.A742|84.KJ4.8652.KT98|Q932.9876.943.Q5|7 7 8 8 8|6 5 5 5 5|7 7 8 8 8|6 6 5 5 5 QJ2.AT543.K93.65|AT63.KQJ762.T7.4|987.8.QJ8.AKQJ98|K54.9.A6542.T732|5 5 7 10 8|7 8 5 3 4|5 5 7 10 8|7 8 5 3 4 A5.JT74.AQJ.T842|QJ4.9.T87643.963|T9872.KQ52.2.J75|K63.A863.K95.AKQ|5 7 4 6 7|6 5 9 6 6|5 7 4 6 7|7 5 9 7 6 AK73.AJ9842.Q52.|JT5.Q75.A974.Q65|9642.T3.KJ3.KJ98|Q8.K6.T86.AT7432|10 10 7 7 9|3 3 6 6 4|10 10 7 7 9|3 3 6 6 4 75.652.AK743.Q95|KT43.A943.J8.AKJ|6.KQ87.T962.T742|AQJ982.JT.Q5.863|3 6 8 6 3|10 7 5 7 8|3 6 8 6 3|10 7 5 7 8 Q93.A62.J642.K96|AJ87.J9854.A9.JT|K42.KT7.KQ73.Q32|T65.Q3.T85.A8754|5 6 8 6 8|7 6 4 6 4|6 5 8 6 8|7 6 4 6 4 J9753.Q532.AT.K4|AQT82.964.73.832|K4.AKT8.Q964.J97|6.J7.KJ852.AQT65|7 8 6 5 7|5 4 6 7 5|7 8 6 5 7|5 4 6 7 5 Q8765..AKJ.KQ743|A932.KQJ985.3.J5|4.A6432.Q654.T62|KJT.T7.T9872.A98|6 4 8 9 4|6 8 5 4 5|6 4 8 9 4|6 8 5 4 5 KQT42.K864.K62.3|AJ87.T5.T8753.Q5|63.AJ73.Q9.KT872|95.Q92.AJ4.AJ964|6 8 4 6 5|7 5 8 7 7|6 8 5 6 6|7 5 8 7 7 K5.Q4.K854.KJ982|QJ96.A9732.732.3|A84.KJT6.J96.Q74|T732.85.AQT.AT65|6 7 7 9 8|7 6 5 4 4|6 7 7 9 8|7 6 5 4 4 KT953.J.T.KJT974|Q72.T75.J7642.86|AJ6.962.853.AQ53|84.AKQ843.AKQ9.2|11 2 1 11 2|2 10 10 2 2|11 2 1 11 2|2 10 10 2 2 T653.KQT72.J97.T|92.J86.AT84.6532|KQ.9.Q653.AJ9874|AJ874.A543.K2.KQ|5 6 7 7 6|7 7 5 6 6|5 6 7 7 6|7 7 5 6 6 AK75.9743.KQ.K94|32.AKQ6.AJ3.AQJ2|T986.5.76542.T53|QJ4.JT82.T98.876|8 3 7 4 3|5 10 6 9 10|7 3 5 3 3|5 10 6 9 10 AJ87.Q864.QJ53.T|5.A3.A87.KQJ9843|KQT63.K75.K92.72|942.JT92.T64.A65|10 8 8 3 4|3 5 4 9 8|10 8 8 3 4|3 4 4 9 8 J98.97.JT96.AJ95|T.AK8542.542.Q32|KQ642.QJ3.A87.T7|A753.T6.KQ3.K864|7 4 6 5 7|6 9 7 7 6|7 4 6 5 6|6 9 7 7 6 Q.AT.J9864.Q9642|J98652.QJ.Q2.JT8|AKT43.32.T75.AK5|7.K987654.AK3.73|8 4 10 9 9|5 9 3 3 4|8 4 10 9 9|5 9 3 3 4 93.AT5.A763.AQ85|QT2.J432.QJT5.K2|7.K96.9842.T9764|AKJ8654.Q87.K.J3|4 5 5 8 4|9 8 5 5 8|4 5 5 8 4|9 8 5 5 8 KQ7.Q962.KT5.K95|A943.A87.A32.QT6|852.KJT4.QJ84.72|JT6.53.976.AJ843|5 8 7 4 5|8 5 5 8 7|4 8 7 4 5|8 5 5 8 7 K653.KQ2.AKT9.Q3|7.A5.J542.AKT654|QJT.JT98.Q873.72|A9842.7643.6.J98|6 5 8 3 5|6 5 5 9 8|6 5 8 3 5|6 5 5 9 8 Q5.T8.AKJ943.875|KJ93.J6432.Q.QJ6|AT864.A.T86.AT32|72.KQ975.752.K94|9 4 11 10 9|4 9 2 3 3|9 4 11 9 9|4 9 2 3 3 4.KT3.AKT4.JT652|AKQ65.Q.97652.AK|T932.97654.J.Q94|J87.AJ82.Q83.873|3 5 3 7 4|9 6 9 5 9|3 5 3 7 4|9 7 9 5 9 Q7.T964.K6.Q9765|KJ8632.7.J93.842|A5.QJ82.AQ72.AT3|T94.AK53.T854.KJ|4 9 7 9 6|8 4 5 4 5|4 9 7 9 6|8 4 5 4 5 643.JT6.AK3.K932|T97.A872.J97.Q76|K82.KQ3.Q8.AJT85|AQJ5.954.T6542.4|7 7 6 9 8|6 6 7 3 5|7 7 6 9 8|6 6 7 3 5 KJ732.AJ653.KJ.8|9.T87.Q97654.954|QT84.94.AT83.KQ2|A65.KQ2.2.AJT763|10 8 7 4 7|3 4 6 8 3|10 8 7 4 10|3 5 6 8 3 Q852.KT.QT86.A85|KT97.4.A954.KQ63|43.AQJ75.732.J92|AJ6.98632.KJ.T74|4 6 5 3 5|9 7 8 9 7|3 6 4 3 5|9 7 8 9 8 A9765.A87.AQ.A85|Q.654.87642.QT96|T43.JT3.JT9.7432|KJ82.KQ92.K53.KJ|6 5 5 6 6|6 7 8 7 6|7 6 5 6 7|6 7 8 7 6 AKQ73.AT52.Q63.Q|J54.3.AKJ92.9432|62.KQ8.8754.A876|T98.J9764.T.KJT5|10 9 8 5 10|3 3 5 8 3|9 7 5 4 8|3 3 5 8 3 AQ7.A965.A52.Q62|KJ96.QJ42.64.873|43.K83.KQJT9.AK5|T852.T7.873.JT94|8 11 12 10 12|5 2 1 3 1|8 10 12 10 12|5 2 1 3 1 KJ9643.A.QJ6.K64|A82.QT52.A42.A87|QT75.K3.985.QJT5|.J98764.KT73.932|9 4 5 7 7|4 9 7 6 5|9 4 5 7 7|4 9 7 6 5 AJ875.AKJ7.5.KJ8|Q42..KQ76.A97654|K6.QT8532.AT2.T3|T93.964.J9843.Q2|11 12 5 5 10|2 1 8 7 2|11 12 5 5 10|2 1 8 7 2 T95432.A7543.5.5|AJ7.QJ8.A43.AQ83|86.92.J876.T7642|KQ.KT6.KQT92.KJ9|5 3 1 1 1|7 10 12 12 12|5 3 1 1 1|7 10 12 12 12 AKT53.87.Q83.AK3|J2.AJT9.J6.J9764|Q9874.Q65.A4.T82|6.K432.KT9752.Q5|10 4 5 6 8|3 8 8 7 5|10 5 5 6 8|3 8 8 7 5 T643.92.K9853.86|A52.AK73.Q72.K93|Q8.J8654.AJT64.2|KJ97.QT..AQJT754|1 4 7 0 0|12 8 5 13 8|1 4 7 0 0|12 8 5 13 8 K9743.T63.A72.KJ|T65.AJ92.65.Q652|AJ82.Q8.KJ943.A4|Q.K754.QT8.T9873|10 5 10 5 9|3 8 3 8 4|10 5 10 5 9|3 8 3 8 4 QJ543.K9.AQT83.4|AKT98.J865..AT83|6.432.KJ542.QJ97|72.AQT7.976.K652|5 3 9 3 6|8 10 4 10 7|5 3 9 3 6|8 10 4 10 7 T2.JT864.J2.K542|Q7.KQ9753.Q98.J7|J.A2.AKT64.AQ983|AK986543..753.T6|4 8 9 10 5|8 4 2 1 2|5 8 10 10 5|8 4 2 1 2 QT8.2.T653.KT954|AK7.Q3.9742.AQ87|95.AKJ8654.J8.J2|J6432.T97.AKQ.63|3 6 4 5 6|10 6 9 7 6|3 6 4 5 6|10 6 9 8 6 Q8.A92.JT975.KJT|AJ9.J6.Q632.AQ53|T7642.K873.A4.64|K53.QT54.K8.9872|6 5 5 4 4|7 7 7 9 8|6 5 5 4 4|7 7 7 9 8 K54.Q65.AJ9862.K|J7.AKT83.5.AJ985|AQT8.J.KQT73.QT2|9632.9742.4.7643|10 6 11 6 10|3 7 1 7 3|10 6 11 6 10|3 7 1 7 3 T4.A972..AKJT985|K3.J85.JT974.Q76|AQJ9.KT43.K63.43|87652.Q6.AQ852.2|9 12 5 12 8|3 1 8 1 3|9 12 5 12 9|3 1 8 1 3 T72.QJT3.A32.K84|K8643.A64.QJ5.53|J5.K952.8764.972|AQ9.87.KT9.AQJT6|2 6 4 2 3|10 7 8 10 9|2 6 4 2 3|10 7 8 10 9 T986.K764..KQ652|AQ7.A82.JT85.A83|3.QJT95.AQ732.J9|KJ542.3.K964.T74|3 10 5 6 3|8 3 8 7 8|3 10 5 6 3|8 3 8 7 8 J765432.A95.3.65|T8.Q4.Q852.AQJ74|AKQ.KT863.4.K932|9.J72.AKJT976.T8|10 9 4 5 5|3 4 9 8 4|10 9 4 5 5|3 4 9 8 4 Q93.AT64.5432.62|542.Q8.AQT.AQT93|AJT7.KJ7.KJ97.J4|K86.9532.86.K875|8 8 8 5 6|4 5 4 8 7|8 8 8 5 6|4 5 4 8 6 JT6.QJ986.JT7.AK|K82.T54.AQ8653.9|A93.K3.K942.Q732|Q754.A72..JT8654|6 8 7 7 9|6 3 5 6 3|7 8 7 7 9|5 3 5 6 3 K642..A843.K7652|A973.QJ52.765.98|QJT85.T43.J.AQJ3|.AK9876.KQT92.T4|11 2 3 11 6|1 8 7 1 7|11 2 5 12 6|2 8 8 1 7 AT74.K9762.5.K82|Q6.T5.9843.JT964|K82.J843.J762.Q3|J953.AQ.AKQT.A75|7 9 5 4 6|6 4 8 8 5|7 9 5 5 7|6 4 8 8 6 T6.A43.754.AKQ73|K852.KQJ765..542|A974.T98.AQJ3.T6|QJ3.2.KT9862.J98|7 7 9 9 9|6 6 4 3 4|7 6 9 9 9|6 6 4 3 4 A964.8.A73.AKQ76|K3.AQ64.T62.9852|75.KJT973.J9854.|QJT82.52.KQ.JT43|7 10 10 7 7|6 3 2 6 4|7 10 10 7 7|5 3 2 6 4 KT54.AK.732.KJ75|9.J6542.KJ85.QT9|AQ2.QT3.AT4.8643|J8763.987.Q96.A2|9 6 7 9 9|4 7 6 3 4|9 6 7 9 9|4 7 6 3 4 JT985.KQ94.Q3.A7|K64.AT752.76.QJ9|Q3.83.AK52.T8632|A72.J6.JT984.K54|7 6 6 7 7|5 7 7 6 5|7 6 6 7 7|5 7 7 6 5 AJT9.6.J94.Q9654|765.83.A.AKT8732|Q3.A4.KT876532.J|K842.KQJT9752.Q.|7 4 11 6 9|5 9 1 6 3|7 4 11 6 9|6 9 1 6 3 AQ75.JT.J6.K9653|32.87.KQ9874.JT4|K984.Q932.T.A872|JT6.AK654.A532.Q|9 6 3 8 5|4 7 10 4 7|9 6 3 8 5|4 7 10 4 7 652.T7.872.AT943|AKT743.64.KJ.762|QJ9.KJ932.Q94.QJ|8.AQ85.AT653.K85|3 5 3 4 3|10 8 9 8 9|3 5 3 4 3|10 8 10 9 9 A643.QJ9632.6.J8|J72.74.QJT85.QT6|Q85.KT85.A974.75|KT9.A.K32.AK9432|6 8 2 2 2|7 5 11 10 7|6 8 2 2 2|7 5 11 10 7 KJT432.T.Q9762.T|A5.AKJ98.KJ8.K92|876.Q6543.4.8643|Q9.72.AT53.AQJ75|7 1 2 0 1|6 11 10 13 12|7 1 2 0 1|6 12 11 13 12 T.AQJ9542.AK.A32|K9864.K3.JT75.KJ|AQJ3.T8.Q8.Q9854|752.76.96432.T76|8 11 7 11 11|5 2 6 2 2|8 11 7 11 11|5 2 6 2 2 KJ.KT94.QT4.A653|QT87432.J3.A3.97|A965.A765.K6.KQ8|.Q82.J98752.JT42|9 10 8 9 11|4 2 5 3 2|9 11 8 10 11|4 2 5 3 2 AKT86.T84.T52.K5|3.KJ2.K764.JT876|Q94.AQ3.AJ98.Q43|J752.9765.Q3.A92|11 9 9 7 11|2 4 2 6 2|11 9 9 7 10|2 4 2 6 2 KJ.764.KJT96.A86|763.932.Q7542.Q5|T984.AT5.A3.J732|AQ52.KQJ8.8.KT94|6 5 7 6 6|7 7 6 6 6|6 5 7 6 6|7 7 6 6 6 652.T2.J432.QJ75|K87.AQ7.987.KT83|AJT4.965.KQ65.A6|Q93.KJ843.AT.942|7 4 9 5 6|6 8 4 7 7|7 4 9 5 6|5 8 4 7 7 A9632.86.Q2.9765|KQJ8.AQT4.T64.AJ|T754.95.AJ7.KQT2|.KJ732.K9853.843|6 3 3 6 5|7 10 10 7 8|6 3 3 6 5|7 10 10 7 8 3.Q93.AK7.AKJ853|JT876.42.J85.Q62|Q5.AKJ765.QT96.7|AK942.T8.432.T94|7 12 12 11 8|5 0 0 2 1|7 12 12 11 8|5 0 0 2 1 QJ6.A976.KQJ6.Q9|AT75.K8.T7.AKT42|K8432.JT5.A9.765|9.Q432.85432.J83|9 7 7 5 6|4 6 6 8 6|9 7 7 5 6|4 6 6 8 6 AQ76.KJ62.JT62.7|T3.AQT53.K3.KJ53|984.84.AQ87.AQ96|KJ52.97.954.T842|9 9 10 8 9|4 4 3 5 4|9 8 10 7 9|4 4 3 5 4 A75.K52.AJ4.AJ97|QJ6.AT76.T95.T64|T9832.QJ4.3.K532|K4.983.KQ8762.Q8|10 8 6 10 9|3 5 6 3 4|10 8 6 10 9|3 5 6 3 4 A532.A765.7.KQ32|KJ8.Q3.QT53.AJ95|64.K984.AKJ94.T8|QT97.JT2.862.764|8 11 9 8 8|5 2 4 5 5|8 11 9 8 8|5 2 4 5 5 T.Q762.AQ.K87642|KQJ95.AT985.J7.9|A862.3.K86543.Q3|743.KJ4.T92.AJT5|3 3 8 8 3|8 8 5 4 6|3 3 8 9 3|8 8 5 4 6 J972.KJT854.A.KJ|T.A9762.KT932.87|AQ3..QJ876.Q6432|K8654.Q3.54.AT95|8 7 7 8 7|4 5 5 4 5|8 7 7 8 8|4 5 5 4 5 82.T7642.53.Q742|K97653.5.Q76.JT5|QT4.K3.T92.AK986|AJ.AQJ98.AKJ84.3|0 3 0 7 0|11 9 12 6 8|0 3 0 7 3|11 9 12 6 8 AQJ8.Q.AT8532.J4|763.T962.K74.976|KT42.K5.J9.KQT53|95.AJ8743.Q6.A82|10 6 10 10 7|3 7 3 3 3|10 6 10 10 7|3 7 3 3 3 AJ64.843.862.J43|K97.A7.KQT94.975|Q2.KQT96.J5.QT82|T853.J52.A73.AK6|4 6 4 6 4|9 6 9 7 9|4 6 4 6 4|8 6 9 7 8 AJ763.K84.J5432.|98.6.QT7.AQJ9863|QT4.AT95.AK96.KT|K52.QJ732.8.7542|12 10 13 5 12|1 3 0 8 1|12 10 13 5 12|1 3 0 8 1 AT63.J8.KT542.KQ|KQ92.75432.A.J64|8.QT96.9763.8732|J754.AK.QJ8.AT95|2 4 8 3 3|10 9 5 9 8|2 4 8 3 3|10 9 5 9 8 deal319/tests/great880000644000175200017520000003540111062564544012651 0ustar cbecbeproc problem {id title diagram goal {denomination notrump} {leader south}} { set tricks [dds -diagram $diagram -leader $leader south $denomination] if {$tricks != $goal} { set result FAIL } else { set result PASS } puts "$result: Problem $id ($title) makes $tricks tricks with goal $goal" } # Tribe 1 - Eliminations, Endplays of Position problem 1 Avoidance { {A987 - A} {Q5 987 -} {64 K2 2} {K2 AQ3 -} } 3 notrump problem 2 {The Pitt coup} { {A2 753} {Q9 64 Q} {KJ - 753} {3 Q98 A} } 5 spades problem 3 {Gambit and jettison} { {A 873 A} {6 9 K KJ} {- A6 - Q43} {8 Q Q98 -} } 4 spades problem 4 {Forced finesse} { {842 32} {A76 K8} {KQ3 AQ} {J9 75 2} } 4 notrump problem 5 {Strip setup finesse} { {7 - Q63 A} {9 - JT8 7} {- - K94 65} {5 - - K984} } 4 spades problem 6 {Double strip finesse} { {- 86 - A96} {5 A53 - 5} {A 742 - 2} {- 9 8 874} } 4 notrump problem 7 {Crossruff strip} { {97 - 72 2} {- Q3 Q KQ} {86 - A8 8} {J J KJ J} } 3 spades problem 8 {Jettison entry strip} { {2 32 - A2} {- - J9 KJ6} {- - A43 Q3} {- KQ KQ 8} } 4 spades problem 9 {Jettison two-entry strip} { {- A7 - QJ5} {- 65 AK9 -} {J J9 QJ -} {8 K3 - K9} } 4 spades problem 10 {Double-entry strip} { {743 A A -} {Q Q Q QJ} {KJ2 - - 32} {A65 K K} } 4 notrump problem 11 {Fork strip} { {52 5 5 5} {98 9 9 9} {AQ A 3 A} {K63 K A -} } 4 notrump problem 12 {Total fork strip} { {T42 - A 4} {QJ7 - J Q} {K85 8 6 -} {A96 - 3 5} } 3 hearts problem 13 {Progressive fork strip} { {Q3 - - KQJ} {KT2 - - 64} {AJ97 J - -} {8654 A - -} } 4 notrump problem 14 {Transfer fork strip} { {6 4 - AJ5} {- - 65 Q84} {- - 72 K63} {- Q K4 92} } 4 spades problem 15 {Jettison double fork strip} { {- - J T862} {7 8 - A97} {J 642 5 -} {9 953 8 -} } 3 spades problem 16 {Repeat-jettison fork strip} { {- A A KJ7} {5 - Q9 AQ} {Q 2 KJ8 -} {J 3 764} } 4 spades problem 17 {Two-fork double strip} { {- 8 J7 A9} {- Q7 A8 8} {A A93 6 -} {- 65 Q Q6} } 4 notrump problem 18 {Double blocked fork strip} { {- Q9 J95} {- KT73 Q} {9 8 A64} {4 J K73} } 3 spades problem 19 {Crossruff or finesse strip} { {T 5 - AT5} {- JT KQ J} {5 A - 432} {- KQ - KQ9} } 4 spades problem 20 {Crossruff entry strip} { {3 4 A 32} {- K K KQJ} {54 A - 75} {- 75 98 A} } 4 spades problem 21 {Crossruff fork strip} { {A AQ Q A} {- K5 K KQ} {3 32 3 3} {- J9 J J9} } 4 spades problem 22 {Crossruff split-fork strip} { {3 Q - KT3} {- A9 - Q75} {4 6 - A94} {- K A J86} } 4 spades problem 23 {Entry or fork strip} { {3 72 Q2} {2 J54 J} {- AK3 A7} {- Q98 K9} } 4 notrump problem 24 {Jettison-entry fork strip} { {K984 - K -} {AJ - - 876} {- Q65 72 -} {- 98 A65 -} } 3 notrump problem 25 {Blocked fork strip or entry} { {KJ3 - K 8} {Q7 - QJ 9} {- J 84 J6} {- 9 9 Q72} } 4 notrump problem 26 {Crossruff entry fork strip} { {3 32 - 53} {- - 98754 -} {75 75 - 2} {- 64 6 64} } 4 spades # Tribe 2 - Coups, Endplays of Time problem 27 {En passant} { {A54 2 - 2} {7 - A7 87} {- 3 32 A3} {98 9 9 9} } 4 spades problem 28 {Grand coup} { {- 42 AK A} {K4 - 43 4} {AQ2 - 2 2} {J9 - J9 J} } 5 spades problem 29 {Grand coup fork strip} { {876 A - 9} {3 K K KQ} {AJT2 - A -} {KQ9 9 9 -} } 4 spades problem 30 {Overruff grand coup} { {Q972 - - Q} {- - K6 K62} {54 4 5 4} {JT8 32 - -} } 4 spades problem 31 {Repeating grand coup} { {AK - - QT8} {J9765 - - -} {QT8 A A -} {432 8 8 -} } 5 spades problem 32 {Undercut} { {- 4 A65 A} {KQT - K 4} {AJ2 6 4 -} {- A QJ98 -} } 4 spades problem 33 {Uppercut} { {Q7 8 J A} {A65 - 2 8} {42 42 4 -} {983 A 9 -} } 2 spades problem 34 {Smother play} { {A42 2 - 2} {T9 T9 T -} {QJ87 7 - -} {K653 3 - -} } 4 spades problem 35 {Double smother} { {AT3 - AK -} {J6 6 6 6} {K92 A - 4} {Q85 5 5 -} } 5 spades # Tribe 3 - Squeezes, Endplays of Mass problem 36 {Double squeeze} { {A2 2 - KQ} {KJ - A 86} {3 - 2 A72} {Q9 A - J9} } 5 notrump problem 37 {Double squeeze} { {94 - 2 K3} {A5 Q - J8} {Q63 2 - 6} {J - 8 972} } 4 spades problem 38 {Double automatic squeeze} { {AQ3 - - K4} {J87 A - 7} {2 2 2 A2} {K96 - A 9} } 5 notrump problem 39 {Split squeeze} { {K3 - 74 A} {J - QJ K9} {A2 - A Q2} {Q - - J875} } 5 notrump problem 40 {Overtake squeeze} { {A964 - - K} {T8752 - - -} {KQJ K K -} {3 A2 A A} } 4 notrump problem 41 {Progressive squeeze} { {3 A3 Q 4} {Q82 - J A} {A7 7 K8 -} {K9 K9 9 -} } 5 notrump problem 42 {Transfer repeat squeeze} { {A7 4 6 7} {J9 - 98 Q} {Q8 - A54 -} {K654 - Q -} } 5 notrump problem 43 {Three-two squeeze} { {- A4 4 42} {- - A3 863} {7 7 - AQ7} {- K6 K J9} } 5 notrump problem 44 {Finesse jettison squeeze} { {K8 - 953 -} {- J JT7 9} {- 9 Q8 63} {Q764 - K -} } 4 notrump problem 45 {Progressive jettison squeeze} { {A4 9 A 5} {- 73 764 -} {96 K4 8 -} {QJ - KJ Q} } 4 notrump problem 46 {Progressive jettison squeeze or squeeze} { {- A3 A9 Q} {- 75 876 -} {9 86 QJ -} {- Q4 K4 K} } 5 notrump problem 47 {Trump squeeze} { {KJ84 - - K} {Q65 - - 32} {A73 K K -} {T9 A A A} } 5 spades problem 48 {Squeeze or forced finesse} { {KQ KQ J} {9 A K93} {2 3 AQ7} {A8765 - -} } 4 notrump problem 49 {Finesse squeeze} { {82 - A9 2} {- 62 8 74} {- 54 Q A6} {- 73 KJ 9} } 5 spades # Tribe 4: Compund and Hybrid Endings problem 50 {One-way finesse or fork strip} { {KJ - - A62} {AQ9 - J7 -} {853 - K4 -} {- - Q5 QJ5} } 3 notrump problem 51 {Forced jettison strip squeeze} { {- A AJ64 -} {8 - Q98 K} {9 Q97 - 7} {J JT86 - -} } 3 spades problem 52 {Crossruff strip triple squeeze} { {6 76 - 76} {9 QJ - QJ} {7 K8 Q 8} {- - KJ876 -} } 3 spades problem 53 {Forced triple squeeze (with fork strip)} { {9 Q8 - Q7} {- J7 - J64} {A6 9 9 9} {T8 - T T8} } 4 notrump problem 54 {Squeeze strip or suitout} { {- 76 A2 2} {- J8 KQ K} {7 AQ5 7 -} {- K94 95 -} } 4 spades problem 55 {Triple squeeze forced finesse} { {Q6 3 8 2} {K 82 A 8} {- A4 K AK} {T4 T - T4} } 4 notrump problem 56 {Jettison squeeze finesse} { {A K2 K2 -} {42 - - QJ9} {53 - - AK3} {K A A 87} } 4 notrump problem 57 {Squeeze or strip squeeze} { {- AQ9 KQ -} {7 KJ AJ -} {K 2 2 JT} {4 - - Q654} } 4 spades problem 58 {Triple squeeze scoop strip} { {K874 - - 2} {A65 - - 98} {2 9 9 AK} {QJ Q Q Q} } 4 notrump problem 59 {Triple squeeze entry strip} { {A654 K - -} {T987 - - K} {KQJ - K 2} {32 A A A} } 4 notrump problem 60 {Jettison triple squeeze entry strip} { {43 2 J A} {K - 98 54} {A - 432 6} {95 9 - K9} } 4 notrump problem 61 {Fork squeeze entry strip} { {- A52 - A9} {- J K9 K8} {- K73 Q7 -} {- Q86 - 64} } 4 notrump problem 62 {Squeeze finesse} { {K2 9 9 K} {J864 - - J} {A95 - - A2} {Q3 A A Q} } 5 notrump problem 63 {Finesse threat 3-2 squeeze} { {2 - K5 A7} {- J8 J97 -} {- 2 AT43 -} {- 9 Q8 J9} } 5 spades problem 64 {Hexagon squeeze finesse} { {2 A9 2 2} {K Q Q4 J} {- 2 A9 AK} {A K4 K Q} } 5 notrump problem 65 {One-way squeeze scoop finesse} { {KJ2 K - 2} {Q54 3 - 4} {A63 - - AK} {987 A - 3} } 5 notrump problem 66 {Automatic squeeze scoop finesse} { {- - T5 A52} {98 - Q76 -} {- 9 K8 K9} {- - 93 T86} } 5 notrump problem 67 {Squeeze ruffout} { {A5 - K98 -} {7 - - QJ87} {93 T95 - -} {- KQ QJT -} } 5 spades problem 68 {Squeeze overruff} { {Q5 5 - KQ} {K KT 87 -} {- A87 T 9} {- J64 J 5} } 5 clubs problem 69 {Repeat-squeeze entry strip} { {2 K4 K K} {AK97 9 - -} {QJ64 8 - -} {8 A2 Q Q} } 2 notrump problem 70 {Forced unblock triple-squeeze scoop} { {QJ8 7 7 -} {- 9 J J94} {965 - - Q8} {AK7 - - K7} } 2 notrump problem 71 {Squeeze unblock finesse} { {Q5 32 - J} {A64 K9 - -} {K8 AJ - 9} {JT97 - - A} } 3 notrump problem 72 {Blocked fork strip} { {- Q7 J92} {- K952 Q} {J 8 A73} {3 J K85} } 3 spades problem 73 {En passant mutate} { {86 74 - 8} {AQ 6 76 -} {K AJ QT -} {- Q98 KJ -} } 4 spades problem 74 {Repeated trump discard} { {42 QJ9 - -} {KQ8 - QJ -} {AJ63 - - 8} {9 7 976 -} } 4 spades west problem 75 {Squeeze scoop ruffout} { {- K9 K AQ} {- A8 - K54} {97 - 9 97} {- QJ Q J6} } 5 spades problem 76 {Coup or squeeze} { {864 - - Q9} {- 5 JT K8} {- 7 7 A42} {75 - 6 T7} } 5 spades problem 77 {Triple-squeeze ruffout} { {52 - 98 9} {J 2 KQ Q} {A4 - 74 7} {- KQ975 - -} } 4 spades west problem 78 {Progressive squeeze jettison scoop} { {5 95 - A7} {- Q8 - JT9} {- J 76 Q3} {9 AT - K8} } 4 notrump problem 79 {Double squeeze strip} { {- A97 83 -} {- T86 T9 -} {8 QJ3 - Q} {K5 K54 - -} } 4 notrump problem 80 {One-way squeeze or ditto} { {7 Q7 7 7} {- - A6 864} {- J J4 J5} {A 986 5 -} } 4 notrump problem 81 {En passant or double squeeze} { {J5 5 - J8} {- - 98 Q74} {3 - J3 K3} {Q9 Q - 96} } 4 spades problem 82 {Squeeze entry strip} { {5 Q6 AJ -} {9 J9 K K} {8 - Q54 8} {Q6 - 976 -} } 4 notrump problem 83 {Double-squeeze scoop} { {- - 86 AQ6} {- 98 - K84} {J J - 953} {- - JT JT7} } 3 notrump problem 84 {Jettison strip mutate} { {- A A K92} {3 J5 - AT} {5 Q6 T8 -} {- K 973 Q} } 4 spades problem 85 {Split squeeze entry strip} { {J53 - AQ} {KQ9 - KJ} {82 Q73 -} {- 964 42} } 3 notrump problem 86 {Hexagon squeeze finesse} { {- 9 A9 75} {- Q7 Q7 Q} {8 K8 8 8} {- J J6 J6} } 4 notrump problem 87 {Endplays in series} { {9 A8 - 87} {T - T9 T9} {- 92 5 A4} {K K765 - -} } 4 notrump problem 88 {Contra squeeze} { {- A T43 A} {A2 K J K} {KQJ - K2 -} {- - AQ765 -} } 3 notrump deal319/tests/benchmark.tcl0000644000175200017520000000006511064743150014072 0ustar cbecbeproc write_deal {} { puts [tricks south notrump] } deal319/tests/input/0000755000175200017520000000000011062564544012600 5ustar cbecbedeal319/tests/input/sample.line0000644000175200017520000001522011062564544014732 0ustar cbecbe8532 Q7 AK4 T952| A962 JT932 AK43|A JT8543 876 Q76|KQJT9764 K Q5 J8 A 87 QJT642 Q752|QJ986 A AK5 KT63|KT75432 JT6 AJ9| KQ95432 9873 84 AT54 Q9 842 AT75|K87 KT876 Q9 KQ9|Q63 AJ KJ753 J63|J92 5432 AT6 842 AQ64 42 QJ843 83|97 QT76 97 QJ975|J8532 J853 6 AT6|KT AK9 AKT52 K42 AJ K964 AQ65 J74|T973 J5 K94 A962|85 8 JT832 KT853|KQ642 AQT732 7 Q AKT KQ752 6 T643|Q9843 J9752 AQ9|652 T84 AQ8 J875|J7 AJ963 KT43 K2 AQ73 JT75 5 A862|86 KQ9 KJ87 KJT4|J2 A862 QT96 Q73|KT954 43 A432 95 AJ743 Q6 JT5 K65|96 J85 A86 JT943|KQT AT42 Q43 A82|852 K973 K972 Q7 T5 T643 Q85 Q542|8643 92 JT742 76|AQJ92 8 K63 AT93|K7 AKQJ75 A9 KJ8 A874 94 AK93 QT3|T3 KJT7 QJT5 AJ2|J952 AQ53 842 K8|KQ6 862 76 97654 Q764 T5 AK2 KQ86|T95 7 QT9873 J74|2 AQJ86432 4 T32|AKJ83 K9 J65 A95 AT96 Q2 K73 AQJ4|Q3 AJT93 QJ2 K98|KJ52 K75 986 T53|874 864 AT54 762 AQ6 T8752 2 Q863|852 AQJ9 QJT96 4|J9743 63 3 KT972|KT K4 AK8754 AJ5 654 Q982 T93 732|QT7 AKJ64 QJ AQJ|AJ9 T73 A87542 9|K832 5 K6 KT8654 AKQJ 3 AJ95 Q864|72 762 T8 JT9753|84 AKJ984 K43 AK|T9653 QT5 Q762 2 JT987 753 J73 A4|K63 KT6 AKQ52 K5|AQ4 J92 T94 T832|52 AQ84 86 QJ976 KJ6 J52 4 T75432|AQ9 4 KT982 AKQ9|8432 KQT97 A75 J|T75 A863 QJ63 86 A5 T985 AQ872 K5|QJ74 K63 J9 Q963|92 QJ74 T43 AJ42|KT863 A2 K65 T87 AJ82 Q8 8 AKQJ76|54 KT AQ97654 82|KT73 A7542 J T53|Q96 J963 KT32 94 4 42 K32 T965432|AT952 J7 AJ84 K7|KQJ3 Q5 Q75 AQJ8|876 AKT9863 T96 AKQ42 KT93 KT62|53 Q76 QT9632 93|J876 J84 AKJ5 87|T9 A52 874 AQJ54 8765 K7 AT53 853|QJT J Q842 JT976|K92 AT9652 97 KQ|A43 Q843 KJ6 A42 Q7 J9743 Q975 T8|JT94 KQT A6 K972|K65 62 T832 QJ54|A832 A85 KJ4 A63 753 Q872 Q742 T3|AKT9642 T63 85 8|8 A4 AJ3 J976542|QJ KJ95 KT96 AKQ 9843 8 J76542 AT|K76 A32 Q98 KJ32|AQ52 QJT64 AT 97|JT K975 K3 Q8654 Q52 T94 A853 K92|AT974 KJ82 KJ 74|863 3 Q72 AQJT65|KJ AQ765 T964 83 KT65 AT5 AKJ J63|AJ7 Q32 QT7 A742|84 KJ4 8652 KT98|Q932 9876 943 Q5 QJ2 AT543 K93 65|AT63 KQJ762 T7 4|987 8 QJ8 AKQJ98|K54 9 A6542 T732 A5 JT74 AQJ T842|QJ4 9 T87643 963|T9872 KQ52 2 J75|K63 A863 K95 AKQ AK73 AJ9842 Q52 |JT5 Q75 A974 Q65|9642 T3 KJ3 KJ98|Q8 K6 T86 AT7432 75 652 AK743 Q95|KT43 A943 J8 AKJ|6 KQ87 T962 T742|AQJ982 JT Q5 863 Q93 A62 J642 K96|AJ87 J9854 A9 JT|K42 KT7 KQ73 Q32|T65 Q3 T85 A8754 J9753 Q532 AT K4|AQT82 964 73 832|K4 AKT8 Q964 J97|6 J7 KJ852 AQT65 Q8765 AKJ KQ743|A932 KQJ985 3 J5|4 A6432 Q654 T62|KJT T7 T9872 A98 KQT42 K864 K62 3|AJ87 T5 T8753 Q5|63 AJ73 Q9 KT872|95 Q92 AJ4 AJ964 K5 Q4 K854 KJ982|QJ96 A9732 732 3|A84 KJT6 J96 Q74|T732 85 AQT AT65 KT953 J T KJT974|Q72 T75 J7642 86|AJ6 962 853 AQ53|84 AKQ843 AKQ9 2 T653 KQT72 J97 T|92 J86 AT84 6532|KQ 9 Q653 AJ9874|AJ874 A543 K2 KQ AK75 9743 KQ K94|32 AKQ6 AJ3 AQJ2|T986 5 76542 T53|QJ4 JT82 T98 876 AJ87 Q864 QJ53 T|5 A3 A87 KQJ9843|KQT63 K75 K92 72|942 JT92 T64 A65 J98 97 JT96 AJ95|T AK8542 542 Q32|KQ642 QJ3 A87 T7|A753 T6 KQ3 K864 Q AT J9864 Q9642|J98652 QJ Q2 JT8|AKT43 32 T75 AK5|7 K987654 AK3 73 93 AT5 A763 AQ85|QT2 J432 QJT5 K2|7 K96 9842 T9764|AKJ8654 Q87 K J3 KQ7 Q962 KT5 K95|A943 A87 A32 QT6|852 KJT4 QJ84 72|JT6 53 976 AJ843 K653 KQ2 AKT9 Q3|7 A5 J542 AKT654|QJT JT98 Q873 72|A9842 7643 6 J98 Q5 T8 AKJ943 875|KJ93 J6432 Q QJ6|AT864 A T86 AT32|72 KQ975 752 K94 4 KT3 AKT4 JT652|AKQ65 Q 97652 AK|T932 97654 J Q94|J87 AJ82 Q83 873 Q7 T964 K6 Q9765|KJ8632 7 J93 842|A5 QJ82 AQ72 AT3|T94 AK53 T854 KJ 643 JT6 AK3 K932|T97 A872 J97 Q76|K82 KQ3 Q8 AJT85|AQJ5 954 T6542 4 KJ732 AJ653 KJ 8|9 T87 Q97654 954|QT84 94 AT83 KQ2|A65 KQ2 2 AJT763 Q852 KT QT86 A85|KT97 4 A954 KQ63|43 AQJ75 732 J92|AJ6 98632 KJ T74 A9765 A87 AQ A85|Q 654 87642 QT96|T43 JT3 JT9 7432|KJ82 KQ92 K53 KJ AKQ73 AT52 Q63 Q|J54 3 AKJ92 9432|62 KQ8 8754 A876|T98 J9764 T KJT5 AQ7 A965 A52 Q62|KJ96 QJ42 64 873|43 K83 KQJT9 AK5|T852 T7 873 JT94 KJ9643 A QJ6 K64|A82 QT52 A42 A87|QT75 K3 985 QJT5| J98764 KT73 932 AJ875 AKJ7 5 KJ8|Q42 KQ76 A97654|K6 QT8532 AT2 T3|T93 964 J9843 Q2 T95432 A7543 5 5|AJ7 QJ8 A43 AQ83|86 92 J876 T7642|KQ KT6 KQT92 KJ9 AKT53 87 Q83 AK3|J2 AJT9 J6 J9764|Q9874 Q65 A4 T82|6 K432 KT9752 Q5 T643 92 K9853 86|A52 AK73 Q72 K93|Q8 J8654 AJT64 2|KJ97 QT AQJT754 K9743 T63 A72 KJ|T65 AJ92 65 Q652|AJ82 Q8 KJ943 A4|Q K754 QT8 T9873 QJ543 K9 AQT83 4|AKT98 J865 AT83|6 432 KJ542 QJ97|72 AQT7 976 K652 T2 JT864 J2 K542|Q7 KQ9753 Q98 J7|J A2 AKT64 AQ983|AK986543 753 T6 QT8 2 T653 KT954|AK7 Q3 9742 AQ87|95 AKJ8654 J8 J2|J6432 T97 AKQ 63 Q8 A92 JT975 KJT|AJ9 J6 Q632 AQ53|T7642 K873 A4 64|K53 QT54 K8 9872 K54 Q65 AJ9862 K|J7 AKT83 5 AJ985|AQT8 J KQT73 QT2|9632 9742 4 7643 T4 A972 AKJT985|K3 J85 JT974 Q76|AQJ9 KT43 K63 43|87652 Q6 AQ852 2 T72 QJT3 A32 K84|K8643 A64 QJ5 53|J5 K952 8764 972|AQ9 87 KT9 AQJT6 T986 K764 KQ652|AQ7 A82 JT85 A83|3 QJT95 AQ732 J9|KJ542 3 K964 T74 J765432 A95 3 65|T8 Q4 Q852 AQJ74|AKQ KT863 4 K932|9 J72 AKJT976 T8 Q93 AT64 5432 62|542 Q8 AQT AQT93|AJT7 KJ7 KJ97 J4|K86 9532 86 K875 JT6 QJ986 JT7 AK|K82 T54 AQ8653 9|A93 K3 K942 Q732|Q754 A72 JT8654 K642 A843 K7652|A973 QJ52 765 98|QJT85 T43 J AQJ3| AK9876 KQT92 T4 AT74 K9762 5 K82|Q6 T5 9843 JT964|K82 J843 J762 Q3|J953 AQ AKQT A75 T6 A43 754 AKQ73|K852 KQJ765 542|A974 T98 AQJ3 T6|QJ3 2 KT9862 J98 A964 8 A73 AKQ76|K3 AQ64 T62 9852|75 KJT973 J9854 |QJT82 52 KQ JT43 KT54 AK 732 KJ75|9 J6542 KJ85 QT9|AQ2 QT3 AT4 8643|J8763 987 Q96 A2 JT985 KQ94 Q3 A7|K64 AT752 76 QJ9|Q3 83 AK52 T8632|A72 J6 JT984 K54 AJT9 6 J94 Q9654|765 83 A AKT8732|Q3 A4 KT876532 J|K842 KQJT9752 Q AQ75 JT J6 K9653|32 87 KQ9874 JT4|K984 Q932 T A872|JT6 AK654 A532 Q 652 T7 872 AT943|AKT743 64 KJ 762|QJ9 KJ932 Q94 QJ|8 AQ85 AT653 K85 A643 QJ9632 6 J8|J72 74 QJT85 QT6|Q85 KT85 A974 75|KT9 A K32 AK9432 KJT432 T Q9762 T|A5 AKJ98 KJ8 K92|876 Q6543 4 8643|Q9 72 AT53 AQJ75 T AQJ9542 AK A32|K9864 K3 JT75 KJ|AQJ3 T8 Q8 Q9854|752 76 96432 T76 KJ KT94 QT4 A653|QT87432 J3 A3 97|A965 A765 K6 KQ8| Q82 J98752 JT42 AKT86 T84 T52 K5|3 KJ2 K764 JT876|Q94 AQ3 AJ98 Q43|J752 9765 Q3 A92 KJ 764 KJT96 A86|763 932 Q7542 Q5|T984 AT5 A3 J732|AQ52 KQJ8 8 KT94 652 T2 J432 QJ75|K87 AQ7 987 KT83|AJT4 965 KQ65 A6|Q93 KJ843 AT 942 A9632 86 Q2 9765|KQJ8 AQT4 T64 AJ|T754 95 AJ7 KQT2| KJ732 K9853 843 3 Q93 AK7 AKJ853|JT876 42 J85 Q62|Q5 AKJ765 QT96 7|AK942 T8 432 T94 QJ6 A976 KQJ6 Q9|AT75 K8 T7 AKT42|K8432 JT5 A9 765|9 Q432 85432 J83 AQ76 KJ62 JT62 7|T3 AQT53 K3 KJ53|984 84 AQ87 AQ96|KJ52 97 954 T842 A75 K52 AJ4 AJ97|QJ6 AT76 T95 T64|T9832 QJ4 3 K532|K4 983 KQ8762 Q8 A532 A765 7 KQ32|KJ8 Q3 QT53 AJ95|64 K984 AKJ94 T8|QT97 JT2 862 764 T Q762 AQ K87642|KQJ95 AT985 J7 9|A862 3 K86543 Q3|743 KJ4 T92 AJT5 J972 KJT854 A KJ|T A9762 KT932 87|AQ3 QJ876 Q6432|K8654 Q3 54 AT95 82 T7642 53 Q742|K97653 5 Q76 JT5|QT4 K3 T92 AK986|AJ AQJ98 AKJ84 3 AQJ8 Q AT8532 J4|763 T962 K74 976|KT42 K5 J9 KQT53|95 AJ8743 Q6 A82 AJ64 843 862 J43|K97 A7 KQT94 975|Q2 KQT96 J5 QT82|T853 J52 A73 AK6 AJ763 K84 J5432 |98 6 QT7 AQJ9863|QT4 AT95 AK96 KT|K52 QJ732 8 7542 AT63 J8 KT542 KQ|KQ92 75432 A J64|8 QT96 9763 8732|J754 AK QJ8 AT95 deal319/deck.h0000644000175200017520000000312411062564550011353 0ustar cbecbe/* * Copyright (C) 1996-2001, Thomas Andrews * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DECK_H__ #define __DECK_H__ #define SPADES 0 #define HEARTS 1 #define DIAMONDS 2 #define CLUBS 3 #define NORTH 0 #define EAST 1 #define SOUTH 2 #define WEST 3 #define NOSUIT 4 #define NOSEAT 4 #define NORANK 15 #define NOCARD -1 #define ACE 0 #define KING 1 #define QUEEN 2 #define JACK 3 #define TEN 4 #define NINE 5 #define EIGHT 6 #define SEVEN 7 #define SIX 8 #define FIVE 9 #define FOUR 10 #define THREE 11 #define TWO 12 #define CARDSperSUIT 13 #define CARD(denom,suit) ((int)(denom)*4+(int)(suit)) #define RANK(card) ((card)/4) #define SUIT(card) ((card)%4) extern char *suitname[]; extern char *handname[]; #if defined(__STDC__) #define PROTO(params) params #else #define PROTO(params) () #endif #endif #ifdef HPUX #define random rand #define srandom srand #endif #ifdef USE_RAND48 double drand48(); void srand48(); #endif