rewinds to start and has keyboard controls
This commit is contained in:
1 parent
190a893bae
commit
144e7b8331
5 files changed
+68
-18
No files matched your search
@@ -50,6 +50,10 @@ Options
|
||||
This can be < 0% in case of suicidal moves, or >100% when Kata did not consider the move before, or further analysis shows it to be better than the best one considered.
|
||||
* Score: How far one player is ahead.
|
||||
|
||||
* Keyboard controls
|
||||
* Arrow up: undo
|
||||
* Arrow down: redo
|
||||
|
||||
Play
|
||||
----
|
||||
|
||||
@@ -70,10 +74,10 @@ Play
|
||||
* Play with a friend with instant feedback and/or undos for both, or see how many stones stronger you are with one undo. (But please play unranked and be honest to your opponent on what you're doing)
|
||||
|
||||
* Analysis
|
||||
* Copy the SGF into the text box. Note that branches are not supported and will lead to strange results.
|
||||
* Choose whether or not to turn on `fast` to make the AI weaker but analyze faster.
|
||||
* Click `Load`
|
||||
* Alternatively click `Load` when the text box is empty to get a file chooser dialog.
|
||||
* Click 'Load' when the text box is empty-ish to get a file chooser dialog. Note that branches are not supported and will lead to strange results.
|
||||
* Select if you want fast analysis or rewinding to the start for reviewing. Note that the 'fast' checkbox still affects speed as well,
|
||||
this is just an additional lowering of visits.
|
||||
* Alternatively copy the SGF into the text box and click 'Load'.
|
||||
|
||||
* Save game
|
||||
* Click save to get an sgf with comments saved in the sgfout/ directory (and a short version in the text box).
|
||||
@@ -94,6 +98,15 @@ The `trainer` block has the following options to tweak:
|
||||
|
||||
The cfg file has additional configuration for kata. In particular, it changes the default to being more exploratory and score-based (and therefore nicer as an opponent, but weaker as analysis tool).
|
||||
|
||||
FAQ
|
||||
===
|
||||
* The program is slow to start!
|
||||
* The first startup of KataGo can be slow, after that it should be much faster.
|
||||
* The program is running too slowly!
|
||||
* Lower the visits count in `config.json` by half or so and try again.
|
||||
* Can I play on sizes other than 9, 13 or 19?
|
||||
* Type in `SZ[n]HA[h]` in the text box and hit 'load' for a game on a n by n board with h handicap stones, but note that the default KataGo does not support sizes above 19x19.
|
||||
|
||||
Contributing
|
||||
============
|
||||
* Feedback and pull requests are both very welcome.
|
||||
|
||||
@@ -74,7 +74,9 @@ class Move:
|
||||
return ""
|
||||
|
||||
if eval and not sgf and self.children: # show undos and on previous move as well while playing
|
||||
text = "".join(f"Auto undid move {m.gtp()} ({-self.temperature_stats[2] * (1-m.evaluation):.1f} pt)\n" for m in self.children if m.auto_undid) + "\n"
|
||||
text = "".join(f"Auto undid move {m.gtp()} ({-self.temperature_stats[2] * (1-m.evaluation):.1f} pt)\n" for m in self.children if m.auto_undid)
|
||||
if text:
|
||||
text += "\n"
|
||||
else:
|
||||
text = ""
|
||||
|
||||
@@ -270,6 +272,14 @@ class Board:
|
||||
self.current_move = self.current_move.parent
|
||||
self._init_chains()
|
||||
|
||||
def redo(self):
|
||||
if self.current_move.children:
|
||||
self.play(self.current_move.children[-1])
|
||||
|
||||
def rewind(self):
|
||||
self.current_move = self.root
|
||||
self._init_chains()
|
||||
|
||||
def place_handicap_stones(self, n_handicaps):
|
||||
near = 3 if self.board_size >= 13 else 2
|
||||
far = self.board_size - 1 - near
|
||||
|
||||
+23
-5
@@ -12,8 +12,11 @@ from queue import Queue
|
||||
|
||||
from kivy.clock import Clock
|
||||
from kivy.storage.jsonstore import JsonStore
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.checkbox import CheckBox
|
||||
from kivy.uix.filechooser import FileChooserListView
|
||||
from kivy.uix.gridlayout import GridLayout
|
||||
from kivy.uix.label import Label
|
||||
from kivy.uix.popup import Popup
|
||||
|
||||
from board import Board, IllegalMoveException, Move
|
||||
@@ -169,6 +172,11 @@ class EngineControls(GridLayout):
|
||||
self.info.text = f"Can't undo more than {self.train_settings['num_undo_prompts']} time(s) when locked"
|
||||
return
|
||||
self.board.undo()
|
||||
self.update_evaluation()
|
||||
|
||||
def _do_redo(self):
|
||||
self.board.redo()
|
||||
self.update_evaluation()
|
||||
|
||||
def _do_init(self, board_size, komi=None):
|
||||
self.board_size = board_size
|
||||
@@ -182,21 +190,29 @@ class EngineControls(GridLayout):
|
||||
for el in [self.ai_lock.checkbox, self.hints.black, self.hints.white, self.ai_auto.black, self.ai_auto.white, self.auto_undo.black, self.auto_undo.white, self.ai_move]:
|
||||
el.disabled = False
|
||||
|
||||
def _do_analyze_sgf(self, sgf):
|
||||
def _do_analyze_sgf(self, sgf, faster=False, rewind=False):
|
||||
sgfprops = {k: v for k, v in re.findall(r"\b(\w+)\[(.*?)\]", sgf)}
|
||||
size = int(sgfprops.get("SZ", self.board_size))
|
||||
sgfmoves = re.findall(r"\b([BW])\[([a-z]{2})\]", sgf)
|
||||
if not sgfmoves and not sgfprops:
|
||||
fileselect_popup = Popup(title="Double Click SGF file to analyze", size_hint=(0.8, 0.8))
|
||||
fc = FileChooserListView(multiselect=False, path=os.path.expanduser("~"), filters=["*.sgf"])
|
||||
blui = BoxLayout(orientation="horizontal", size_hint=(1, 0.1))
|
||||
cbfast = CheckBox(color=(0.95, 0.95, 0.95, 1))
|
||||
cbrewind = CheckBox(color=(0.95, 0.95, 0.95, 1))
|
||||
for widget in [Label(text="Analyze Extra Fast"), cbfast, Label(text="Rewind to start"), cbrewind]:
|
||||
blui.add_widget(widget)
|
||||
bl = BoxLayout(orientation="vertical")
|
||||
bl.add_widget(fc)
|
||||
bl.add_widget(blui)
|
||||
fileselect_popup.add_widget(bl)
|
||||
|
||||
def readfile(files, mouse):
|
||||
fileselect_popup.dismiss()
|
||||
with open(files[0]) as f:
|
||||
self.action("analyze-sgf", f.read())
|
||||
self.action("analyze-sgf", f.read(), cbfast.active, cbrewind.active)
|
||||
|
||||
fc = FileChooserListView(multiselect=False, path=os.path.expanduser("~"), filters=["*.sgf"])
|
||||
fc.on_submit = readfile
|
||||
fileselect_popup.add_widget(fc)
|
||||
fileselect_popup.open()
|
||||
return
|
||||
self._do_init(size, sgfprops.get("KM"))
|
||||
@@ -206,7 +222,9 @@ class EngineControls(GridLayout):
|
||||
if handicap > 0:
|
||||
self._request_analysis(self.board.current_move)
|
||||
for move in moves:
|
||||
self.play(move, faster=(self.ai_fast.active and move != moves[-1]))
|
||||
self.play(move, faster=faster and move != moves[-1])
|
||||
if rewind:
|
||||
self.board.rewind()
|
||||
|
||||
# analysis thread
|
||||
def _analysis_read_thread(self):
|
||||
|
||||
+5
-5
@@ -40,13 +40,14 @@
|
||||
checkbox: checkbox
|
||||
text: ''
|
||||
default_active: False
|
||||
position: (0,0)
|
||||
CheckBoxHintLabel:
|
||||
size_hint: 1,0.45
|
||||
font_size: root.height * 0.2
|
||||
size_hint: 1,0.45 if root.orientation=='vertical' else (0.8,1)
|
||||
font_size: root.height * 0.2 if root.orientation=='vertical' else root.height
|
||||
text: root.text
|
||||
on_press: if not checkbox.disabled: checkbox._do_press()
|
||||
CheckBox:
|
||||
size_hint: 1,0.55
|
||||
size_hint: 1,0.55 if root.orientation=='vertical' else (0.2,1)
|
||||
id: checkbox
|
||||
on_active: root.dispatch('on_active')
|
||||
active: root.default_active
|
||||
@@ -224,7 +225,7 @@
|
||||
id: ai_balance
|
||||
default_active: False
|
||||
CheckBoxHint:
|
||||
size_hint: 0.2, 0.5
|
||||
size_hint: 0.167, 0.5
|
||||
text: 'lock\nai'
|
||||
id: ai_lock
|
||||
on_active: self.checkbox.disabled = hints.black.disabled = hints.white.disabled = ai_auto.black.disabled = ai_auto.white.disabled = auto_undo.black.disabled = auto_undo.white.disabled = ai_move.disabled = True
|
||||
@@ -269,7 +270,6 @@
|
||||
StyledButton:
|
||||
text: 'Load'
|
||||
size_hint: 0.5, 1
|
||||
margin: (0,1)
|
||||
on_press: root.action("analyze-sgf",info.text)
|
||||
GridLayout:
|
||||
size_hint: 1, 0.05
|
||||
|
||||
+12
-3
@@ -2,9 +2,8 @@ import math
|
||||
import signal
|
||||
|
||||
from kivy.app import App
|
||||
from kivy.core.window import Window
|
||||
from kivy.graphics import *
|
||||
from kivy.properties import NumericProperty, ObjectProperty
|
||||
from kivy.uix.floatlayout import FloatLayout
|
||||
from kivy.uix.widget import Widget
|
||||
|
||||
from board import Move
|
||||
@@ -186,7 +185,17 @@ class BadukPanWidget(Widget):
|
||||
|
||||
|
||||
class KaTrainGui(BoxLayout):
|
||||
pass
|
||||
def __init__(self, **kwargs):
|
||||
super(KaTrainGui, self).__init__(**kwargs)
|
||||
self._keyboard = Window.request_keyboard(None, self, "")
|
||||
self._keyboard.bind(on_key_down=self._on_keyboard_down)
|
||||
|
||||
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
|
||||
if keycode[1] == "up":
|
||||
self.controls.action("undo")
|
||||
elif keycode[1] == "down":
|
||||
self.controls.action("redo")
|
||||
return True
|
||||
|
||||
|
||||
class KaTrainApp(App):
|
||||
|
||||
Reference in new issue
Block a user