lib/rubykon/cli.rb in rubykon-0.3.0 vs lib/rubykon/cli.rb in rubykon-0.3.1
- old
+ new
@@ -1,26 +1,30 @@
module Rubykon
class CLI
- EXIT = /exit/i
- CHAR_LABELS = GTPCoordinateConverter::X_CHARS
- X_LABEL_PADDING = ' '.freeze * 4
- Y_LABEL_WIDTH = 3
+ EXIT = /exit/i
+ CHAR_LABELS = GTPCoordinateConverter::X_CHARS
+ X_LABEL_PADDING = ' '.freeze * 4
+ Y_LABEL_WIDTH = 3
+ GTP_COORDINATE = /^[A-Z]\d\d?$/
+ MOVE_CONSIDERATIONS_COUNT = 10
def initialize(output = $stdout, input = $stdin)
- @output = output
- @input = input
- @state = :init
+ @output = output
+ @input = input
+ @state = :init
+ @move_validator = MoveValidator.new
+ @root = nil
end
def start
@output.puts 'Please enter a board size (common sizes are 9, 13, and 19)'
size = get_digit_input
@output.puts <<-PLAYOUTS
Please enter the number of playouts you'd like rubykon to make!
More playouts means rubykon is stronger, but also takes longer.
-For 9x9 10000 is an acceptable value, for 19x19 1000 already take a long time.
+For 9x9 10000 is an acceptable value, for 19x19 1000 already take a long time (but still plays bad).
PLAYOUTS
playouts = get_digit_input
init_game(size, playouts)
game_loop
end
@@ -66,11 +70,11 @@
print_board
while true
if bot_turn?
bot_move
else
- human_move
+ human_input
end
end
end
def bot_turn?
@@ -94,29 +98,69 @@
rows.join "\n"
end
def bot_move
@output.puts 'Rubykon is thinking...'
- root = @mcts.start @game_state, @playouts
- move = root.best_move
- best_children = root.children.sort_by(&:win_percentage).reverse.take(10)
- @output.puts best_children.map {|child| "#{@gtp_converter.to(child.move.first)} => #{child.win_percentage}"}.join "\n"
+ @root = @mcts.start @game_state, @playouts
+ move = @root.best_move
make_move(move)
end
- def human_move
+ def human_input
+ input = ask_for_input.upcase
+ case input
+ when GTP_COORDINATE
+ human_move(input)
+ when 'WDYT'.freeze
+ print_move_considerations
+ else
+ invalid_input
+ end
+ end
+
+ def ask_for_input
@output.puts "Make a move in the form XY, e.g. A19, D7 as the labels indicate!"
- coords = get_input
- identifier = @gtp_converter.from(coords)
- move = [identifier, :white]
- make_move(move)
+ @output.puts 'Or ask rubykon what it is thinking with "wdyt"'
+ get_input
end
+ def human_move(input)
+ move = move_from_input(input)
+ if @move_validator.valid?(*move, @game_state.game)
+ make_move(move)
+ else
+ retry_input
+ end
+ end
+
+ def retry_input
+ @output.puts 'That was an invalid move, please try again!'
+ human_input
+ end
+
+ def print_move_considerations
+ best_children = @root.children.sort_by(&:win_percentage).reverse
+ top_children = best_children.take(MOVE_CONSIDERATIONS_COUNT)
+ moves_to_win_percentage = top_children.map do |child|
+ "#{@gtp_converter.to(child.move.first)} => #{child.win_percentage * 100}%"
+ end.join "\n"
+ @output.puts moves_to_win_percentage
+ end
+
+ def move_from_input(input)
+ identifier = @gtp_converter.from(input)
+ [identifier, :white]
+ end
+
def make_move(move)
@game_state.set_move move
print_board
@output.puts "#{move.last} played at #{@gtp_converter.to(move.first)}"
@output.puts "#{@game.next_turn_color}'s turn to move!'"
+ end
+
+ def invalid_input
+ puts "Sorry, didn't catch that!"
end
end
end
\ No newline at end of file