forked from BrainJarOrg/battleships-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
battleship.rb
135 lines (113 loc) · 3.45 KB
/
battleship.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
76
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
class Battleship
def initialize(json)
@grid = Grid.new(json)
@destroyed_ships = json['destroyed']
#puts @grid
generate_points()
end
def shoot
point = smart_shoot
if point.nil? || point.already_targeted?
Battleship.do_move(probe_shoot, 'not smart')
else
Battleship.do_move(point, 'smart')
end
end
private
# @return [Point]
def smart_shoot
@grid.hit.each do |point|
unless point.neighbor_hit?
return find_neighbor(point, 1, 1)
end
if !point.left_neighbor.nil? && point.left_neighbor.was_hit? && !point.right_neighbor.nil? && !point.right_neighbor.already_targeted?
return point.right_neighbor
elsif !point.top_neighbor.nil? && point.top_neighbor.was_hit? && !point.bottom_neighbor.nil? && !point.bottom_neighbor.already_targeted?
return point.bottom_neighbor
elsif !point.right_neighbor.nil? && point.right_neighbor.was_hit? && !point.left_neighbor.nil? && !point.left_neighbor.already_targeted?
return point.left_neighbor
elsif !point.bottom_neighbor.nil? && point.bottom_neighbor.was_hit? && !point.top_neighbor.nil? && !point.top_neighbor.already_targeted?
return point.top_neighbor
end
end
nil
end
# @return [Point]
def probe_shoot
max_score = @points[0].score
tmp_points = Array.new
@points.each do |point|
if point.score == max_score
tmp_points.push(point)
end
end
tmp_points[rand(tmp_points.length)]
end
# @param [Point] square
def self.do_move(square, type)
move = {'move' => square.to_s, 'shoot_type' => type}
puts JSON.generate(move)
end
def max(a, b)
a > b ? a : b
end
def smallest_ship_alive
([2, 3, 4, 5] - @destroyed_ships).min
end
def generate_points
@points = Array.new
@grid.not_targeted.each do |point|
score = 0
(2..5).each { |size|
unless @destroyed_ships.include?(size)
score += search_ships(point, true, size)
score += search_ships(point, false, size)
end
}
point.score=score
@points.push(point)
end
@points.sort!.reverse!
end
# @param [Point] point
# @param [Boolean] x_vary
# @param [Integer] size
# @return [Integer]
def search_ships(point, x_vary, size)
score = 0
variable = x_vary ? point.x : point.y
min = variable-size-1 < 0 ? 0 : variable-size-1
(min..variable).each { |var_min|
might_contains_ship = true
max = var_min+size-1 > 7 ? 7 : var_min+size-1
#puts 'size : ' + size.to_s + ' min : ' + var_min.to_s + ' max : ' + max.to_s
if max-var_min+1 != size
#puts '-> continue'
next
end
(var_min..max).each { |var|
if @grid.already_targeted?(x_vary ? var : point.x, x_vary ? point.y : var)
might_contains_ship = false
break
end
}
if might_contains_ship
score += 1
end
}
score
end
def find_neighbor(point, x_margin, y_margin)
if @grid.available_for_shoot?(point.x+x_margin, point.y)
@grid.get(point.x+x_margin, point.y)
elsif @grid.available_for_shoot?(point.x-x_margin, point.y)
@grid.get(point.x-x_margin, point.y)
elsif @grid.available_for_shoot?(point.x, point.y+y_margin)
@grid.get(point.x, point.y+y_margin)
elsif @grid.available_for_shoot?(point.x, point.y-y_margin)
@grid.get(point.x, point.y-y_margin)
else
nil
end
end
end