Skip to content

Commit

Permalink
Some refactoring, reqs.txt, 3betpotFAST.cfr, black/flake8
Browse files Browse the repository at this point in the history
  • Loading branch information
dpmaloney committed Aug 31, 2023
1 parent 252e586 commit f7c29cd
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 88 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ python/__pycache__/
run.log
script.txt
.vscode/
/*.cfr
*.cfr
!3betpotFAST.cfr
12 changes: 9 additions & 3 deletions python/misc/backup_pio_solves.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ def backup_pio_solves(
num_overwritten += 1
if trial_run:
print(
f"{OVERWRITE} {source_file} => {backup_file} (trial run)"
f"{OVERWRITE} {source_file} => {backup_file} (trial"
" run)"
)
pass
else:
Expand Down Expand Up @@ -176,14 +177,19 @@ def main():
parser.add_argument(
"--offset",
default=None,
help="Common offset from the source and backup location to backup (this will ony backup files within this subdirectory)",
help=(
"Common offset from the source and backup location to backup (this will ony"
" backup files within this subdirectory)"
),
)

parser.add_argument(
"--skip",
nargs="+",
default=[],
help="Skip these subdirectories (listed as offsets from the `source` directory)",
help=(
"Skip these subdirectories (listed as offsets from the `source` directory)"
),
)
parser.add_argument(
"--extensions", nargs="+", default=[".cfr"], help="File extensions to backup"
Expand Down
5 changes: 4 additions & 1 deletion python/misc/compare_sizes_evs.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ def parse_args():
parser.add_argument(
"root_dir",
type=str,
help="Root directory of the solve DBs: should contain subdirectories, each of which contain cfr files",
help=(
"Root directory of the solve DBs: should contain subdirectories, each of"
" which contain cfr files"
),
)
parser.add_argument("--solver_path", type=str, default=PATH)
parser.add_argument("--solver_executable", type=str, default=EXECUTABLE)
Expand Down
138 changes: 73 additions & 65 deletions python/nodelock.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ def parse_args() -> Namespace:
"--output",
"-o",
default=None,
help="where to write to file (default is change 'X.cfr' to 'X_overfolded.cfr' to the end of the original filename)",
help=(
"where to write to file (default is change 'X.cfr' to 'X_overfolded.cfr' to"
" the end of the original filename)"
),
)
parser.add_argument(
"--save_type", default="small", help="normal, small, or very_small"
Expand Down Expand Up @@ -164,10 +167,7 @@ def main():
solver.rebuild_forgotten_streets()
print("DONE")

if args.disable_script_optimization:
script_builder = None
else:
script_builder = ScriptBuilder()
script_builder = None if args.disable_script_optimization else ScriptBuilder()
print("Locking overfolds...")
t0 = time.time()
locked_node_ids = nodelock_utils.lock_overfolds(
Expand All @@ -180,66 +180,7 @@ def main():
print(f"Finished in {t1-t0:1f} seconds")

if not args.unlock_parent_nodes:
# Now, add all parent nodes to be locked to ensure that the solver
# can't adjust its strategy on previous streets to avoid being
# exploited

# To do this we:
# 1. Get all the lines associated with the locked nodes
# 2. Get all the ancestor nodes of those lines that belong
# to the locked player
# 3. Expand those to all nodes
# 4. Lock those nodes

# This is not quite correct, but it's good enough for now. The correct
# way to do this would be to use a trie and store all nodes in the trie.
# then we could traverse the trie backwards

# We use a set to deduplicate

locker = solver
if script_builder is not None:
locker = script_builder

lines_of_locked_nodes: Set[Line] = set()
for node_id in locked_node_ids:
lines_of_locked_nodes.add(node_id_to_line(node_id))

print("Gathering parent nodes...")
parent_lines = set()
for line in lines_of_locked_nodes:
p = line.get_current_player_previous_action()
while p is not None:
parent_lines.add(p)
p = p.get_current_player_previous_action()

parent_node_ids = []
for line in parent_lines:
parent_node_ids += line.get_node_ids(dead_cards=board)

num_node_ids = len(parent_node_ids)

t0 = time.time()
print(f"Locking {len(parent_node_ids):,} parent nodes")
for i, node_id in enumerate(parent_node_ids):
if node_id not in locked_node_ids:
locker.lock_node(node_id)
if (i + 1) % 100 == 0:
print(
f"\r{i+1}/{num_node_ids} ({100.0 * (i+1)/num_node_ids:.1f}%)",
end="",
)
print(f"\r{num_node_ids}/{num_node_ids} (100.0%)")

if script_builder is not None:
print("Writing and running locking scripts...")
script_builder.write_script(osp.abspath("locking_script.txt"))
t2 = time.time()
solver.load_script_silent(osp.abspath("locking_script.txt"))
t3 = time.time()
print(f"Ran script in {t3-t2:.1f} seconds")
t1 = time.time()
print(f"Finished locking parent nodes in {t1-t0:.1f} seconds")
lock_parent_nodes(solver, script_builder, locked_node_ids, board)
# Now, solve!
print("Solving...")
print(
Expand All @@ -255,5 +196,72 @@ def main():
solver.dump_tree(filename=output, save_type=args.save_type)



def lock_parent_nodes(solver, script_builder, locked_node_ids, board):
# Now, add all parent nodes to be locked to ensure that the solver
# can't adjust its strategy on previous streets to avoid being
# exploited

# To do this we:
# 1. Get all the lines associated with the locked nodes
# 2. Get all the ancestor nodes of those lines that belong
# to the locked player
# 3. Expand those to all nodes
# 4. Lock those nodes

# This is not quite correct, but it's good enough for now. The correct
# way to do this would be to use a trie and store all nodes in the trie.
# then we could traverse the trie backwards

# We use a set to deduplicate

locker = solver
if script_builder is not None:
locker = script_builder

lines_of_locked_nodes: Set[Line] = {
node_id_to_line(node_id) for node_id in locked_node_ids
}
print("Gathering parent nodes...")
parent_lines = set()
for line in lines_of_locked_nodes:
p = line.get_current_player_previous_action()
while p is not None:
parent_lines.add(p)
p = p.get_current_player_previous_action()

parent_node_ids = []
for line in parent_lines:
parent_node_ids += line.get_node_ids(dead_cards=board)

num_node_ids = len(parent_node_ids)

t0 = time.time()
print(f"Locking {len(parent_node_ids):,} parent nodes")
for i, node_id in enumerate(parent_node_ids):
if node_id not in locked_node_ids:
locker.lock_node(node_id)
if (i + 1) % 100 == 0:
print(
f"\r{i+1}/{num_node_ids} ({100.0 * (i+1)/num_node_ids:.1f}%)",
end="",
)
print(f"\r{num_node_ids}/{num_node_ids} (100.0%)")

if script_builder is not None:
run_script(script_builder, solver)
t1 = time.time()
print(f"Finished locking parent nodes in {t1-t0:.1f} seconds")


def run_script(script_builder, solver):
print("Writing and running locking scripts...")
script_builder.write_script(osp.abspath("locking_script.txt"))
t2 = time.time()
solver.load_script_silent(osp.abspath("locking_script.txt"))
t3 = time.time()
print(f"Ran script in {t3-t2:.1f} seconds")


if __name__ == "__main__":
main()
25 changes: 15 additions & 10 deletions python/nodelock_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def lock_overfold_at_node_id(
pos = node.get_position()
if pos is None:
return False
pot = node.pot[2]
# pot = node.pot[2]

put_into_pot_by_player = node.pot[0] if pos == "OOP" else node.pot[1]
# max_ev_to_fold = max_ev_threshold * pot
Expand Down Expand Up @@ -101,18 +101,18 @@ def lock_overfold_at_node_id(

target_fold_freq = fold_freq + amount

if target_fold_freq > 1:
# print("WARNING: target_fold_freq > 1")
target_fold_freq = 1
target_fold_freq = min(target_fold_freq, 1)
target_num_combos = target_fold_freq * combos_in_range
num_new_combos_to_fold = target_num_combos - folded_combos

# print("Range has", combos_in_range, "combos")
# print(
# f"Fold {folded_combos:.1f} / {combos_in_range:.1f} ({100 * fold_freq:.2f}%) combos"
# f"Fold {folded_combos:.1f} / {combos_in_range:.1f} ({100 * fold_freq:.2f}%)"
# " combos"
# )
# print(
# f"Target fold {target_num_combos:.1f} / {combos_in_range:.1f} ({100 * target_fold_freq:.2f}%) combos"
# f"Target fold {target_num_combos:.1f} /"
# f" {combos_in_range:.1f} ({100 * target_fold_freq:.2f}%) combos"
# )
# hand_order = solver.show_hand_order()

Expand All @@ -134,17 +134,22 @@ def lock_overfold_at_node_id(
combos_to_fold_at_idx = num_new_combos_to_fold
num_new_combos_to_fold -= combos_to_fold_at_idx
# print(
# f"{hand_order[idx]}: ev: \033[32;1m{ev:.2f}\033[0m pot: \033[32;1m{node.pot}\033[0m"
# f"{hand_order[idx]}: ev: \033[32;1m{ev:.2f}\033[0m pot:"
# f" \033[32;1m{node.pot}\033[0m"
# )
# print(
# f" #combos: {num_combos_at_idx:3.3f}\t fold_freq: {fold_freqs[idx]:3.3f}\t folded: {folded_combos_at_idx:.3f}\t unfolded: {num_combos_at_idx - folded_combos_at_idx:3.3f}"
# f" #combos: {num_combos_at_idx:3.3f}\t fold_freq:"
# f" {fold_freqs[idx]:3.3f}\t folded: {folded_combos_at_idx:.3f}\t "
# f" unfolded: {num_combos_at_idx - folded_combos_at_idx:3.3f}"
# )
# print(
# f" #fold: {combos_to_fold_at_idx:3.3f}\t reamining: {num_new_combos_to_fold:3.3f}\t of: {num_new_combos_to_fold_bkp:3.3f}"
# f" #fold: {combos_to_fold_at_idx:3.3f}\t reamining:"
# f" {num_new_combos_to_fold:3.3f}\t of: {num_new_combos_to_fold_bkp:3.3f}"
# )
# if ev >= max_ev_to_fold:
# print(
# f"Warning: Current hand {hand_order[idx]} has ev {ev} >= max ev to fold {max_ev_to_fold}"
# f"Warning: Current hand {hand_order[idx]} has ev {ev} >= max ev to"
# f" fold {max_ev_to_fold}"
# )
# break
indices_and_amounts_of_combos_to_fold.append((idx, combos_to_fold_at_idx))
Expand Down
7 changes: 2 additions & 5 deletions python/pio_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ def actions_to_streets(
# to the number of streets. `streets` has an entry for root, so
# the maximal length of streets is 4.
#
# Consider if `streets = [['r', '0'], ['c', 'b120', 'c']]`. If this line starts on the
# Consider if `streets = [['r', '0'], ['c', 'b120', 'c']]`.
# If this line starts on the
#
# then we need to add a street (FLOP + 2 = 3 < 4)
streets.append([])
Expand Down Expand Up @@ -539,10 +540,6 @@ def is_oop(line: Line) -> bool:
return line.is_oop()


def is_facing_bet(line: Line) -> bool:
return line.is_facing_bet()


def is_terminal(line: Line) -> bool:
return line._is_terminal

Expand Down
5 changes: 4 additions & 1 deletion python/pyosolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ def __init__(self, raw_node_data: str):
self.flags = tuple(items[5].split(":")[1].strip().split(" "))

def __repr__(self):
return f"Node({self.node_id}, {self.node_type}, {self.board}, {self.pot}, {self.num_children}, {self.flags})"
return (
f"Node({self.node_id}, {self.node_type}, {self.board}, {self.pot},"
f" {self.num_children}, {self.flags})"
)

def __str__(self):
return self._raw_node_data
Expand Down
5 changes: 3 additions & 2 deletions python/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from os import path as osp

path = osp.join(osp.dirname(__file__), "..", "resources", "trees", "Ks7h2c.cfr")
path = osp.join(osp.dirname(__file__), "..", "resources", "trees", "3betpotFAST.cfr")

parser = ArgumentParser()
parser.add_argument("--path", "-p", type=str, default=path)
Expand Down Expand Up @@ -91,5 +91,6 @@
total_nodes = sum([len(nodes) for nodes in nodes_per_line])

print(
f"Expanded all lines to {total_nodes} nodes in {t_expand_all_nodes - t_0:.2f} seconds"
f"Expanded all lines to {total_nodes} nodes in"
f" {t_expand_all_nodes - t_0:.2f} seconds"
)
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pandas
ansi
Binary file added resources/trees/3betpotFAST.cfr
Binary file not shown.

0 comments on commit f7c29cd

Please sign in to comment.