Class: GoshrineBot::GameInProgress

Inherits:
Object
  • Object
show all
Defined in:
lib/goshrine_bot/game.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client) ⇒ GameInProgress

Returns a new instance of GameInProgress.



20
21
22
# File 'lib/goshrine_bot/game.rb', line 20

def initialize(client)
  @client = client
end

Instance Attribute Details

#black_player_idObject

Returns the value of attribute black_player_id.



7
8
9
# File 'lib/goshrine_bot/game.rb', line 7

def black_player_id
  @black_player_id
end

#board_sizeObject

Returns the value of attribute board_size.



4
5
6
# File 'lib/goshrine_bot/game.rb', line 4

def board_size
  @board_size
end

#challenge_idObject

Returns the value of attribute challenge_id.



8
9
10
# File 'lib/goshrine_bot/game.rb', line 8

def challenge_id
  @challenge_id
end

#game_idObject

Returns the value of attribute game_id.



10
11
12
# File 'lib/goshrine_bot/game.rb', line 10

def game_id
  @game_id
end

#gtp_clientObject

Returns the value of attribute gtp_client.



11
12
13
# File 'lib/goshrine_bot/game.rb', line 11

def gtp_client
  @gtp_client
end

#handicapObject

Returns the value of attribute handicap.



16
17
18
# File 'lib/goshrine_bot/game.rb', line 16

def handicap
  @handicap
end

#handicap_stonesObject

Returns the value of attribute handicap_stones.



17
18
19
# File 'lib/goshrine_bot/game.rb', line 17

def handicap_stones
  @handicap_stones
end

#komiObject

Returns the value of attribute komi.



14
15
16
# File 'lib/goshrine_bot/game.rb', line 14

def komi
  @komi
end

#last_activityObject

Returns the value of attribute last_activity.



18
19
20
# File 'lib/goshrine_bot/game.rb', line 18

def last_activity
  @last_activity
end

#move_numberObject

Returns the value of attribute move_number.



12
13
14
# File 'lib/goshrine_bot/game.rb', line 12

def move_number
  @move_number
end

#movesObject

Returns the value of attribute moves.



15
16
17
# File 'lib/goshrine_bot/game.rb', line 15

def moves
  @moves
end

#proposed_by_idObject

Returns the value of attribute proposed_by_id.



5
6
7
# File 'lib/goshrine_bot/game.rb', line 5

def proposed_by_id
  @proposed_by_id
end

#stateObject

Returns the value of attribute state.



3
4
5
# File 'lib/goshrine_bot/game.rb', line 3

def state
  @state
end

#tokenObject

Returns the value of attribute token.



9
10
11
# File 'lib/goshrine_bot/game.rb', line 9

def token
  @token
end

#turnObject

Returns the value of attribute turn.



13
14
15
# File 'lib/goshrine_bot/game.rb', line 13

def turn
  @turn
end

#white_player_idObject

Returns the value of attribute white_player_id.



6
7
8
# File 'lib/goshrine_bot/game.rb', line 6

def white_player_id
  @white_player_id
end

Instance Method Details

#goshrine_coord_to_gtp_coord(value, board_size) ⇒ Object



252
253
254
255
256
257
# File 'lib/goshrine_bot/game.rb', line 252

def goshrine_coord_to_gtp_coord(value, board_size)
  x = value[0].ord - 97
  y = value[1].ord - 97
  x += 1 if x >= 8
  [x+65].pack('c') + (board_size - y).to_s
end

#gtp_coord_to_goshrine_coord(value, board_size) ⇒ Object



259
260
261
262
263
264
# File 'lib/goshrine_bot/game.rb', line 259

def gtp_coord_to_goshrine_coord(value, board_size)
  x = value[0].ord - 65
  x -= 1 if x >= 8
  y = board_size - (value[1..-1].to_i)
  [x+97, y+97].pack('cc')
end

#handle_messagesObject



119
120
121
122
123
# File 'lib/goshrine_bot/game.rb', line 119

def handle_messages
  msg = @queue.pop
  args = msg[1..-1]
  self.send(msg.first, *args)
end

#handle_move(m) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/goshrine_bot/game.rb', line 77

def handle_move(m)
  # {"captures"=>[], "move_number"=>1, "color"=>"b", "move"=>"ir", "black_seconds_left"=>1900, "white_seconds_left"=>1900, "turn_started_at"=>"Sat, 05 Dec 2009 00:44:19 -0600"}
  pos = m["move"]
  color = m["color"].upcase
  if pos && color && color != my_color
    pos = sgf_coord_to_gtp_coord(pos, board_size)
    move_proc = Proc.new do
      gtp_client.play(color, pos).callback {
        self.moves << [color, pos]
        self.move_number = m["move_number"].to_i
        self.turn = m["color"] == "b" ? "w" : "b"
        puts "Going to make move..."
        make_move
      }
    end
    if m["black_seconds_left"] && m["white_seconds_left"]
      gtp_client.time_left("B", m["black_seconds_left"] || 0, 0).callback {
        gtp_client.time_left("W", m["white_seconds_left"] || 0, 0).callback {
          move_proc.call
        }
      }
    else
      move_proc.call
    end
  end
end

#idle_check(timeout) ⇒ Object



104
105
106
107
108
109
# File 'lib/goshrine_bot/game.rb', line 104

def idle_check(timeout)
  if timeout > 0 && @last_gtp_access && @last_gtp_access + timeout < Time.now
    puts "Shutting down gtp client #{self.token} after #{timeout} seconds idle."
    stop_gtp_client
  end
end

#make_moveObject



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/goshrine_bot/game.rb', line 183

def make_move
  return unless started? && my_turn?
  
  res = gtp_client.genmove(turn)
  res.callback { |response_move|
    puts "Generated move: #{response_move} (#{token})"
    self.move_number += 1
    request = nil
    if response_move.upcase == 'PASS'
      request = GoshrineRequest.new("/game/#{token}/pass").post
    elsif response_move.upcase == 'RESIGN'
      request = GoshrineRequest.new("/game/#{token}/resign").post
    else
      rgo_coord = gtp_coord_to_goshrine_coord(response_move.upcase, board_size)
      request = GoshrineRequest.new("/game/#{token}/move/#{rgo_coord}").post
    end
    request.callback { |http|
      if http.response_header.status == 200
        self.moves << [my_color, response_move]
      else
        puts "Could not make move: #{http.response}"
      end
    }
  }
end

#my_colorObject



175
176
177
# File 'lib/goshrine_bot/game.rb', line 175

def my_color
  @client.my_user_id == white_player_id ? "W" : "B"
end

#my_turn?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/goshrine_bot/game.rb', line 125

def my_turn?
  @client.my_user_id == players_turn
end

#opponents_colorObject



179
180
181
# File 'lib/goshrine_bot/game.rb', line 179

def opponents_color
  @client.my_user_id == white_player_id ? "B" : "W"
end

#play_message(m) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/goshrine_bot/game.rb', line 24

def play_message(m)
  return unless m
  #puts "Got game play message: #{m.inspect}"
  case m["action"]
  when 'user_arrive'
    user_id = m["id"].to_i
    puts "User arrived (#{token}): #{m["login"]}"
    if state == 'new' && (user_id == black_player_id || user_id == white_player_id)
      GoshrineRequest.new("/game/#{token}/attempt_start").post
    end
  when 'game_started'
    self.state = "in-play"
    make_move
  when 'updateBoard'
    handle_move(m["data"])
    #puts "Going to update board"
  when 'resignedBy'
    puts "Game resigned by opponent."
    self.state = "finished"
    stop_gtp_client
  when 'updateForUndo'
    # TODO - handle undos?
    puts "Undo not currently supported"
  when 'pleaseWait'
    # ignore
  when 'user_leave'
    # ignore
  when 'gameFinished'
    stop_gtp_client
    self.state = "finished"
    if m['data'].nil?
      puts "Missing data: #{m.inspect}"
      return
    elsif m['data']['scoring_info'].nil?
      puts "Missing scoring_info: #{m.inspect}"
      return
    elsif m['data']['scoring_info']['score'].nil?
      puts "Missing score (game_id = #{game_id}): #{m.inspect}"
      return
    end
    score = m['data']['scoring_info']['score']
    winner = score['black'] > score['white'] ? 'B' : 'W'
    if my_color == winner
      puts "I Won!"
    else
      puts "I Lost."
    end
    puts "Score: #{score.inspect}"
  else
    puts "Unhandled game play message #{m.inspect}"
  end
end

#players_turnObject



240
241
242
# File 'lib/goshrine_bot/game.rb', line 240

def players_turn
  self.turn == 'b' ? black_player_id : white_player_id
end

#private_message(m) ⇒ Object



111
112
113
114
115
116
117
# File 'lib/goshrine_bot/game.rb', line 111

def private_message(m)
  puts "Got private game message: #{m.inspect}"
  case m["type"]
  when 'undo_requested'
    GoshrineReuqest.new("/game/accept_undo/" + m["request_id"]).post
  end
end

#sgf_coord_to_gtp_coord(value, board_size) ⇒ Object



244
245
246
247
248
249
250
# File 'lib/goshrine_bot/game.rb', line 244

def sgf_coord_to_gtp_coord(value, board_size)
  return 'pass' if value.downcase == 'pass'
  x = value[0].ord - 97
  y = value[1].ord - 97
  x += 1 if x >= 8
  [x+65].pack('c') + (board_size - y).to_s
end

#start_engineObject



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/goshrine_bot/game.rb', line 209

def start_engine
  gtp = GtpStdioClient.new(@client.gtp_cmd_line, "gtp_#{token}.log")
  gtp.boardsize(@board_size)
  gtp.clear_board
  gtp.komi(@komi)
  
  if @handicap_stones.size > 0
    gtp_coords = @handicap_stones.map {|s| sgf_coord_to_gtp_coord(s, board_size) }
    gtp.set_free_handicap(gtp_coords.join(" "))
  end
  
  if @moves
    @moves.each do |m|
      #puts "Going to play #{m.first}, #{m.last}"
      gtp.play(m.first, m.last)
    end
  end
  gtp
end

#started?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/goshrine_bot/game.rb', line 129

def started?
  state != 'new'
end

#stop_gtp_clientObject



234
235
236
237
238
# File 'lib/goshrine_bot/game.rb', line 234

def stop_gtp_client
  @gtp_client.close if @gtp_client
  @gtp_client = nil
  @last_gtp_access = nil
end

#update_from_game_list(attrs) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/goshrine_bot/game.rb', line 147

def update_from_game_list(attrs)
  #puts "attrs = #{attrs.inspect}"
  self.state = attrs['state']
  self.token = attrs['token']
  self.game_id = attrs['id'].to_i
  self.komi = attrs['komi'].to_f
  self.white_player_id = attrs['white_player_id'].to_i
  self.black_player_id = attrs['black_player_id'].to_i
  self.turn = attrs['turn']
  self.board_size = attrs['board']['size'].to_i
  self.move_number = attrs['move_number'].to_i
  self.handicap = attrs['handicap'].to_i rescue 0
  self.handicap_stones = attrs['handicap_stones']
  self.moves = []
  move_colors = ["B", "W"]
  handicap_offset = self.handicap > 0 ? 1 : 0
  if attrs['moves']
    attrs['moves'].each_with_index do |m,idx|
      self.moves << [move_colors[(idx+handicap_offset) % 2], sgf_coord_to_gtp_coord(m, board_size)]
    end
  end
  
  if state == 'new'
    GoshrineRequest.new("/game/#{token}/attempt_start").post
  end
  
end

#update_from_match_request(attrs) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/goshrine_bot/game.rb', line 133

def update_from_match_request(attrs)
  self.state = attrs['state']
  self.board_size = attrs['board_size'].to_i
  self.proposed_by_id = attrs['proposed_by_id'].to_i
  self.white_player_id = attrs['white_player_id'].to_i
  self.black_player_id = attrs['black_player_id'].to_i
  self.challenge_id = attrs['id'].to_i
  self.handicap = attrs['handicap'].to_i
  self.handicap_stones = attrs['handicap_stones']
  self.turn = handicap > 1 ? 'w' : 'b'
  self.move_number = 0
  self.moves = []
end