横浜へなちょこプログラミング勉強会にて過去に出題された十字の壁がそそり立つ世界の中を君は螺旋状に歩くを解いてみた。
回答にかかった時間は90分程度。
別実装を30分程度で書いたのだが、それだと追加問題に対応できなかった。
追加問題にも対応するため再度実装しなおしたのがこの実装となる。
追加問題についても答えが載っていたので、他のテストケースと同じ形式に直してテストケースに追加する形を取っている。
CrossWallWorld#roundingのeach内でbreakすることで本来selfが返ってくるはずなのに数値を返したり、CrossWallWorld#goのinjectで数字を回しておきながらbreakでSymbolを返すというなんとも気持ち悪い実装をしている。
読み返してもやっぱり気持ち悪いのだが、他にいいやり方も思いつかないのでこのままにしている。
class CrossWallWorld
def travel input
wall, days = input.split ":"
@north, @east, @south, @west = wall.split(",").map &:to_i
go *rounding(days.to_i)
end
private
def rounding days
c = (1..Float::INFINITY).each{|c, _|
r = @north * 2 + @east * 2 + @south * 2 + @west * 2 + c * 8
break c if days < r
days -= r
}
[days, c]
end
def go days, count
[
[@east, :E], [count * 2, :S], [@east, :W],
[@south, :S], [count * 2, :W], [@south, :N],
[@west, :W], [count * 2, :N], [@west, :E],
[@north, :N], [count * 2, :E], [@north - 1, :S],
[@east, :E]
].inject(0){|d, (len, way)|
break way if days < (d + len)
d + len
}.to_s
end
end
test = <<_TEST
/*0*/ test( "2,3,5,4:85", "S" );
/*1*/ test( "1,2,3,4:1", "E" );
/*2*/ test( "1,2,3,4:2", "S" );
/*3*/ test( "1,2,3,4:3", "S" );
/*4*/ test( "1,2,3,4:4", "W" );
/*5*/ test( "1,2,3,4:27", "E" );
/*6*/ test( "1,2,3,4:63", "E" );
/*7*/ test( "1,2,3,4:40", "W" );
/*8*/ test( "1,4,3,2:40", "S" );
/*9*/ test( "3,3,3,3:30", "S" );
/*10*/ test( "3,3,3,3:31", "E" );
/*11*/ test( "3,3,3,3:32", "E" );
/*12*/ test( "3,3,3,3:70", "S" );
/*13*/ test( "3,3,3,3:71", "E" );
/*14*/ test( "3,3,3,3:72", "E" );
/*15*/ test( "1,1,1,1:7", "N" );
/*16*/ test( "1,2,1,1:7", "W" );
/*17*/ test( "1,6,1,1:7", "S" );
/*18*/ test( "1,8,1,1:7", "E" );
/*19*/ test( "1,1,1,1:30", "N" );
/*20*/ test( "1,2,1,1:30", "W" );
/*21*/ test( "1,5,1,1:30", "S" );
/*22*/ test( "1,8,1,1:30", "E" );
/*23*/ test( "9,9,9,9:99", "W" );
/*24*/ test( "5,6,3,8:3", "E" );
/*25*/ test( "5,8,1,1:11", "W" );
/*26*/ test( "2,8,1,2:18", "S" );
/*27*/ test( "3,2,3,1:20", "N" );
/*28*/ test( "3,3,8,1:28", "N" );
/*29*/ test( "2,5,1,2:32", "E" );
/*30*/ test( "2,5,1,6:33", "E" );
/*31*/ test( "1,2,5,7:34", "N" );
/*32*/ test( "3,6,5,6:36", "E" );
/*33*/ test( "6,2,8,1:39", "S" );
/*34*/ test( "3,1,2,3:41", "W" );
/*35*/ test( "1,1,3,4:45", "W" );
/*36*/ test( "1,3,1,2:46", "N" );
/*37*/ test( "4,4,4,4:49", "W" );
/*38*/ test( "3,1,4,4:55", "N" );
/*39*/ test( "6,6,2,1:56", "W" );
/*40*/ test( "3,2,1,2:59", "S" );
/*41*/ test( "2,7,7,1:60", "S" );
/*42*/ test( "3,1,1,1:63", "N" );
/*43*/ test( "4,6,4,1:78", "E" );
/*44*/ test( "7,5,3,6:79", "W" );
/*45*/ test( "7,8,3,1:81", "E" );
/*46*/ test( "3,2,5,2:82", "S" );
/*47*/ test( "1,1,3,4:84", "N" );
/*48*/ test( "7,4,1,5:88", "S" );
/*49*/ test( "3,6,5,3:89", "S" );
/*50*/ test( "1,4,2,3:92", "N" );
/*51*/ test( "1,3,4,5:93", "W" );
/*52*/ test( "2,4,8,1:94", "W" );
/*53*/ test( "3,6,1,7:99", "S" );
/*54*/ test( "1234,2345,3456,4567:978593417", "E" );
/*55*/ test( "1234,2345,3456,4567:978593418", "S" );
/*56*/ test( "31415,92653,58979,32384:9812336139", "W" );
/*57*/ test( "31415,92653,58979,32384:9812336140", "S" );
/*58*/ test( "314159,265358,979323,84626:89099331642", "S" );
/*59*/ test( "314159,265358,979323,84626:89099331643", "W" );
_TEST
require 'minitest/autorun'
describe 'CrossWallWorld' do
test.split("\n").each do |line|
t, n, input, expect = line.match(/^\/\*(\d+)\*\/\s*test\(\s*"([^"]+)",\s*"([^"]+)"\s*\);*\s*$/).to_a
world = CrossWallWorld.new
it input do
assert_equal expect, world.travel(input)
end
end
end