readme update and undo lock option

This commit is contained in:
Sander Land committed 2020-02-15 19:05:55 +01:00
1 parent 136dff4f1c
commit d57e6ce87d
5 files changed
+37 -11

No files matched your search

+18 -2
View File
@@ -1,3 +1,19 @@
Introduction
============
This repository contains tool for playing go with AI feedback aimed at kyu players.
The idea is to give immediate feedback on the many large mistakes we make in terms of inefficient moves.
It is based on the KataGo AI and relies heavily on score estimation rather than win rate.
Some uses include:
* Analyze your games to find the moves that were most costly in terms of points lost.
* Play against AI and get immediate feedback on mistakes with option to retry.
* Play against a stronger player and use the retry option instead of handicap stones.
* Play a match with an evenly matched friend where both players get instant feedback.
![screenshot](https://i.imgur.com/2T2b6qL.png)
Manual
======
@@ -23,7 +39,7 @@ Options
* Undo: automatically undo poor moves for this player and make them try again.
* AI: let the AI control this player. Check both for self-play.
* Show owner: show expected control of territory.
* Lock AI: disallow extra undos, changing hints options, changing auto move, or AI move.
* Lock AI: disallow extra undos, changing hints options, changing auto move, or AI move. Also turns off the option to click on a move to see detailed comments.
* Fast: use a lower number of max visits for evaluation/AI move.
* Balance score: Deliberately make sub-optimal moves as the AI in an attempt to balance the score towawrds a slight win.
@@ -58,7 +74,7 @@ Play
* Click `Analyze`
* Save game
* Click save to get an sgf as `out.sgf` with comments (and a short version in the text box).
* Click save to get an sgf with comments saved in the sgfout/ directory (and a short version in the text box).
Configuration
-------------
+3 -3
View File
@@ -315,8 +315,8 @@ class Board:
return "\n".join("".join(Move.PLAYERS[self.chains[c][0].player] if c >= 0 else "-" for c in l) for l in self.board) + f"\ncaptures: {self.prisoner_count}"
def write_sgf(self, komi, train_settings, file_name=None):
def sgfify(mvs):
return f"(;GM[1]FF[4]SZ[{self.board_size}]KM[{komi}]RU[JP];" + ";".join(mvs) + ")"
def sgfify(mvs, comment=""):
return f"(;GM[1]FF[4]SZ[{self.board_size}]KM[{komi}]RU[JP];" + ";".join(mvs) + (f"C[{comment}])" if comment else "")
def format_move(move, prev_move):
undos = [m for m in prev_move.children if m != move]
@@ -349,4 +349,4 @@ class Board:
pass
with open(file_name, "w") as f:
f.write(sgfify(sgfmoves))
return sgfify(sgfmoves_small)
return sgfify(sgfmoves_small, f"SGF with analysis written to {file_name}")
+2 -1
View File
@@ -39,7 +39,8 @@
"undo_eval_threshold": 0.875,
"undo_point_threshold": 1,
"num_undo_prompts": 1,
"sgf_show_best_move_threshold": 0.95
"sgf_show_best_move_threshold": 0.95,
"dont_lock_undos": false
},
"debug": {
"level": 1
+10 -3
View File
@@ -36,6 +36,7 @@ class EngineControls(GridLayout):
self.komi = 6.5 # loaded from config in init
self.outstanding_analysis_queries = [] # allows faster interaction while kata is starting
self.kata = None
self.query_time = {}
def redraw(self, include_board=False):
if include_board:
@@ -153,7 +154,12 @@ class EngineControls(GridLayout):
self.play(aimove)
def _do_undo(self):
if self.ai_lock.active and self.auto_undo.active(self.board.current_move.player) and len(self.board.current_move.parent.children) > self.train_settings["num_undo_prompts"]:
if (
self.ai_lock.active
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 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"
return
self.board.undo()
@@ -183,8 +189,6 @@ class EngineControls(GridLayout):
while self.outstanding_analysis_queries:
self._send_analysis_query(self.outstanding_analysis_queries.pop(0))
line = self.kata.stdout.readline()
if self.debug:
print("KATA ANALYSIS RECEIVED:", line[:80], "...")
if not line: # occasionally happens?
return
try:
@@ -192,10 +196,13 @@ class EngineControls(GridLayout):
except json.JSONDecodeError as e:
print(f"JSON decode error: '{e}' encountered after receiving input '{line}'")
return
if self.debug:
print(f"[{time.time()-self.query_time.get(analysis['id'],0):.1f}] kata analysis received:", line[:80], "...")
self.board.store_analysis(analysis)
self.update_evaluation()
def _send_analysis_query(self, query):
self.query_time[query["id"]] = time.time()
if self.kata:
self.kata.stdin.write((json.dumps(query) + "\n").encode())
self.kata.stdin.flush()
+4 -2
View File
@@ -53,11 +53,13 @@ class BadukPanWidget(Widget):
yd, yp = self._find_closest(touch.y)
stones_here = [m for m in self.engine.board.stones if m.coords == (xp, yp)]
if stones_here and max(yd, xd) < self.grid_size / 2: # load old comment
self.engine.info.text = stones_here[-1].comment(sgf=True)
self.engine.show_evaluation_stats(stones_here[-1])
if self.engine.debug:
print("\nAnalysis:\n", stones_here[-1].analysis)
print("\nParent Analysis:\n", stones_here[-1].parent.analysis)
if not self.engine.ai_lock.active:
self.engine.info.text = stones_here[-1].comment(sgf=True)
self.engine.show_evaluation_stats(stones_here[-1])
self.ghost_stone = None
self.redraw() # remove ghost