Skip to content

Commit

Permalink
API-updates and generate PBN from game.py
Browse files Browse the repository at this point in the history
  • Loading branch information
ThorvaldAagaard committed Apr 20, 2024
1 parent 5f6d44b commit 8d5b2ac
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ scripts/training/data/WBC/play.txt
scripts/match/bidding/default
UCBC 2024/MvsM/models/1 Mill SAYC.ben
scripts/training/bidding/1 Mill SAYC.ben
scripts/training/data/GIB-Thorvald.ben
scripts/training/data/BEN-UCBC.ben
14 changes: 6 additions & 8 deletions src/bots.py
Original file line number Diff line number Diff line change
Expand Up @@ -1199,8 +1199,6 @@ def next_card_softmax(self, trick_i):
def pick_card_after_pimc_eval(self, trick_i, leader_i, current_trick, players_states, card_dd, bidding_scores, quality, samples, play_status):
t_start = time.time()
card_softmax = self.next_card_softmax(trick_i)
#if trick_i == 4:
# xx
if self.verbose:
print(f'Next card response time: {time.time() - t_start:0.4f}')

Expand Down Expand Up @@ -1231,9 +1229,9 @@ def pick_card_after_pimc_eval(self, trick_i, leader_i, current_trick, players_st
))

if self.models.matchpoint:
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(x[1].expected_tricks_dd, 1), round(x[1].insta_score, 2), -x[0]), reverse=True)
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (int(x[1].expected_tricks_dd * 10) / 10, round(x[1].insta_score, 2), -x[0]), reverse=True)
else:
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(5*x[1].p_make_contract, 1), round(x[1].expected_tricks_dd, 1), round(x[1].insta_score, 2), -x[0]), reverse=True)
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(5*x[1].p_make_contract, 1), int(x[1].expected_tricks_dd * 10), round(x[1].insta_score, 2), -x[0]), reverse=True)

candidate_cards = [card for _, card in candidate_cards]

Expand Down Expand Up @@ -1300,20 +1298,20 @@ def pick_card_after_dd_eval(self, trick_i, leader_i, current_trick, players_stat
# We should probably also consider bidding_scores in this
# If we have bad quality of samples we should probably just use the neural network
if valid_bidding_samples >= 0:
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(5*x[1].p_make_contract, 1), round(x[1].expected_tricks_dd, 1), round(x[1].insta_score, 2), -x[0]), reverse=True)
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(5*x[1].p_make_contract, 1), int(x[1].expected_tricks_dd * 10) / 10, round(x[1].expected_score_dd, 1), round(x[1].insta_score, 2), -x[0]), reverse=True)
candidate_cards = [card for _, card in candidate_cards]
who = "NN"
else:
if self.models.use_biddingquality_in_eval:
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: ( round(x[1].insta_score, 2), round(5*x[1].p_make_contract, 1), round(x[1].expected_tricks_dd, 1), -x[0]), reverse=True)
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: ( round(x[1].insta_score, 2), round(5*x[1].p_make_contract, 1), int(x[1].expected_tricks_dd * 10) / 10, -x[0]), reverse=True)
candidate_cards = [card for _, card in candidate_cards]
candidate_cards2 = sorted(enumerate(candidate_cards), key=lambda x: (round(x[1].expected_score_dd, 1), round(x[1].insta_score, 2), round(x[1].expected_tricks_dd, 1), -x[0]), reverse=True)
candidate_cards2 = sorted(enumerate(candidate_cards), key=lambda x: (round(x[1].expected_score_dd, 1), round(x[1].insta_score, 2), int(x[1].expected_tricks_dd * 10) / 10, -x[0]), reverse=True)
candidate_cards2 = [card for _, card in candidate_cards]
if candidate_cards[0].expected_score_dd < 0 and candidate_cards2[0].expected_score_dd:
candidate_cards = candidate_cards2
who = "DD"
else:
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(5*x[1].p_make_contract, 1), round(x[1].insta_score, 2), round(x[1].expected_tricks_dd, 1), -x[0]), reverse=True)
candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (round(5*x[1].p_make_contract, 1), round(x[1].insta_score, 2), int(x[1].expected_tricks_dd * 10) / 10, -x[0]), reverse=True)
candidate_cards = [card for _, card in candidate_cards]
who = "Make"

