below board panel
This commit is contained in:
1 parent
c4ce996ef5
commit
3f8e15f36c
6 files changed
+60
-43
No files matched your search
@@ -28,7 +28,6 @@
|
|||||||
"eval_off_show_last": 3
|
"eval_off_show_last": 3
|
||||||
},
|
},
|
||||||
"board_ui": {
|
"board_ui": {
|
||||||
"board_margin": 1.5,
|
|
||||||
"starpoint_size": 0.1,
|
"starpoint_size": 0.1,
|
||||||
"stone_size": 0.475,
|
"stone_size": 0.475,
|
||||||
"eval_dot_max_size": 0.5,
|
"eval_dot_max_size": 0.5,
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ class Game:
|
|||||||
|
|
||||||
def ai_move(self, train_settings):
|
def ai_move(self, train_settings):
|
||||||
while not self.current_node.analysis_ready:
|
while not self.current_node.analysis_ready:
|
||||||
self.katrain.set_status("Thinking...")
|
self.katrain.controls.set_status("Thinking...")
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|
||||||
# select move
|
# select move
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
from gui.badukpan import BadukPanWidget
|
from gui.badukpan import BadukPanWidget, BadukPanControls
|
||||||
from gui.controls import Controls
|
from gui.controls import Controls
|
||||||
from gui.kivyutils import (
|
from gui.kivyutils import (
|
||||||
BWCheckBoxHint,
|
BWCheckBoxHint,
|
||||||
|
|||||||
+38
-33
@@ -2,6 +2,7 @@ import math
|
|||||||
|
|
||||||
from kivy.graphics.context_instructions import Color
|
from kivy.graphics.context_instructions import Color
|
||||||
from kivy.graphics.vertex_instructions import Ellipse, Line, Rectangle
|
from kivy.graphics.vertex_instructions import Ellipse, Line, Rectangle
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
from kivy.uix.widget import Widget
|
from kivy.uix.widget import Widget
|
||||||
|
|
||||||
from constants import OUTPUT_DEBUG
|
from constants import OUTPUT_DEBUG
|
||||||
@@ -15,22 +16,23 @@ class BadukPanWidget(Widget):
|
|||||||
self.ui_config = {}
|
self.ui_config = {}
|
||||||
self.trainer_config = {}
|
self.trainer_config = {}
|
||||||
self.ghost_stone = []
|
self.ghost_stone = []
|
||||||
self.gridpos = []
|
self.gridpos_x = []
|
||||||
|
self.gridpos_y = []
|
||||||
self.grid_size = 0
|
self.grid_size = 0
|
||||||
self.stone_size = 0
|
self.stone_size = 0
|
||||||
self.last_eval = 0
|
self.last_eval = 0
|
||||||
|
|
||||||
# stone placement functions
|
# stone placement functions
|
||||||
def _find_closest(self, pos):
|
def _find_closest(self, pos, gridpos):
|
||||||
return sorted([(abs(p - pos), i) for i, p in enumerate(self.gridpos)])[0]
|
return sorted([(abs(p - pos), i) for i, p in enumerate(gridpos)])[0]
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
def on_touch_down(self, touch):
|
||||||
if not self.gridpos:
|
if not self.gridpos_x:
|
||||||
return
|
return
|
||||||
xd, xp = self._find_closest(touch.x)
|
xd, xp = self._find_closest(touch.x,self.gridpos_x)
|
||||||
yd, yp = self._find_closest(touch.y)
|
yd, yp = self._find_closest(touch.y,self.gridpos_y)
|
||||||
prev_ghost = self.ghost_stone
|
prev_ghost = self.ghost_stone
|
||||||
if max(yd, xd) < self.grid_size / 2 and (xp, yp) not in [m.coords for m in self.parent.game.stones]:
|
if max(yd, xd) < self.grid_size / 2 and (xp, yp) not in [m.coords for m in self.katrain.game.stones]:
|
||||||
self.ghost_stone = (xp, yp)
|
self.ghost_stone = (xp, yp)
|
||||||
else:
|
else:
|
||||||
self.ghost_stone = None
|
self.ghost_stone = None
|
||||||
@@ -41,14 +43,14 @@ class BadukPanWidget(Widget):
|
|||||||
return self.on_touch_down(touch)
|
return self.on_touch_down(touch)
|
||||||
|
|
||||||
def on_touch_up(self, touch):
|
def on_touch_up(self, touch):
|
||||||
if not self.gridpos:
|
if not self.gridpos_x:
|
||||||
return
|
return
|
||||||
katrain = self.parent
|
katrain = self.katrain
|
||||||
if self.ghost_stone:
|
if self.ghost_stone:
|
||||||
katrain("play", self.ghost_stone)
|
katrain("play", self.ghost_stone)
|
||||||
else:
|
else:
|
||||||
xd, xp = self._find_closest(touch.x)
|
xd, xp = self._find_closest(touch.x,self.gridpos_x)
|
||||||
yd, yp = self._find_closest(touch.y)
|
yd, yp = self._find_closest(touch.y,self.gridpos_y)
|
||||||
|
|
||||||
nodes_here = [node for node in katrain.game.current_node.nodes_from_root if node.single_move and node.single_move.coords == (xp, yp)]
|
nodes_here = [node for node in katrain.game.current_node.nodes_from_root if node.single_move and node.single_move.coords == (xp, yp)]
|
||||||
if nodes_here and max(yd, xd) < self.grid_size / 2: # load old comment
|
if nodes_here and max(yd, xd) < self.grid_size / 2: # load old comment
|
||||||
@@ -68,20 +70,20 @@ class BadukPanWidget(Widget):
|
|||||||
|
|
||||||
def draw_stone(self, x, y, col, outline_col=None, innercol=None, evalcol=None, evalscale=1.0, scale=1.0):
|
def draw_stone(self, x, y, col, outline_col=None, innercol=None, evalcol=None, evalscale=1.0, scale=1.0):
|
||||||
stone_size = self.stone_size * scale
|
stone_size = self.stone_size * scale
|
||||||
draw_circle((self.gridpos[x], self.gridpos[y]), stone_size, col)
|
draw_circle((self.gridpos_x[x], self.gridpos_y[y]), stone_size, col)
|
||||||
if outline_col:
|
if outline_col:
|
||||||
Color(*outline_col)
|
Color(*outline_col)
|
||||||
Line(circle=(self.gridpos[x], self.gridpos[y], stone_size), width=0.05 * stone_size)
|
Line(circle=(self.gridpos_x[x], self.gridpos_y[y], stone_size), width=0.05 * stone_size)
|
||||||
if evalcol:
|
if evalcol:
|
||||||
evalsize = self.stone_size * evalscale * self.ui_config["eval_dot_max_size"]
|
evalsize = self.stone_size * evalscale * self.ui_config["eval_dot_max_size"]
|
||||||
draw_circle((self.gridpos[x], self.gridpos[y]), evalsize, evalcol)
|
draw_circle((self.gridpos_x[x], self.gridpos_y[y]), evalsize, evalcol)
|
||||||
# highlight_col = [ ((1-c)*0.33+e)/1.33 for c,e in zip(col,evalcol) ]
|
# highlight_col = [ ((1-c)*0.33+e)/1.33 for c,e in zip(col,evalcol) ]
|
||||||
# Color(*highlight_col[:3],0.5)
|
# Color(*highlight_col[:3],0.5)
|
||||||
# Line(circle=(self.gridpos[x], self.gridpos[y], evalsize))
|
# Line(circle=(self.gridpos[x], self.gridpos[y], evalsize))
|
||||||
|
|
||||||
if innercol:
|
if innercol:
|
||||||
Color(*innercol)
|
Color(*innercol)
|
||||||
Line(circle=(self.gridpos[x], self.gridpos[y], stone_size * 0.45 / 0.85), width=0.125 * stone_size) # 1.75
|
Line(circle=(self.gridpos_x[x], self.gridpos_y[y], stone_size * 0.45 / 0.85), width=0.125 * stone_size) # 1.75
|
||||||
|
|
||||||
def eval_color(self, points_lost):
|
def eval_color(self, points_lost):
|
||||||
colors = self.ui_config["eval_colors"]
|
colors = self.ui_config["eval_colors"]
|
||||||
@@ -94,39 +96,40 @@ class BadukPanWidget(Widget):
|
|||||||
def draw_board(self, *args):
|
def draw_board(self, *args):
|
||||||
if not self.ui_config:
|
if not self.ui_config:
|
||||||
return
|
return
|
||||||
katrain = self.parent
|
katrain = self.katrain
|
||||||
board_size = katrain.game.board_size
|
board_size = katrain.game.board_size
|
||||||
self.canvas.before.clear()
|
self.canvas.before.clear()
|
||||||
with self.canvas.before:
|
with self.canvas.before:
|
||||||
# board
|
# board
|
||||||
sz = min(self.width, self.height)
|
sz = min(self.width, self.height)
|
||||||
Color(*self.ui_config["board_color"])
|
Color(*self.ui_config["board_color"])
|
||||||
board_rectangle = Rectangle(pos=(0, 0), size=(sz, sz))
|
board_rectangle = Rectangle(pos=self.pos, size=(sz, sz))
|
||||||
# grid lines
|
# grid lines
|
||||||
margin = self.ui_config["board_margin"]
|
margin = 1.5
|
||||||
self.grid_size = board_rectangle.size[0] / (board_size - 1 + 1.5 * margin)
|
self.grid_size = board_rectangle.size[0] / (board_size - 1 + 1.5 * margin)
|
||||||
self.stone_size = self.grid_size * self.ui_config["stone_size"]
|
self.stone_size = self.grid_size * self.ui_config["stone_size"]
|
||||||
self.gridpos = [math.floor((margin + i) * self.grid_size + 0.5) for i in range(board_size)]
|
self.gridpos_x = [self.pos[0] + math.floor((margin + i) * self.grid_size + 0.5) for i in range(board_size)]
|
||||||
|
self.gridpos_y = [self.pos[1] + math.floor((margin + i) * self.grid_size + 0.5) for i in range(board_size)]
|
||||||
|
|
||||||
line_color = self.ui_config["line_color"]
|
line_color = self.ui_config["line_color"]
|
||||||
Color(*line_color)
|
Color(*line_color)
|
||||||
lo, hi = self.gridpos[0], self.gridpos[-1]
|
|
||||||
for i in range(board_size):
|
for i in range(board_size):
|
||||||
Line(points=[(self.gridpos[i], lo), (self.gridpos[i], hi)])
|
Line(points=[(self.gridpos_x[i], self.gridpos_y[0]), (self.gridpos_x[i], self.gridpos_y[-1])])
|
||||||
Line(points=[(lo, self.gridpos[i]), (hi, self.gridpos[i])])
|
Line(points=[( self.gridpos_x[0], self.gridpos_y[i]), ( self.gridpos_x[-1], self.gridpos_y[i])])
|
||||||
|
|
||||||
# star points
|
# star points
|
||||||
star_point_pos = 3 if board_size <= 11 else 4
|
star_point_pos = 3 if board_size <= 11 else 4
|
||||||
starpt_size = self.grid_size * self.ui_config["starpoint_size"]
|
starpt_size = self.grid_size * self.ui_config["starpoint_size"]
|
||||||
for x in [star_point_pos - 1, board_size - star_point_pos, int(board_size / 2)]:
|
for x in [star_point_pos - 1, board_size - star_point_pos, int(board_size / 2)]:
|
||||||
for y in [star_point_pos - 1, board_size - star_point_pos, int(board_size / 2)]:
|
for y in [star_point_pos - 1, board_size - star_point_pos, int(board_size / 2)]:
|
||||||
draw_circle((self.gridpos[x], self.gridpos[y]), starpt_size, line_color)
|
draw_circle((self.gridpos_x[x], self.gridpos_y[y]), starpt_size, line_color)
|
||||||
|
|
||||||
# coordinates
|
# coordinates
|
||||||
Color(0.25, 0.25, 0.25)
|
Color(0.25, 0.25, 0.25)
|
||||||
|
coord_offset = self.grid_size * margin / 2
|
||||||
for i in range(board_size):
|
for i in range(board_size):
|
||||||
draw_text(pos=(self.gridpos[i], lo / 2), text=Move.GTP_COORD[i], font_size=self.grid_size / 1.5)
|
draw_text(pos=(self.gridpos_x[i], self.gridpos_y[0] -coord_offset), text=Move.GTP_COORD[i], font_size=self.grid_size / 1.5)
|
||||||
draw_text(pos=(lo / 2, self.gridpos[i]), text=str(i + 1), font_size=self.grid_size / 1.5)
|
draw_text(pos=(self.gridpos_x[0] - coord_offset, self.gridpos_y[i]), text=str(i + 1), font_size=self.grid_size / 1.5)
|
||||||
|
|
||||||
def draw_board_contents(self, *args):
|
def draw_board_contents(self, *args):
|
||||||
if not self.ui_config:
|
if not self.ui_config:
|
||||||
@@ -134,7 +137,7 @@ class BadukPanWidget(Widget):
|
|||||||
stone_color = self.ui_config["stones"]
|
stone_color = self.ui_config["stones"]
|
||||||
outline_color = self.ui_config["outline"]
|
outline_color = self.ui_config["outline"]
|
||||||
_ghost_alpha = self.ui_config["_ghost_alpha"]
|
_ghost_alpha = self.ui_config["_ghost_alpha"]
|
||||||
katrain = self.parent
|
katrain = self.katrain
|
||||||
board_size = katrain.game.board_size
|
board_size = katrain.game.board_size
|
||||||
|
|
||||||
self.canvas.clear()
|
self.canvas.clear()
|
||||||
@@ -171,7 +174,7 @@ class BadukPanWidget(Widget):
|
|||||||
ix_owner = "B" if ownership[ix] > 0 else "W"
|
ix_owner = "B" if ownership[ix] > 0 else "W"
|
||||||
if ix_owner != (has_stone.get((x, y), -1)):
|
if ix_owner != (has_stone.get((x, y), -1)):
|
||||||
Color(*stone_color[ix_owner], abs(ownership[ix]))
|
Color(*stone_color[ix_owner], abs(ownership[ix]))
|
||||||
Rectangle(pos=(self.gridpos[x] - rsz / 2, self.gridpos[y] - rsz / 2), size=(rsz, rsz))
|
Rectangle(pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz))
|
||||||
ix = ix + 1
|
ix = ix + 1
|
||||||
|
|
||||||
policy = current_node.policy
|
policy = current_node.policy
|
||||||
@@ -187,8 +190,7 @@ class BadukPanWidget(Widget):
|
|||||||
policy_delta = best_move_policy - policy[ix]
|
policy_delta = best_move_policy - policy[ix]
|
||||||
polcol = self.eval_color(0.1 * policy_delta / avg_policy)
|
polcol = self.eval_color(0.1 * policy_delta / avg_policy)
|
||||||
Color(*polcol)
|
Color(*polcol)
|
||||||
Rectangle(pos=(self.gridpos[x] - rsz / 2, self.gridpos[y] - rsz / 2), size=(rsz, rsz))
|
Rectangle(pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz))
|
||||||
else:
|
|
||||||
ix = ix + 1
|
ix = ix + 1
|
||||||
policy_delta = best_move_policy - policy[ix]
|
policy_delta = best_move_policy - policy[ix]
|
||||||
katrain.controls.pass_btn.face_color = (*self.eval_color(100*policy_delta),1)
|
katrain.controls.pass_btn.face_color = (*self.eval_color(100*policy_delta),1)
|
||||||
@@ -220,7 +222,6 @@ class BadukPanWidget(Widget):
|
|||||||
scale = 0.85
|
scale = 0.85
|
||||||
self.draw_stone(move.coords[0], move.coords[1], c, scale=scale)
|
self.draw_stone(move.coords[0], move.coords[1], c, scale=scale)
|
||||||
|
|
||||||
|
|
||||||
# hover next move ghost stone
|
# hover next move ghost stone
|
||||||
if self.ghost_stone:
|
if self.ghost_stone:
|
||||||
self.draw_stone(*self.ghost_stone, (*stone_color[next_player], _ghost_alpha))
|
self.draw_stone(*self.ghost_stone, (*stone_color[next_player], _ghost_alpha))
|
||||||
@@ -233,7 +234,11 @@ class BadukPanWidget(Widget):
|
|||||||
else:
|
else:
|
||||||
text = "pass"
|
text = "pass"
|
||||||
Color(0.45, 0.05, 0.45, 0.5)
|
Color(0.45, 0.05, 0.45, 0.5)
|
||||||
center = self.gridpos[int(board_size / 2)]
|
center = (self.pos[0] + self.width/2,self.pos[1]+self.height/2)
|
||||||
Ellipse(pos=(center - self.grid_size * 1.5, center - self.grid_size * 1.5), size=(self.grid_size * 3, self.grid_size * 3))
|
size = min(self.width, self.height) * 0.22
|
||||||
|
Ellipse(pos=(center[0] - size/2, center[1] - size/2), size=(size,size))
|
||||||
Color(0.15, 0.15, 0.15)
|
Color(0.15, 0.15, 0.15)
|
||||||
draw_text(pos=(center, center), text=text, font_size=self.grid_size * 0.66, halign="center", outline_color=[0.95, 0.95, 0.95])
|
draw_text(pos=center, text=text, font_size=size*0.25, halign="center", outline_color=[0.95, 0.95, 0.95])
|
||||||
|
|
||||||
|
class BadukPanControls(BoxLayout):
|
||||||
|
pass
|
||||||
+19
-6
@@ -264,8 +264,8 @@
|
|||||||
|
|
||||||
<BadukPanWidget>:
|
<BadukPanWidget>:
|
||||||
size: self.parent.height, self.parent.height
|
size: self.parent.height, self.parent.height
|
||||||
engine: self.parent.controls
|
katrain: self.parent.parent
|
||||||
|
|
||||||
<Controls>
|
<Controls>
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
play_tab_button: play_tab_button
|
play_tab_button: play_tab_button
|
||||||
@@ -300,6 +300,7 @@
|
|||||||
play_tab.size_hint_x = None
|
play_tab.size_hint_x = None
|
||||||
play_tab.width = 0
|
play_tab.width = 0
|
||||||
play_tab.opacity = 0
|
play_tab.opacity = 0
|
||||||
|
self.state = 'down'
|
||||||
StyledToggleButton:
|
StyledToggleButton:
|
||||||
text: 'Play'
|
text: 'Play'
|
||||||
group: 'tabs'
|
group: 'tabs'
|
||||||
@@ -312,6 +313,7 @@
|
|||||||
analyze_tab.size_hint_x = None
|
analyze_tab.size_hint_x = None
|
||||||
analyze_tab.width = 0
|
analyze_tab.width = 0
|
||||||
analyze_tab.opacity = 0
|
analyze_tab.opacity = 0
|
||||||
|
self.state = 'down'
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hint: 1,0.25
|
size_hint: 1,0.25
|
||||||
orientation: 'horizontal'
|
orientation: 'horizontal'
|
||||||
@@ -467,21 +469,32 @@
|
|||||||
size_hint: 0.25, 1
|
size_hint: 0.25, 1
|
||||||
on_press: root.katrain('config-popup')
|
on_press: root.katrain('config-popup')
|
||||||
|
|
||||||
|
<BadukPanControls>:
|
||||||
|
StyledIconButton:
|
||||||
|
icon: 'img/flaticon/go-game.png'
|
||||||
|
size_hint: 0.25, 1
|
||||||
|
on_press: root.katrain("new-game-popup")
|
||||||
|
|
||||||
<KaTrainGui>:
|
<KaTrainGui>:
|
||||||
board_gui: board_gui
|
board_gui: board_gui
|
||||||
controls: controls
|
controls: controls
|
||||||
|
board_aspect_ratio: 1.1
|
||||||
canvas.before:
|
canvas.before:
|
||||||
Color:
|
Color:
|
||||||
rgba: 0.95, 0.95, 0.95, 1
|
rgba: 0.95, 0.95, 0.95, 1
|
||||||
Rectangle:
|
Rectangle:
|
||||||
pos: self.pos
|
pos: self.pos
|
||||||
size: root.size
|
size: root.size
|
||||||
BadukPanWidget:
|
BoxLayout:
|
||||||
id: board_gui
|
orientation: 'vertical'
|
||||||
size_hint: 1 - controls.size_hint[0], 1
|
size_hint: 1 - controls.size_hint[0], 1
|
||||||
|
BadukPanWidget:
|
||||||
|
id: board_gui
|
||||||
|
size_hint: (1,1)
|
||||||
|
BadukPanControls:
|
||||||
|
id: board_controls
|
||||||
|
size_hint: (1,root.board_aspect_ratio-1)
|
||||||
Controls:
|
Controls:
|
||||||
id: controls
|
id: controls
|
||||||
size_hint: max(0.25,(root.width - root.height)/root.width), 1
|
size_hint: max(0.25,(root.width - root.height/root.board_aspect_ratio)/root.width), 1
|
||||||
|
|
||||||
+1
-1
@@ -160,7 +160,7 @@ class SGFNode:
|
|||||||
def single_move(self) -> Optional[Move]:
|
def single_move(self) -> Optional[Move]:
|
||||||
"""Returns the single move for the node if one exists, or None if no moves (or multiple ones) exist."""
|
"""Returns the single move for the node if one exists, or None if no moves (or multiple ones) exist."""
|
||||||
moves = self.moves
|
moves = self.moves
|
||||||
if len(moves) == 1:
|
if len(moves) == 1: # TODO: and not placements?
|
||||||
return moves[0]
|
return moves[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
Reference in new issue
Block a user