This repository has been archived by the owner on Aug 8, 2023. It is now read-only.
/
bao-best-draw.rb
executable file
·111 lines (90 loc) · 2.62 KB
/
bao-best-draw.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
#!/usr/bin/ruby
# Model
class Bao
def initialize fields, enemy_fields
@fields = fields
@enemy_fields = enemy_fields
end
public
attr_reader :fields, :enemy_fields
def draw field, first_draw = true
# set position
@position = field
# take own stones in hand
@hand = @fields[@position]
@fields[@position] = 0
# take from enemy
if enemy_bordering? and not first_draw
@hand += @enemy_fields[bordering(@position)]
@enemy_fields[bordering(@position)] = 0
end
# put stones down
while @hand > 0
@position = (@position + 1) % (@fields.length)
@fields[@position] += 1
@hand -= 1
end
# draw again?
draw(@position, false) if @fields[@position] >= 2
end
def balance
(@fields.inject(0, :+) - @enemy_fields.inject(0, :+)) / 2
end
def render
pitch_width = @fields.length / 2
p @enemy_fields.slice(0, pitch_width).join(";")
p @enemy_fields.slice(pitch_width, (pitch_width*2)).reverse.join(";")
p @fields.slice(pitch_width, (pitch_width*2)).join(";")
p @fields.slice(0, pitch_width).reverse.join(";")
end
private
def enemy_bordering?
# is an enemy field bordering?
@position > (@fields.count+1)/2
end
def bordering field
@fields.length - 1 - (field - @fields.length/2)
end
end
# Controller
class BaoBestDraw
def initialize fields, enemy_fields = nil
# init
best = nil
best_draw = nil
# try each field as starting point
fields.length.times do |start_field|
start_field = 13
# start simulation
bao = Bao.new fields.dup, enemy_fields.dup
bao.draw start_field
# have new winner?
if not best or bao.balance > best.balance
best = bao
best_draw = start_field
end
break
end
# render
p "best draw: #{best_draw + 1}; #{best.balance} stones stolen"
best.render
end
private
def ___render bao
pitch_width = bao.fields.length / 2
buffer = bao.enemy_fields.slice(0, pitch_width).join(";")
buffer += "\n" + bao.enemy_fields.slice(pitch_width, (pitch_width*2)).reverse.join(";")
buffer += "\n" + bao.fields.slice(pitch_width, (pitch_width*2)).join(";")
buffer += "\n" + bao.fields.slice(0, pitch_width).reverse.join(";")
end
end
# parse params
default = "2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2"
fields = (
Hash[ARGV.join(' ').scan(/--?([^=\s]+)(?:=(\S+))?/)]["fields"] || default
).split(";").map(&:to_i)
enemy_fields = (
Hash[ARGV.join(' ').scan(/--?([^=\s]+)(?:=(\S+))?/)]["enemy_fields"] || default
).split(";").map(&:to_i)
# go!
BaoBestDraw.new fields, enemy_fields