Expand Down
24 changes: 0 additions & 24 deletions src/dools.py

This file was deleted.

9 changes: 9 additions & 0 deletions src/frontend/api.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ <h1>Enter Board information</h1>
processLinCommand(command, param);
startIndex = closePipeIndex + 1;
}
// Replace "D" with "X" and "RD" with "XX"
bidSequence = bidSequence.map(item => {
if (item === "D") {
return "X";
} else if (item === "RD") {
return "XX";
}
return item; // Keep other items unchanged
});
document.getElementById('biddingInput').value = bidSequence.join('-').toUpperCase()
const seat = document.getElementById('seatInput').value;
const dealer = "NESW".indexOf(document.getElementById('dealerInput').value);
Expand Down
60 changes: 59 additions & 1 deletion src/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def set_deal(self, board_number, deal_str, auction_str, play_only = None, biddin
self.vuln_ns = self.deal_data.vuln_ns
self.vuln_ew = self.deal_data.vuln_ew
self.trick_winners = []
self.tricks_taken = 0

# Now you can use hash_integer as a seed
hash_integer = calculate_seed(deal_str)
Expand Down Expand Up @@ -232,7 +233,57 @@ async def run(self):
'pbn': self.deal_str,
'dict': self.to_dict()
}))


def asPBN(self):
dealer = "NESW"[self.dealer_i]
pbn_str = ""
pbn_str += '% PBN 2.1'
pbn_str += '% EXPORT'
pbn_str += '[Event ""]\n'
pbn_str += '[Site ""]\n'
pbn_str += f'[Date "{datetime.datetime.now().date().isoformat()}"]'
pbn_str += f'[Board "{self.board_number}"]\n'
pbn_str += '[West "BEN"]\n'
pbn_str += '[North "BEN"]\n'
pbn_str += '[East "BEN"]\n'
pbn_str += '[South "BEN"]\n'
pbn_str += f'[Dealer "{dealer}"]\n'
if self.vuln_ns and self.vuln_ew:
pbn_str += '[Vulnerable "All"]\n'
if self.vuln_ns and not self.vuln_ew:
pbn_str += '[Vulnerable "NS"]\n'
if not self.vuln_ns and self.vuln_ew:
pbn_str += '[Vulnerable "EW"]\n'
if not self.vuln_ns and not self.vuln_ew:
pbn_str += '[Vulnerable "None"]\n'
pbn_str += f'[Deal "N:{self.deal_str}"]\n'
pbn_str += '[Scoring "IMP"]\n'
pbn_str += f'[Declarer "{self.contract[-1]}"]\n'
pbn_str += f'[Contract "{self.contract[:-1]}"]\n'
pbn_str += f'[Result "{self.tricks_taken}"]\n'
pbn_str += f'[Auction "{dealer}"]\n'
for i, b in enumerate(self.bid_responses, start=1):
pbn_str += (b.bid)
if i % 4 == 0:
pbn_str += "\n"
else:
pbn_str += " "
# Add an additional line break if the total number of bids is not divisible by 4
if i % 4 != 0:
pbn_str += "\n"
pbn_str += '[Play ""]\n'
for i, c in enumerate(self.card_responses, start=1):
pbn_str += c.card.symbol()
if i % 4 == 0:
pbn_str += "\n"
else:
pbn_str += " "
pbn_str += '[HomeTeam ""]\n'
pbn_str += '[VisitTeam ""]\n'
pbn_str += '[ScoreIMP ""]\n'
pbn_str += '\n'
return pbn_str

