Skip to content

Instantly share code, notes, and snippets.

@shinh
Last active August 19, 2017 07:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shinh/9d2ef1d27d18687ecaeaf5b8041f4aee to your computer and use it in GitHub Desktop.
Save shinh/9d2ef1d27d18687ecaeaf5b8041f4aee to your computer and use it in GitHub Desktop.
ICFPC 2017 shinh vs unagi lightning
# shinh is shinh-fixed.rb
# wata is https://github.com/imos/icfpc2017/tree/master/wata/ with no option (thus for lightning config?)
$ ./death_match.rb ./shinh ./wata
circle ./shinh:4(139) ./shinh:3(114) ./wata:1(60) ./wata:2(98)
circle ./shinh:4(135) ./wata:1(77) ./shinh:2(79) ./wata:3(108)
circle ./shinh:2(136) ./wata:3(218) ./wata:1(26) ./shinh:4(232)
circle ./wata:4(302) ./shinh:3(143) ./shinh:2(55) ./wata:1(0)
circle ./wata:3(152) ./shinh:4(244) ./wata:1(59) ./shinh:2(131)
circle ./wata:4(329) ./wata:1(60) ./shinh:2(80) ./shinh:3(141)
MAP TOTAL: circle ./shinh:35(1629) ./wata:25(1489)
lambda ./shinh:3(37) ./shinh:4(45) ./wata:1(1) ./wata:2(14)
lambda ./shinh:4(270) ./wata:1(0) ./shinh:3(21) ./wata:2(6)
lambda ./shinh:3(28) ./wata:2(19) ./wata:1(0) ./shinh:4(40)
lambda ./wata:2(43) ./shinh:4(222) ./shinh:1(29) ./wata:3(72)
lambda ./wata:2(27) ./shinh:4(633) ./wata:1(1) ./shinh:3(39)
lambda ./wata:1(1) ./wata:2(11) ./shinh:4(229) ./shinh:3(34)
MAP TOTAL: lambda ./shinh:40(1627) ./wata:20(195)
randomMedium ./shinh:4(284) ./shinh:3(193) ./wata:2(90) ./wata:1(0)
randomMedium ./shinh:4(63) ./wata:2(0) ./shinh:3(55) ./wata:2(0)
randomMedium ./shinh:4(66) ./wata:2(26) ./wata:1(1) ./shinh:3(65)
randomMedium ./wata:4(2750) ./shinh:2(128) ./shinh:3(254) ./wata:1(0)
randomMedium ./wata:2(175) ./shinh:3(251) ./wata:1(0) ./shinh:4(814)
randomMedium ./wata:4(2834) ./wata:1(0) ./shinh:2(138) ./shinh:3(883)
MAP TOTAL: randomMedium ./shinh:38(3194) ./wata:23(5876)
randomSparse ./shinh:4(90) ./shinh:3(42) ./wata:1(0) ./wata:2(29)
randomSparse ./shinh:4(82) ./wata:1(0) ./shinh:3(38) ./wata:2(1)
randomSparse ./shinh:4(86) ./wata:2(14) ./wata:1(5) ./shinh:3(58)
randomSparse ./wata:4(496) ./shinh:3(100) ./shinh:2(72) ./wata:1(69)
randomSparse ./wata:2(10) ./shinh:4(94) ./wata:1(0) ./shinh:3(78)
randomSparse ./wata:4(268) ./wata:3(141) ./shinh:1(99) ./shinh:2(109)
MAP TOTAL: randomSparse ./shinh:36(948) ./wata:24(1033)
Sierpinski-triangle ./shinh:3(123) ./shinh:4(125) ./wata:2(45) ./wata:1(2)
Sierpinski-triangle ./shinh:2(60) ./wata:3(61) ./shinh:4(123) ./wata:1(36)
Sierpinski-triangle ./shinh:3(28) ./wata:2(3) ./wata:1(2) ./shinh:4(99)
Sierpinski-triangle ./wata:4(342) ./shinh:3(149) ./shinh:2(125) ./wata:2(125)
Sierpinski-triangle ./wata:4(352) ./shinh:3(173) ./wata:2(123) ./shinh:1(116)
Sierpinski-triangle ./wata:3(131) ./wata:4(247) ./shinh:1(54) ./shinh:2(116)
MAP TOTAL: Sierpinski-triangle ./shinh:32(1291) ./wata:29(1469)
circle ./shinh:2(134) ./shinh:4(174) ./wata:1(103) ./wata:3(154)
circle ./shinh:3(124) ./wata:2(86) ./shinh:4(128) ./wata:1(47)
circle ./shinh:2(128) ./wata:3(159) ./wata:1(49) ./shinh:4(187)
circle ./wata:4(328) ./shinh:3(201) ./shinh:2(139) ./wata:1(123)
circle ./wata:3(242) ./shinh:4(284) ./wata:1(35) ./shinh:2(130)
circle ./wata:4(330) ./wata:1(0) ./shinh:2(136) ./shinh:3(156)
MAP TOTAL: circle ./shinh:35(1921) ./wata:25(1656)
lambda ./shinh:4(332) ./shinh:3(70) ./wata:2(26) ./wata:1(12)
lambda ./shinh:4(369) ./wata:2(0) ./shinh:1(-99) ./wata:3(6)
lambda ./shinh:4(386) ./wata:1(0) ./wata:2(21) ./shinh:3(55)
lambda ./wata:3(231) ./shinh:4(332) ./shinh:1(-98) ./wata:2(19)
lambda ./wata:3(79) ./shinh:4(399) ./wata:2(9) ./shinh:1(-93)
lambda ./wata:4(496) ./wata:3(210) ./shinh:2(202) ./shinh:1(115)
MAP TOTAL: lambda ./shinh:32(1970) ./wata:28(1109)
randomMedium ./shinh:1(-581) ./shinh:2(-79) ./wata:3(34) ./wata:4(251)
randomMedium ./shinh:2(-525) ./wata:4(14) ./shinh:1(-611) ./wata:3(9)
randomMedium ./shinh:1(-610) ./wata:4(394) ./wata:3(39) ./shinh:2(-561)
randomMedium ./wata:4(2404) ./shinh:1(-554) ./shinh:2(-481) ./wata:3(28)
randomMedium ./wata:3(0) ./shinh:2(-512) ./wata:4(538) ./shinh:1(-569)
randomMedium ./wata:4(2834) ./wata:2(0) ./shinh:1(-548) ./shinh:3(197)
MAP TOTAL: randomMedium ./shinh:19(-5434) ./wata:41(6545)
randomSparse ./shinh:1(-164) ./shinh:2(-161) ./wata:4(33) ./wata:3(9)
randomSparse ./shinh:4(210) ./wata:2(1) ./shinh:1(-206) ./wata:3(10)
randomSparse ./shinh:4(356) ./wata:3(44) ./wata:2(6) ./shinh:1(-158)
randomSparse ./wata:4(496) ./shinh:2(-150) ./shinh:1(-178) ./wata:3(69)
randomSparse ./wata:4(10) ./shinh:2(-156) ./wata:3(0) ./shinh:1(-172)
randomSparse ./wata:4(268) ./wata:3(141) ./shinh:1(-151) ./shinh:2(-141)
MAP TOTAL: randomSparse ./shinh:22(-1071) ./wata:38(1087)
Sierpinski-triangle ./shinh:2(96) ./shinh:4(355) ./wata:3(320) ./wata:1(77)
Sierpinski-triangle ./shinh:3(113) ./wata:4(380) ./shinh:3(113) ./wata:1(106)
Sierpinski-triangle ./shinh:4(104) ./wata:1(12) ./wata:2(53) ./shinh:3(89)
Sierpinski-triangle ./wata:3(647) ./shinh:2(113) ./shinh:2(113) ./wata:4(972)
Sierpinski-triangle ./wata:2(139) ./shinh:4(176) ./wata:1(116) ./shinh:3(145)
Sierpinski-triangle ./wata:2(197) ./wata:4(661) ./shinh:3(355) ./shinh:1(113)
MAP TOTAL: Sierpinski-triangle ./shinh:34(1885) ./wata:28(3680)
OVERALL: ./shinh:323(7960) ./wata:281(24139)
#!/usr/bin/env ruby
# $ bazel build stadium
# $ ./death_match.rb ./shinh ./wata
# diff --git a/stadium/local_punter.cc b/stadium/local_punter.cc
# index 133015e..9d80c10 100644
# --- a/stadium/local_punter.cc
# +++ b/stadium/local_punter.cc
# @@ -58,15 +58,16 @@ PunterInfo LocalPunter::SetUp(const common::SetUpData& args) {
# std::vector<River> futures;
# if (args.settings.futures) {
# const base::ListValue* futures_list;
# - CHECK(response->GetList("futures", &futures_list));
# - for (int i = 0; i < futures_list->GetSize(); ++i) {
# - const base::DictionaryValue* future_value;
# - CHECK(futures_list->GetDictionary(i, &future_value));
# - int source, target;
# - CHECK(future_value->GetInteger("source", &source));
# - CHECK(future_value->GetInteger("target", &target));
# - futures.push_back(River{source, target});
# - // TDOO check if source is mine.
# + if (response->GetList("futures", &futures_list)) {
# + for (int i = 0; i < futures_list->GetSize(); ++i) {
# + const base::DictionaryValue* future_value;
# + CHECK(futures_list->GetDictionary(i, &future_value));
# + int source, target;
# + CHECK(future_value->GetInteger("source", &source));
# + CHECK(future_value->GetInteger("target", &target));
# + futures.push_back(River{source, target});
# + // TDOO check if source is mine.
# + }
# }
# }
# return {name, futures};
MAPS = %w(circle lambda randomMedium randomSparse Sierpinski-triangle)
combs = []
(2**4).times do |i|
s = '%04b' % i
combs << s.chars.map(&:to_i) if s.count('0') == 2
end
combs = combs.sort.uniq
AIS = ARGV
def run(ais, map, future)
args = ['./bazel-bin/stadium/stadium']
args << "--map=maps/#{map}.json"
args << "--futures" if future
args += ais
args = args.join(' ') + " 2>&1"
#puts args
scores = []
pipe = IO.popen(args, "r:binary")
pipe.each do |line|
if line =~ /Punter: (\d+), Score: (-?\d+)/
scores[$1.to_i] = $2.to_i
end
end
scores
end
def calc_points(scores)
scores = scores.each_with_index.sort.reverse
points = []
prev_score = 1e100
prev_point = 99
point = 4
scores.each do |score, index|
if score == prev_score
points[index] = prev_point
else
points[index] = point
prev_score = score
prev_point = point
end
point -= 1
end
points
end
total_points = {}
total_scores = {}
AIS.each do |ai|
total_points[ai] = 0
total_scores[ai] = 0
end
[false, true].each do |future|
MAPS.each do |map|
set_points = {}
set_scores = {}
AIS.each do |ai|
set_points[ai] = 0
set_scores[ai] = 0
end
combs.each do |comb|
ais = comb.map{|c|AIS[c]}
scores = run(ais, map, future)
points = calc_points(scores)
a = []
ais.size.times do |i|
ai = ais[i]
total_scores[ai] += scores[i]
total_points[ai] += points[i]
set_scores[ai] += scores[i]
set_points[ai] += points[i]
a << "#{ai}:#{points[i]}(#{scores[i]})"
end
puts "#{map} #{a * ' '}"
end
a = []
AIS.each do |ai|
a << "#{ai}:#{set_points[ai]}(#{set_scores[ai]})"
end
puts "MAP TOTAL: #{map} #{a * ' '}"
end
end
a = []
AIS.each do |ai|
a << "#{ai}:#{total_points[ai]}(#{total_scores[ai]})"
end
puts "OVERALL: #{a * ' '}"
#!/usr/bin/ruby
require 'json'
SERV = 'punter.inf.ed.ac.uk'
NAME = 'anago'
class Site
attr_reader :id, :x, :y, :site
attr_accessor :is_mine
def initialize(id, x, y, site)
@id = id
@x = x
@y = y
@is_mine = false
@site = site
end
def clone
s = Site.new(@id, @x, @y, @site)
s.is_mine = @is_mine
s
end
end
class River
attr_reader :st, :river
attr_accessor :pid
def initialize(s, t, river)
@st = [s, t]
@river = river
@pid = nil
end
def id
@st
end
def clone
r = River.new(@st[0], @st[1], @river)
r.pid = @pid
r
end
def another(s)
if @st[0] == s
@st[1]
elsif @st[1] == s
@st[0]
else
raise
end
end
end
class State
attr_reader :pid, :npt, :done
attr_reader :sites, :rivers, :mines, :futures
attr_accessor :use_rand
def initialize
@done = false
end
def has_mine(river)
@sites[river.st[0]].is_mine || @sites[river.st[1]].is_mine
end
def clone(o)
@pid = o.pid
@npt = o.npt
@done = o.done
@sites = {}
o.sites.each do |_, site|
@sites[site.id] = site.clone
end
@rivers = {}
o.rivers.each do |_, river|
@rivers[river.id] = river.clone
end
@mines = o.mines.dup
@futures = o.futures.dup
self
end
def setup(setup)
@pid = setup['punter']
@npt = setup['punters']
map = setup['map']
if setup['futures']
set_futures(setup['futures'])
end
@sites = {}
map['sites'].each do |site|
id = site['id'].to_i
x = site['x'].to_f
y = site['y'].to_f
@sites[id] = Site.new(id, x, y, site)
end
@rivers = {}
map['rivers'].each do |river|
s = river['source'].to_i
t = river['target'].to_i
@rivers[[s,t]] = River.new(s, t, river)
end
@mines = []
map['mines'].each do |mine|
@mines << mine
@sites[mine].is_mine = true
end
STDERR.puts "pid=#{@pid} npt=#{@npt} sites=#{@sites.size} rivers=#{@rivers.size} mines=#{@mines.size}"
end
def set_futures(futures)
@futures = {}
futures.each do |future|
@futures[future['source']] = future['target']
end
end
def search_paths(from, pid)
scores = []
queue = [[from, 0]]
until queue.empty?
sid, distance = queue.shift
next if scores[sid]
scores[sid] = distance
@site_to_rivers[sid].each do |river|
next if pid && river.pid != pid
nsid = river.another(sid)
queue.push([nsid, distance + 1])
end
end
scores
end
def construct_score_map
return if @score_map
@site_to_rivers = []
@rivers.each do |st, river|
@site_to_rivers[st[0]] = [] if !@site_to_rivers[st[0]]
@site_to_rivers[st[0]] << river
@site_to_rivers[st[1]] = [] if !@site_to_rivers[st[1]]
@site_to_rivers[st[1]] << river
end
@score_map = {}
@mines.each do |mine|
@score_map[mine] = search_paths(mine, nil)
end
end
def calc_score_impl(pid, futures)
construct_score_map
score = 0
fscore = 0
if futures
futures.each do |mine, to|
len = @score_map[mine][to]
fscore -= len ** 3
end
end
@mines.each do |mine|
search_paths(mine, pid).each_with_index do |d, to|
if d
len = @score_map[mine][to]
score += len ** 2
if futures && futures[mine] == to
fscore += len ** 3 * 2
end
end
end
end
[score, fscore]
end
def calc_score(pid)
score, fscore = calc_score_impl(pid, pid == @pid ? @futures : nil)
score + fscore
end
def handle_claim(claim)
pid = claim['punter']
raise "What? #{claim.inspect}" if !pid
s = claim['source']
raise "What? #{claim.inspect}" if !s
t = claim['target']
raise "What? #{claim.inspect}" if !t
pid = pid.to_i
s = s.to_i
t = t.to_i
s, t = t, s if !@rivers[[s, t]]
raise 'Broken!' if @rivers[[s, t]].pid
@rivers[[s, t]].pid = pid
end
def handle_moves(m)
moves = if m['stop']
@done = true
@scores = m['stop']['scores']
m['stop']['moves']
elsif m['move']
m['move']['moves']
else
raise if !m['moves']
m['moves']
end
moves.each do |move|
if claim = move['claim']
handle_claim(claim)
elsif move['pass']
else
raise "What? #{move.inspect}"
end
end
end
def search_cost(source, target)
construct_score_map
seen = {}
cost_queue = [[0, source]]
best_cost = @rivers.size
until cost_queue.empty?
cost, sid = cost_queue.shift
if sid == target
best_cost = cost
break
end
next if seen[sid]
seen[sid] = cost
@site_to_rivers[sid].each do |river|
nid = river.another(sid)
if river.pid == @pid
cost_queue.unshift [cost, nid]
elsif !river.pid
cost_queue << [cost + 1, nid]
end
end
#cost_queue.sort!
end
best_cost
end
def calc_future_cost
if !@futures
return 0
end
total_cost = 0
@futures.each do |source, target|
cost = search_cost(source, target)
#STDERR.puts "cost #{source}=>#{target}: #{cost}" if @pid == 0
total_cost += cost
end
total_cost
end
def choose(pid)
construct_score_map
cands = []
@rivers.each do |_, river|
if !river.pid
score = 0
river.st.each do |f|
if @sites[f].is_mine
score += 1000
end
@site_to_rivers[f].each do |r|
if r.pid == pid
score += 200
end
end
if @futures && @futures[f]
score += 10000
end
end
cands << [score, river]
end
end
cands = cands.sort_by{|s,_|-s}.map{|_, cand|cand}
start_time = Time.now
best_river = nil
best_score = -1e100
cands.each do |river|
if Time.now - start_time > 0.9
STDERR.puts "timeout!"
break
end
raise if river.pid
river.pid = pid
score = calc_score(pid) * 100.0
#STDERR.puts "#{river.st}" if @pid == 0
score -= calc_future_cost * 10000.0
if has_mine(river)
score += 1000.0
end
@mines.each do |mine|
river.st.each do |v|
d = @score_map[mine][v]
# TODO: really?
next if !d
score += 300.0 / (d + 1)
end
end
if best_score < score
best_score = score
best_river = river
end
river.pid = nil
end
[best_river, best_score]
end
def decide_move
start_time = Time.now
chosen, best_score = choose(@pid)
elapsed = Time.now - start_time
if elapsed > 0.5
STDERR.puts "*** SLOW!!!!! ***"
end
STDERR.puts "best_score=#{best_score} elapsed=#{elapsed}"
#chosen = cands[rand(cands.size)]
{
'claim' => {
'punter' => @pid,
'source' => chosen.st[0],
'target' => chosen.st[1],
}
}
end
def myrand(*n)
if @use_rand
rand(*n)
else
0
end
end
def decide_futures
construct_score_map
num_moves = @rivers.size / @npt
#future_len = num_moves / 4
future_len = Math.sqrt(num_moves)
if future_len < 2
future_len = 2
end
STDERR.puts "future_len=#{future_len}"
best_pair = nil
best_score = 1e100
@mines.each do |m1|
@mines.each do |m2|
next if m1 == m2
len = @score_map[m1][m2]
#STDERR.puts "m1=#{m1} m2=#{m2} len=#{len}"
score = (len - future_len) ** 2 + myrand * future_len
if best_score > score
best_score = score
best_pair = [m1, m2]
end
end
end
return [] if !best_pair
futures = []
[best_pair, best_pair.reverse].each do |m1, m2|
best_target = nil
best_score = 1e100
@site_to_rivers[m2].each do |river|
m3 = river.another(m2)
next if @sites[m3].is_mine
len = @score_map[m1][m3]
score = (len - future_len) ** 2
if best_score > score
best_score = score
best_target = m3
end
end
if best_target
STDERR.puts "future: #{m1}=>#{best_target} #{@score_map[m1][best_target]}"
futures << {
"source" => m1,
"target" => best_target,
}
end
end
set_futures(futures)
futures
end
def summary(futures=nil)
scores = []
@npt.times do |pid|
f = if futures
futures[pid]
else
pid == @pid ? @futures : nil
end
score, fscore = calc_score_impl(pid, f)
ss = ''
if f
ss = "#{score+fscore}(#{fscore})"
else
ss = "#{score+fscore}"
end
if pid == @pid
ss = "*#{ss}"
end
scores << ss
end
scores * ' '
end
end
class Visualizer
def initialize(st)
require 'sdl'
xs = []
ys = []
st.sites.each do |_, site|
xs << site.x
ys << site.y
end
@min_x = xs.min
@max_x = xs.max
@min_y = ys.min
@max_y = ys.max
SDL.init(SDL::INIT_VIDEO)
@w = 1000
@h = 1000
@scr = SDL.set_video_mode(@w, @h, 32, SDL::SWSURFACE)
end
def show(st)
conv_x = proc{|x|
(x - @min_x) * (@w - 40) / (@max_x - @min_x) + 20
}
conv_y = proc{|y|
(y - @min_y) * (@h - 40) / (@max_y - @min_y) + 20
}
st.futures.each do |s, t|
color = [255,255,0]
@scr.draw_line(conv_x[st.sites[s].x]+2,
conv_y[st.sites[s].y]+2,
conv_x[st.sites[t].x]+2,
conv_y[st.sites[t].y]+2,
color)
end if st.futures
st.rivers.each do |_, river|
s, t = river.st
color = if river.pid == st.pid
[0,255,0]
elsif river.pid
v = river.pid / st.npt.to_f
[v*255,0,(1-v)*255]
else
[255,255,255]
end
@scr.draw_line(conv_x[st.sites[s].x],
conv_y[st.sites[s].y],
conv_x[st.sites[t].x],
conv_y[st.sites[t].y],
color)
end
st.sites.each do |_, site|
color = site.is_mine ? [255,0,0] : [255,255,255]
@scr.draw_circle(conv_x[site.x], conv_y[site.y], 3, color)
end
@scr.flip
end
end
def send_impl(fd, j)
j = JSON.dump(j)
STDERR.puts "=> #{j} =>"
msg = "#{j.size}:#{j}"
fd.print msg
fd.flush
end
def recv_impl(fd)
r = ''
loop {
c = fd.getc
break if c == ':'
r += c
}
j = fd.read(r.to_i)
STDERR.puts "<= #{j} <="
JSON.load(j)
end
def handshake(send, recv)
send[{'me' => NAME}]
r = recv[]
if r['you'] != NAME
raise "What? #{r}"
end
end
if ARGV[0] =~ /\.json$/
map_to_npt = {}
%w(sample).each{|n|map_to_npt[n] = 2}
%w(Sierpinski-triangle).each{|n|map_to_npt[n] = 3}
%w(lambda circle randomMedium randomSparse).each{|n|map_to_npt[n] = 4}
%w(boston-sparse tube).each{|n|map_to_npt[n] = 8}
%w(edinburgh-sparse nara-sparse oxford-sparse gothenburg-sparse).each{|n|
map_to_npt[n] = 16
}
name = File.basename($`)
npt = map_to_npt[name]
map = JSON.parse(File.read(ARGV[0]))
states = []
npt.times do |pid|
state = State.new
state.use_rand = true
setup = {
'punter' => pid,
'punters' => npt,
'map' => map,
}
state.setup(setup)
state.decide_futures
states << state
end
viz = Visualizer.new(states[0])
pid = 0
states[0].rivers.size.times do |turn|
river, best_score = states[pid].choose(pid)
states.each do |st|
st.rivers[river.st].pid = pid
end
futures = {}
states.each do |st|
futures[st.pid] = st.futures
end
STDERR.puts states[pid].summary(futures)
viz.show(states[0])
while false
ev = SDL::Event2.wait
case ev
when SDL::Event2::KeyDown
case ev.sym
when SDL::Key::ESCAPE
exit
end
break
end
end
pid = (pid + 1) % states[0].npt
end
elsif !ARGV[0]
send = proc {|j| send_impl(STDOUT, j) }
recv = proc { recv_impl(STDIN) }
handshake(send, recv)
msg = recv[]
if msg['map']
state = State.new
state.setup(msg)
settings = msg['settings']
if settings && settings['futures']
futures = state.decide_futures
end
msg['moves'] = []
msg.delete('state')
msg['futures'] = futures if futures
reply = {
'ready' => state.pid,
'state' => msg,
}
reply['futures'] = futures if futures
send[reply]
elsif msg['stop']
# nothing to do.
else
state_msg = msg['state']
state = State.new
state.setup(state_msg)
state.handle_moves(state_msg)
state.handle_moves(msg)
move = state.decide_move
state_msg['moves'] += msg['move']['moves']
state_msg.delete('state')
reply = move
reply['state'] = state_msg
send[reply]
end
elsif ARGV[0] =~ /^\d+$/
require 'socket'
sock = TCPSocket.new(SERV, ARGV[0].to_i)
send = proc {|j| send_impl(sock, j) }
recv = proc { recv_impl(sock) }
handshake(send, recv)
setup = recv[]
state = State.new
state.setup(setup)
settings = setup['settings']
if settings && settings['futures']
futures = state.decide_futures
end
msg = {'ready' => state.pid}
msg['futures'] = futures if futures
send[msg]
move = nil
loop {
STDERR.puts state.summary
moves = recv[]
state.handle_moves(moves)
if state.done
break
end
move = state.decide_move
send[move]
}
state.handle_claim(move['claim'])
STDERR.puts state.summary
elsif ARGV[0]
lines = File.readlines(ARGV[0])
states = []
state = nil
last_claim = nil
lines.each do |line|
j = if line =~ /^(<=|=>)(.*)\1/ || line =~ /^(<=|=>)(.*)$/
JSON.load($2)
end
next if !j
req = $1 == '=>'
if j['ready'] && j['futures']
state.set_futures(j['futures'])
elsif j['map']
state = State.new
state.setup(j)
states.push(state)
elsif j['claim']
last_claim = j['claim']
elsif (j['move'] || j['stop']) && !req
nstate = State.new
nstate.clone(state)
nstate.handle_moves(j)
if j['stop']
if last_claim
nstate.handle_claim(last_claim)
end
end
state = nstate
states.push(state)
end
end
viz = Visualizer.new(states[0])
n = 0
was_down = false
state_changed = true
while true
st = states[n]
if state_changed
state_changed = false
summary = st.summary
STDERR.puts "#{n}/#{states.size}"
STDERR.puts summary
end
viz.show(st)
ev = SDL::Event2.wait
case ev
when SDL::Event2::Quit
exit
when SDL::Event2::KeyDown
if !was_down
was_down = true
case ev.sym
when SDL::Key::N
n += 1
if states[n]
state_changed = true
else
n -= 1
end
when SDL::Key::P
n -= 1
if n >= 0
state_changed = true
else
n += 1
end
when SDL::Key::ESCAPE
exit
end
end
when SDL::Event2::KeyUp
was_down = false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment