From 28508ba3d174461446ac4992bd9aa8c1315d9723 Mon Sep 17 00:00:00 2001 From: Travis Hoppe Date: Mon, 6 Dec 2010 15:29:39 -0500 Subject: [PATCH] Began versioning. --- DECK.py | 152 +++++++++++++++++++++++++++++++ GAMEPLAY.py | 235 ++++++++++++++++++++++++++++++++++++++++++++++++ PBOT.py | 63 +++++++++++++ combinations.py | 26 ++++++ p1.py | 40 +++++++++ p2.py | 46 ++++++++++ 6 files changed, 562 insertions(+) create mode 100644 DECK.py create mode 100644 GAMEPLAY.py create mode 100644 PBOT.py create mode 100644 combinations.py create mode 100755 p1.py create mode 100755 p2.py diff --git a/DECK.py b/DECK.py new file mode 100644 index 0000000..cff2f71 --- /dev/null +++ b/DECK.py @@ -0,0 +1,152 @@ +from random import randint, choice, seed +from combinations import * + +''' +Cards in the deck is stored as (n,m), where n is the rank number +n=[0,12], m=[0,3], with n defined to be the card value and m as the suit. + + Examples: + (0,1) is a two of hearts, + (11,0) is a king of spades, + (12,3) is an Ace of clubs +''' + +DECK = dict().fromkeys(range(52)) +for c in DECK: DECK[c] = (c/4,c%4) + +''' Fisher-Yates shuffle from Knuth ''' +def shuffle(DECK): + for n in range(1,52)[::-1]: + k = randint(0,n-1) + DECK[k], DECK[n] = DECK[n], DECK[k] + +''' +To determine which five card hand is stronger according to standard poker +rules, each hand is given a score and a pair rank. The score cooresponds to +the poker hand (Straight Flush=8, Four of a Kind=7, etc...). The pair score +is used to break ties of score. The pair score creates a set of pairs then +rank sorts within each set. Examples: + +Hand A: 7575K +Hand B: 885A5 + +Pair Score A: [ (2, [7,5]), (1, [K]) ] +Pair Score B: [ (2, [8,5]), (1, [A]) ] + +Hand A: AKQJ2 +Hand B: 2345A + +Pair Score A: [ (1, [A,K,Q,J,2]) ] +Pair Score B: [ (1, [A,5,4,3,2]) ] +''' + +def pairScore(cards): + P = dict().fromkeys(cards,0) + for c in cards: P[c] += 1 + V = sorted(set(P.values()))[::-1] + return [[v,sorted([c for c in set(P) if P[c]==v])[::-1]] for v in V] + +def top_pairScore(P1,P2): # Only compare to cards with same score! + for p1, p2 in zip(P1,P2): + if p1[1]>p2[1]: return 1 + elif p1[1]B[0]: return H1,A + elif A[0] 0: return H1,A + elif pairscore < 0: return H2,B + return H1,A + +def top_hand_score(A,B): + A.score,B.score = handScore(A.score), handScore(B.score) + if A.score[0]>B.score[0]: return 1 + elif A.score[0] self.cash: wager = self.cash + if wager < 0: wager = 0 + if wager-self.owe > other_player.cash: + wager = other_player.cash + self.cash -= wager + self.owe -= wager + self.owe = self.owe if self.owe < 0 else 0 + GP("ACTION Player ", self.name, " bets: ", wager) + return wager + + def record_info(self, pot, min_raise, flop, turn, river, other_player): + global GLOBAL_TXT + self.IN.write("INFO NAME " + str(self.name) + '\n'); self.IN.flush() + self.IN.write("INFO ONAME " + str(other_player.name) + '\n'); self.IN.flush() + self.IN.write("INFO STACK " + str(self.cash) + '\n'); self.IN.flush() + self.IN.write("INFO OSTACK " + str(other_player.cash) + '\n'); self.IN.flush() + self.IN.write("INFO POT " + str(pot) + '\n'); self.IN.flush() + self.IN.write("INFO MINRAISE " + str(min_raise)+'\n'); self.IN.flush() + self.IN.write("INFO OWE " + str(self.owe) + '\n'); self.IN.flush() + self.IN.write("INFO HOLE " + pp_hand(self.hole) + '\n'); self.IN.flush() + self.IN.write("INFO FLOP " + pp_hand(flop) + '\n'); self.IN.flush() + self.IN.write("INFO TURN " + pp_hand(turn) + '\n'); self.IN.flush() + self.IN.write("INFO RIVER " + pp_hand(river) + '\n'); self.IN.flush() + self.GP_FLUSH(GLOBAL_TXT) + + def GP_FLUSH(self, TXT): + for g in TXT: + if g not in self.GP_BUFFER: + self.GP_BUFFER.append(g) + self.IN.write(g + "\n") + self.IN.flush() + + def human_play(self, pot, min_raise, flop, turn, river, other_player): + if GLOBAL_TXT: print GLOBAL_TXT[-1] + print "[", pp_hand(self.hole), "] Board: ", + print "[", pp_hand(flop), pp_hand(turn), pp_hand(river), "]" + print "POT: ", pot, " OWE: ", self.owe, " MIN_RAISE: ", min_raise, + print " | ", "STACK: ", self.cash, "Opp. STACK: ", other_player.cash + return raw_input("What do you want to bet, " + self.name + ": ") + + def decide(self, pot, min_raise, flop, turn, river, other_player,endgame=False): + + in_bet = '' + + if not self.brain: + in_bet = self.human_play(pot,min_raise, flop, turn, river, other_player) + + else: + self.record_info(pot,min_raise,flop,turn,river,other_player) + self.IN.write("MOVE \n"); self.IN.flush() + in_bet = self.OUT.readline().strip() + + if endgame: return False + + if in_bet.isalpha(): + in_bet = in_bet.upper() + if in_bet == 'A': in_bet = self.cash + elif in_bet == 'C': in_bet = self.owe + else : self.FOLD = True + else: + try : in_bet = int(in_bet) + except: self.FOLD = True + + if self.FOLD: return False + + if in_bet >= self.cash or in_bet == self.owe or in_bet >= min_raise: + out_bet = self.bet(in_bet, other_player) + other_player.owe += out_bet + return out_bet + + # Bets between whats owed and min_raise are considered a call + if in_bet >= self.owe and in_bet < min_raise: + out_bet = self.bet(self.owe, other_player) + other_player.owe += out_bet + return out_bet + + # Illegal bets will be counted as folds! + GP("ACTION Player ", self.name, "bets ", str(in_bet), " illegally and FOLDS. Valid bets are ", str(self.owe), " or anything >= ", min_raise) + self.FOLD = True + return False + + +def GP(*S): GLOBAL_TXT.append(''.join(map(str,S))) +def returnGP(): return GLOBAL_TXT + +def hand_judgement(A,B, board, pot): + if A.FOLD: + GP("ACTION Player ", A.name, " folds" ) + GP("ACTION Player ", B.name, " wins: ", pot) + B.cash += pot + return GLOBAL_TXT + + elif B.FOLD: + GP("ACTION Player ", B.name, "folds") + GP("ACTION Player ", A.name, "wins: ", pot) + A.cash += pot + return GLOBAL_TXT + + S = HOLDEM_score(A, B, board) + + if S == 1: + GP("ACTION Player ", A.name, "wins: ", pot) + A.cash += pot + return GLOBAL_TXT + + elif S ==-1: + GP( "ACTION Player ", B.name, "wins: ", pot) + B.cash += pot + return GLOBAL_TXT + + elif S == 0: + GP("ACTION Split pot ") + split_pot, carry = pot/2, pot%2 + A.cash += split_pot + carry + B.cash += split_pot + return GLOBAL_TXT + +def checkFOLD(A,B): + if A.FOLD or B.FOLD: return True + return False + +def betting_round(P,pot,min_raise,flop,turn,river): + for player in P: + player.option = True + + while((P[0].owe>0 or P[1].owe>0) or (P[0].option or P[1].option) and (P[0].cash)): + action = P[0].decide(pot, min_raise, flop,turn,river, P[-1]) + P[0].option = False + + if action >= min_raise: min_raise = 2*action + if checkFOLD(P[0],P[1]): return pot + + pot += action + P = [P[-1]] + P[:-1] # Cycle the player order + return pot + + +def gameplay(DECK, A, B, smallB, ): + global GLOBAL_TXT + + # Shuffle the deck and deal two cards to each player + shuffle(DECK) + + A.hole = [DECK[n] for n in xrange(2) ] + B.hole = [DECK[n] for n in xrange(2,4)] + board = [DECK[n] for n in xrange(4,9)] + + flop, turn, river = '', '', '' + GLOBAL_TXT = [] + + pot = 0 + A.owe = 2*smallB + B.owe = smallB + A.FOLD, B.FOLD = False, False + + # Handle the case if a player can't post the blinds completely, ALL_IN + if B.owe > B.cash: + pot += B.bet(B.owe, A) + pot += A.bet(pot, B) + return hand_judgement(A,B,board,pot) + elif A.owe > A.cash: + pot += A.bet(A.owe, B) + pot += B.bet(pot, A) + return hand_judgement(A,B,board,pot) + + # Both players can post the blinds + pot += A.bet(A.owe, B) + pot += B.bet(B.owe, A) + + # PRE-FLOP ACTION - Player B is small blind, first to act + B.owe += smallB + A.owe -= smallB + min_raise = smallB*4 + play_order = [B,A] + pot = betting_round(play_order,pot,min_raise,flop,turn,river) + if checkFOLD(A,B): return hand_judgement(A,B,board,pot) + if not A.cash or not B.cash: return hand_judgement(A,B,board,pot) + + # FLOP ACTION - Player A is now first to act + flop = board[:3] + GP( "ACTION FLOP ", pp_hand(flop) ) + A.owe, B.owe = 0, 0 + min_raise = smallB*2 + play_order = [A,B] + pot = betting_round(play_order,pot,min_raise,flop,turn,river) + if checkFOLD(A,B): return hand_judgement(A,B,board,pot) + if not A.cash or not B.cash: return hand_judgement(A,B,board,pot) + + # TURN ACTION + turn = board[3:4] + GP( "ACTION TURN ", pp_hand(turn) ) + A.owe, B.owe = 0, 0 + play_order = [A,B] + pot = betting_round(play_order,pot,min_raise,flop,turn,river) + if checkFOLD(A,B): return hand_judgement(A,B,board,pot) + if not A.cash or not B.cash: return hand_judgement(A,B,board,pot) + + # RIVER ACTION + river = board[4:5] + GP( "ACTION RIVER ", pp_hand(river)) + A.owe, B.owe = 0, 0 + play_order = [A,B] + pot = betting_round(play_order,pot,min_raise,flop,turn,river) + if checkFOLD(A,B): return hand_judgement(A,B,board,pot) + + # SHOWDOWN! + return hand_judgement(A,B,board,pot) diff --git a/PBOT.py b/PBOT.py new file mode 100644 index 0000000..fdcb384 --- /dev/null +++ b/PBOT.py @@ -0,0 +1,63 @@ +import popen2 +from DECK import * +from GAMEPLAY import * +global GLOBAL_TXT +#import psyco; psyco.full() + +start_stack = 1000 +blinds = [1,2,4,8,16,25,37,50] +hand_clock = 20 + +# Command line arguments +import sys + +try : A = player(sys.argv[1],sys.argv[1]) +except: A = player('Meg') +try : B = player(sys.argv[2], sys.argv[2]) +except: B = player('Jack') +try : tournament_N = int(sys.argv[3]) +except: tournament_N = 1 + +P = [A,B] +for n in xrange(tournament_N): + A.cash = start_stack + B.cash = start_stack + + hand_count,b = 0, 0 + + while A.cash > 0 and B.cash > 0: + hand_count += 1 + + if hand_count % hand_clock==0: + b = b+1 if b < len(blinds)-1 else len(blinds)-1 + + GLOBAL_TXT = gameplay(DECK, P[0],P[1], blinds[b]) + + # Allow the players to view the end result + board = [DECK[n] for n in xrange(4,9)] + flop,turn,river = board[:3], board[3:4], board[4:5] + if not A.FOLD and not B.FOLD: + GP("INFO ",A.name, pp_hand(A.hole), pp_score(A), ' ',A.cash) + GP("INFO ",B.name, pp_hand(B.hole), pp_score(B), ' ',B.cash) + GP("INFO GAMEOVER ", hand_count) + for p in P: + if p.brain: + p.GP_FLUSH(returnGP()) + p.GP_BUFFER = [] + + # Human player text + if not A.brain or not B.brain: # or True: + for g in GLOBAL_TXT: print g + print "INFO BOARD ", pp_hand([DECK[n] for n in xrange(4,9)]) + + P = [P[-1]] + P[:-1] # Cycle the player order + + if A.cash: print A.name, hand_count + else : print B.name, hand_count + +for p in P: + if p.brain: p.die() # Kill the players! + + + + diff --git a/combinations.py b/combinations.py new file mode 100644 index 0000000..14251cf --- /dev/null +++ b/combinations.py @@ -0,0 +1,26 @@ +from __future__ import generators + +def xcombinations(items, n): + if n==0: yield [] + else: + for i in xrange(len(items)): + for cc in xcombinations(items[:i]+items[i+1:],n-1): + yield [items[i]]+cc + +def xuniqueCombinations(items, n): + if n==0: yield [] + else: + for i in xrange(len(items)): + for cc in xuniqueCombinations(items[i+1:],n-1): + yield [items[i]]+cc + +def xselections(items, n): + if n==0: yield [] + else: + for i in xrange(len(items)): + for ss in xselections(items, n-1): + yield [items[i]]+ss + +def xpermutations(items): + return xcombinations(items, len(items)) + diff --git a/p1.py b/p1.py new file mode 100755 index 0000000..7b9e762 --- /dev/null +++ b/p1.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +import sys +import os + +IN, OUT = sys.stdin, sys.stdout + +FOUT = open("test_anyAce.txt",'a') +allin = False + +while True: + std_in = IN.readline().strip() + if std_in: + FOUT.write(std_in+'\n') + + std_in = std_in.split(' ') + try : + tag = std_in[0] + type = std_in[1] + data = std_in[2:] + except: + #FOUT.write(str(std_in)) + tag = std_in[0] + + #FOUT.write(tag+' '+type+' '+str(data)+' '+'\n') + if tag == "END" : FOUT.close(); exit() + if tag == "MOVE": + # You must return a valid bet here + if allin: OUT.write("A\n") + else : OUT.write("f\n") + + OUT.flush() + allin = False + + elif tag == "INFO" and type == "HOLE": + # Handle new information + # Save info to a file and go all in on any Ace + h1, h2 = data[-1], data[-2] + #FOUT.write(h1+h2+'\n') + + if h1[0]=='A' or h2[0]=='A': allin = True diff --git a/p2.py b/p2.py new file mode 100755 index 0000000..6377776 --- /dev/null +++ b/p2.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +import sys +import os + +IN, OUT = sys.stdin, sys.stdout + +FOUT = open("test_anyPair.txt",'w') +allin = False + +while True: + std_in = IN.readline().strip() + if std_in: + std_in = std_in.split(' ') + try : + tag = std_in[0] + type = std_in[1] + data = std_in[2:] + except: + FOUT.write(str(std_in)) + tag = std_in[0] + + #FOUT.write(tag+' '+type+' '+str(data)+' '+'\n') + + if tag == "MOVE": + # You must return a valid bet here + if allin: OUT.write("A\n") + else : OUT.write("f\n") + OUT.flush() + allin = False + + elif tag == "INFO" and type == "HOLE": + # Handle new information + # Save info to a file and go all in on any pair + h1, h2 = data[-1], data[-2] + + if h1[0] == h2[0] and h1[0]=="A": allin = True + + + + + + + + + + -- 2.26.2