def to_dict(self):
result = {
'timestamp': time.time(),
Expand Down Expand Up @@ -630,6 +681,7 @@ async def play(self, contract, strain_i, decl_i, auction, opening_lead52):
pprint.pprint(list(zip(decoded_tricks52, trick_won_by)))

self.trick_winners = trick_won_by
self.tricks_taken = card_players[3].n_tricks_taken

# Print contract and result
print("Contract: ",self.contract, card_players[3].n_tricks_taken, "tricks")
Expand Down Expand Up @@ -734,6 +786,7 @@ async def main():
parser.add_argument("--config", default=f"{base_path}/config/default.conf", help="Filename for configuration")
parser.add_argument("--playonly", type=bool, default=False, help="Just play, no bidding")
parser.add_argument("--biddingonly", type=bool, default=False, help="Just bidding, no play")
parser.add_argument("--outputpbn", default="", help="Save each board to this PBN file")
parser.add_argument("--verbose", type=bool, default=False, help="Output samples and other information during play")
parser.add_argument("--seed", type=int, help="Seed for random")

Expand All @@ -745,6 +798,7 @@ async def main():
playonly = args.playonly
biddingonly = args.biddingonly
seed = args.seed
outputpbn = args.outputpbn
boards = []

if args.boards:
Expand Down Expand Up @@ -829,6 +883,10 @@ async def main():
print('{1} Board played in {0:0.1f} seconds.'.format(time.time() - t_start, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
db[uuid.uuid4().hex] = deal

if outputpbn != "":
with open(outputpbn, "a") as file:
file.write(driver.asPBN())

if not auto:
user_input = input("\n Q to quit or any other key for next deal ")
if user_input.lower() == "q":
Expand Down
27 changes: 22 additions & 5 deletions src/gameapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import json
import os
import logging
import uuid
import shelve

# Set logging level to suppress warnings
logging.getLogger().setLevel(logging.ERROR)
Expand Down Expand Up @@ -307,6 +309,9 @@ def home():
@app.route('/bid')
def bid():
try:
if request.args.get("tournament"):
matchpoint = request.args.get("tournament").lower() == "mp"
models.matchpoint = matchpoint
# First we extract our hand
hand = request.args.get("hand").replace('_','.')
seat = request.args.get("seat")
Expand Down Expand Up @@ -334,6 +339,8 @@ def bid():
hint_bot = BotBid(vuln, hand, models, sampler, position, dealer_i, verbose)
bid = hint_bot.bid(auction)
print("Bidding: ",bid.bid)
with shelve.open(f"{base_path}/gameapibiddb") as db:
db[uuid.uuid4().hex] = bid.to_dict()
return json.dumps(bid.to_dict())
except Exception as e:
print(e)
Expand All @@ -343,6 +350,9 @@ def bid():
@app.route('/lead')
def lead():
try:
if request.args.get("tournament"):
matchpoint = request.args.get("tournament").lower() == "mp"
models.matchpoint = matchpoint
# First we extract our hand and seat
hand = request.args.get("hand").replace('_','.')
seat = request.args.get("seat")
Expand All @@ -365,6 +375,8 @@ def lead():
card_resp.who = user
print("Leading:", card_resp.card.symbol())
result = card_resp.to_dict()
with shelve.open(f"{base_path}/gameapiplaydb") as db:
db[uuid.uuid4().hex] = result
return json.dumps(result)
except Exception as e:
print(e)
Expand All @@ -374,7 +386,10 @@ def lead():

@app.route('/play')
async def frontend():
#try:
try:
if request.args.get("tournament"):
matchpoint = request.args.get("tournament").lower() == "mp"
models.matchpoint = matchpoint
# First we extract the hands and seat
hand_str = request.args.get("hand").replace('_','.')
dummy_str = request.args.get("dummy").replace('_','.')
Expand Down Expand Up @@ -432,12 +447,14 @@ async def frontend():
card_resp = await play_api(dealer_i, vuln[0], vuln[1], hands, models, sampler, contract, strain_i, decl_i, auction, cards, cardplayer, verbose)
print("Playing:", card_resp.card.symbol())
result = card_resp.to_dict()
with shelve.open(f"{base_path}/gameapiplaydb") as db:
db[uuid.uuid4().hex] = result
#print(json.dumps(result))
return json.dumps(result)
# except Exception as e:
# print(e)
# error_message = "An error occurred: {}".format(str(e))
# return jsonify({"error": error_message}), 400 # HTTP status code 500 for internal server error
except Exception as e:
print(e)
error_message = "An error occurred: {}".format(str(e))
return jsonify({"error": error_message}), 400 # HTTP status code 500 for internal server error

def get_binary_contract(position, vuln, hand_str, dummy_str):
X = np.zeros(2 + 2 * 32, dtype=np.float16)
Expand Down

0 comments on commit 8d5b2ac

Please sign in to comment.