-
-
Save shinh/9d2ef1d27d18687ecaeaf5b8041f4aee to your computer and use it in GitHub Desktop.
ICFPC 2017 shinh vs unagi lightning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 * ' '}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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