横浜へなちょこプログラミング勉強会にて過去に出題されたサイコロの展開図を解いてみた。
回答にかかった時間は120分程度と大幅オーバー。
ほとんどは自前で全パターンを列挙するExpandedDice#patterns
を実装する時間なので、全パターンをハードコーディングすればもっと早く出来上がったものと思われる。
メソッドの名前は上段が正面、右側、裏面、下段が下側、左側、上側と仮定した場合に回す方向で考えている。
-
ExpandedDice#rotate_topdown
: 上を12時、右側を3時、下を6時、左側を9時方向として時計回りに90度回転させる -
ExpandedDice#rotate_side
: 裏面を12時、右側を3時、正面を6時、左側を9時方向として時計回りに90度 * 指定回数回転させる -
ExpandedDice#rotate_face
: 上を12時、裏面を3時、下を6時、正面を9時方向として時計回りに90度回転させる
多分手元にサイコロがあればもっと考えがまとまりやすかったと思われる。
class ExpandedDice
Dice = "12S/453"
def initialize
@patterns = patterns
end
def masked_cell input
r = /#{input.gsub(/[wxyz]/, ".")}/
list = @patterns.select{|pattern| r === pattern}
case list.size
when 0
"none"
when 1
input.scan(/[wxyz]/).map{|m|
"#{m}=#{list[0][input.index(m)]}"
}.join(",")
else
"many"
end
end
private
def patterns
[Dice, rotate_topdown(Dice)].each_with_object([]){|dice, r|
3.times{|i|
pattern = rotate_side dice, i
rev_pattern = pattern.reverse
[
pattern, rev_pattern,
rotate_face(pattern), rotate_face(rev_pattern)
].each{|pat| r << pat}
}
}
end
def rotate_cell cell
case cell
when "2" then "D"
when "D" then "2"
when "3" then "T"
when "T" then "3"
when "6" then "S"
when "S" then "6"
else cell
end
end
def rotate_topdown dice
[
dice[0], dice[6], dice[2],
"/",
dice[1], dice[4], dice[5]
].map{|c| rotate_cell(c)}.join
end
def rotate_side dice, count
side = (dice[0..2] + dice[5]).chars.rotate(count)
[
side[0..2],
"/",
(count % 2).zero? ? dice[4] : rotate_cell(dice[4]),
(count % 2).zero? ? rotate_cell(side.last) : side.last,
(count % 2).zero? ? dice[6] : rotate_cell(dice[6])
].flatten.join
end
def rotate_face dice
dice[4..6] + "/" + dice[0..2]
end
end
test = <<_TEST
/*0*/ test( "Tx4/5yz", "x=1,y=S,z=2" );
/*1*/ test( "14S/xyz", "none" );
/*2*/ test( "1w6/xyz", "many" );
/*3*/ test( "4w3/12S", "w=5" );
/*4*/ test( "4w3/S51", "w=D" );
/*5*/ test( "15S/wD4", "w=3" );
/*6*/ test( "54D/6Tw", "w=1" );
/*7*/ test( "S21/35w", "w=4" );
/*8*/ test( "w2x/354", "w=S,x=1" );
/*9*/ test( "wx1/54D", "w=6,x=T" );
/*10*/ test( "45w/12x", "w=3,x=S" );
/*11*/ test( "5w2/x14", "w=S,x=T" );
/*12*/ test( "Dw5/x41", "w=3,x=6" );
/*13*/ test( "w4x/1y6", "w=D,x=5,y=T" );
/*14*/ test( "15w/xy4", "w=S,x=3,y=D" );
/*15*/ test( "D35/wxy", "w=6,x=4,y=1" );
/*16*/ test( "4wx/51y", "w=6,x=T,y=2" );
/*17*/ test( "wTx/D4y", "w=1,x=6,y=5" );
/*18*/ test( "wxy/z3D", "w=1,x=4,y=6,z=5" );
/*19*/ test( "wx5/1yz", "w=D,x=4,y=T,z=6" );
/*20*/ test( "w53/xyz", "w=4,x=1,y=2,z=S" );
/*21*/ test( "wx1/yzD", "w=6,x=T,y=5,z=4" );
/*22*/ test( "wxS/3yz", "w=1,x=5,y=D,z=4" );
/*23*/ test( "wx2/y1z", "w=5,x=S,y=T,z=4" );
/*24*/ test( "4wx/2yz", "w=1,x=T,y=S,z=5" );
/*25*/ test( "T6w/xyz", "w=4,x=2,y=1,z=5" );
/*26*/ test( "Swx/yDz", "w=5,x=1,y=4,z=3" );
/*27*/ test( "wDx/yzS", "w=3,x=4,y=1,z=5" );
/*28*/ test( "wxy/5Sz", "w=T,x=1,y=4,z=2" );
/*29*/ test( "wSx/4yz", "w=2,x=5,y=1,z=T" );
/*30*/ test( "wxS/y5z", "w=1,x=2,y=4,z=3" );
/*31*/ test( "wxy/35z", "w=S,x=2,y=1,z=4" );
/*32*/ test( "wxy/T6z", "w=2,x=1,y=5,z=4" );
/*33*/ test( "wxD/yz1", "w=5,x=4,y=6,z=T" );
/*34*/ test( "1wx/yz5", "w=T,x=6,y=D,z=4" );
/*35*/ test( "wx3/y5z", "w=4,x=D,y=S,z=1" );
/*36*/ test( "6wx/y3z", "w=4,x=1,y=D,z=5" );
/*37*/ test( "5wx/4yz", "w=1,x=2,y=6,z=T" );
/*38*/ test( "wx4/Syz", "w=3,x=5,y=2,z=1" );
/*39*/ test( "w3D/xyz", "w=5,x=1,y=4,z=6" );
/*40*/ test( "w3x/6yz", "w=D,x=5,y=4,z=1" );
/*41*/ test( "wxy/z12", "w=4,x=6,y=T,z=5" );
/*42*/ test( "1wS/xyz", "many" );
/*43*/ test( "wxy/Dz5", "many" );
/*44*/ test( "3w4/xyz", "many" );
/*45*/ test( "wxy/5zD", "many" );
/*46*/ test( "wxy/Tz4", "many" );
/*47*/ test( "5wD/xyz", "many" );
/*48*/ test( "wDx/y5z", "many" );
/*49*/ test( "wxy/3z4", "many" );
/*50*/ test( "wxy/5z2", "many" );
/*51*/ test( "Dyz/S1x", "none" );
/*52*/ test( "w1z/xyS", "none" );
/*53*/ test( "15x/T6y", "none" );
/*54*/ test( "zy4/5x6", "none" );
/*55*/ test( "2xy/4Tz", "none" );
/*56*/ test( "xzS/y1w", "none" );
/*57*/ test( "Syx/4z5", "none" );
/*58*/ test( "xwS/Tzy", "none" );
/*59*/ test( "D5z/xwy", "none" );
/*60*/ test( "yxD/z35", "none" );
_TEST
require 'minitest/autorun'
describe 'ExpandedDice' do
dice = ExpandedDice.new
test.split("\n").each do |line|
t, n, input, expect = line.match(/^\/\*(\d+)\*\/\s*test\(\s*"([^"]+)",\s*"([^"]+)"\s*\);*\s*$/).to_a
it input do
assert_equal expect, dice.masked_cell(input)
end
end
end