fractional undos are probably a terrible idea

This commit is contained in:
Sander Land committed 2020-02-20 21:26:50 +01:00
1 parent 144e7b8331
commit 847eb10c7d
2 files changed
+25 -11

No files matched your search

+3
View File
@@ -1,4 +1,5 @@
import os import os
import random
from datetime import datetime from datetime import datetime
@@ -26,6 +27,7 @@ class Move:
self.x_comment = "" self.x_comment = ""
self.auto_undid = False self.auto_undid = False
self.move_number = 0 self.move_number = 0
self.undo_threshold = random.random() # for fractional undos, store the random threshold in the move itself for consistency
def __repr__(self): def __repr__(self):
return f"{Move.PLAYERS[self.player]}{self.gtp()}" return f"{Move.PLAYERS[self.player]}{self.gtp()}"
@@ -82,6 +84,7 @@ class Move:
text += f"Move {self.move_number}: {self.bw_player()} {self.gtp()} {'(AI Move)' if self.robot else ''}\n" text += f"Move {self.move_number}: {self.bw_player()} {self.gtp()} {'(AI Move)' if self.robot else ''}\n"
text += self.x_comment text += self.x_comment
print("xc = ", self.x_comment)
if self.analysis_ready: if self.analysis_ready:
score, _, temperature = self.temperature_stats score, _, temperature = self.temperature_stats
+22 -11
View File
@@ -1,6 +1,7 @@
import copy import copy
import json import json
import os import os
import math
import random import random
import re import re
import shlex import shlex
@@ -109,7 +110,7 @@ class EngineControls(GridLayout):
if self.eval.active(current_move.player): if self.eval.active(current_move.player):
self.show_evaluation_stats(current_move) self.show_evaluation_stats(current_move)
if current_move.analysis_ready and current_move.parent and current_move.parent.analysis_ready and not current_move.children: if current_move.analysis_ready and current_move.parent and current_move.parent.analysis_ready and not current_move.children and not current_move.x_comment:
# handle automatic undo # handle automatic undo
if self.auto_undo.active(current_move.player) and not self.ai_auto.active(current_move.player) and not current_move.auto_undid: if self.auto_undo.active(current_move.player) and not self.ai_auto.active(current_move.player) and not current_move.auto_undid:
ts = self.train_settings ts = self.train_settings
@@ -117,14 +118,18 @@ class EngineControls(GridLayout):
eval = max(current_move.evaluation, current_move.outdated_evaluation or 0) eval = max(current_move.evaluation, current_move.outdated_evaluation or 0)
points_lost = (current_move.parent or current_move).temperature_stats[2] * (1 - eval) points_lost = (current_move.parent or current_move).temperature_stats[2] * (1 - eval)
if eval < ts["undo_eval_threshold"] and points_lost >= ts["undo_point_threshold"]: if eval < ts["undo_eval_threshold"] and points_lost >= ts["undo_point_threshold"]:
current_move.auto_undid = True if self.num_undos(current_move) == 0:
self.board.undo() current_move.x_comment = f"Move was below threshold, but no undo granted (probability is {ts['num_undo_prompts']:.0%}).\n"
if len(current_move.parent.children) >= ts["num_undo_prompts"] + 1: self.update_evaluation()
best_move = sorted([m for m in current_move.parent.children], key=lambda m: -(m.evaluation_info[0] or 0))[0] else:
best_move.x_comment = f"Automatically played as best option after max. {ts['num_undo_prompts']} undo(s).\n" current_move.auto_undid = True
self.board.play(best_move) self.board.undo()
self.update_evaluation() if len(current_move.parent.children) >= ts["num_undo_prompts"] + 1:
return best_move = sorted([m for m in current_move.parent.children], key=lambda m: -(m.evaluation_info[0] or 0))[0]
best_move.x_comment = f"Automatically played as best option after max. {ts['num_undo_prompts']} undo(s).\n"
self.board.play(best_move)
self.update_evaluation()
return
# ai player doesn't technically need parent ready, but don't want to override waiting for undo # ai player doesn't technically need parent ready, but don't want to override waiting for undo
current_move = self.board.current_move # this effectively checks undo didn't just happen current_move = self.board.current_move # this effectively checks undo didn't just happen
if self.ai_auto.active(1 - current_move.player) and not self.board.game_ended: if self.ai_auto.active(1 - current_move.player) and not self.board.game_ended:
@@ -162,14 +167,20 @@ class EngineControls(GridLayout):
aimove.x_comment = "AI Balance on, moves considered: " + ", ".join(f"{move} ({aimove.format_score(score)})" for move, score, _ in sel_moves) + "\n" aimove.x_comment = "AI Balance on, moves considered: " + ", ".join(f"{move} ({aimove.format_score(score)})" for move, score, _ in sel_moves) + "\n"
self.play(aimove) self.play(aimove)
def num_undos(self, move):
if self.train_settings["num_undo_prompts"] < 1:
return int(move.undo_threshold < self.train_settings["num_undo_prompts"])
else:
return self.train_settings["num_undo_prompts"]
def _do_undo(self): def _do_undo(self):
if ( if (
self.ai_lock.active self.ai_lock.active
and self.auto_undo.active(self.board.current_move.player) and self.auto_undo.active(self.board.current_move.player)
and len(self.board.current_move.parent.children) > self.train_settings["num_undo_prompts"] and len(self.board.current_move.parent.children) > self.num_undos(self.board.current_move)
and not self.train_settings.get("dont_lock_undos") and not self.train_settings.get("dont_lock_undos")
): ):
self.info.text = f"Can't undo more than {self.train_settings['num_undo_prompts']} time(s) when locked" self.info.text = f"Can't undo this move more than {self.num_undos(self.board.current_move)} time(s) when locked"
return return
self.board.undo() self.board.undo()
self.update_evaluation() self.update_evaluation()