どう書く
オフラインリアルタイムどう書くの 会場や問題のリスト - 鍋あり谷あり
ポーカー
https://qiita.com/Nabetani/items/cbc3af152ee3f50a822f
Suit = %W(S H D C) Rank = %W(2 3 4 5 6 7 8 9 10 J Q K A) def cards Suit.flat_map {|s| Rank.map {|r| s + r} }.sample(5).join end t = Regexp.compile("[#{Suit.join}]") counted = cards.chars.slice_before(t).map {|a, *b| b.join} .tally.values.sort.reverse ans = if counted[0] == 4 "4K" elsif counted[0] == 3 && counted[1] == 2 "FH" elsif counted[0] == 3 "3K" elsif counted[0] == 2 && counted[1] == 2 "2P" elsif counted[0] == 2 "1P" else "--" end puts ans
別解。
Suit = %W(S H D C) Rank = %W(2 3 4 5 6 7 8 9 10 J Q K A) def cards Suit.flat_map {|s| Rank.map {|r| s + r} }.sample(5).join end t = Regexp.compile("[#{Suit.join}]") counted = cards.chars.slice_before(t).map {|a, *b| b.join} .tally.values.sort.reverse.join ["4", "32", "3", "22", "2", "1"].zip(%W(4K FH 3K 2P 1P --)).each do |c, h| if counted.start_with?(c) puts h break end end
Tick-Tack-Toe
http://nabetani.sakura.ne.jp/hena/1/
class TickTackToe WinPattern = %W(123 456 789 147 258 369 159 357) def initialize(input) @input = input.chars.map(&:to_i) @field = Array.new(10) @turn = 0 #o @ptns = WinPattern.map {|pt| pt.chars.map(&:to_i)} end def solve @input.each do |i| if @field[i] return "Foul : #{output_turn(false)} won." else @field[i] = @turn if settle? return "#{output_turn} won." elsif @field[1..9].all? return "Draw game." else @turn = 1 - @turn end end end end def settle? @ptns.any? do |pt| a = pt.map {|i| @field[i]}.join a == "000" || a == "111" end end def output_turn(t = true) %W(o x)[t ? @turn : 1 - @turn] end def self.solve(input) new(input).solve end end if $0 == __FILE__ data = [79538246, 35497162193, 61978543, 254961323121, 6134278187, 4319581, 9625663381, 7975662, 2368799597, 18652368566, 965715, 38745796, 371929, 758698769, 42683953, 618843927, 36535224, 882973, 653675681, 9729934662, 972651483927, 5439126787, 142583697, 42198637563, 657391482] data.each do |d| puts TickTackToe.solve(d.to_s) end end
二値画像の回転
https://qiita.com/Nabetani/items/9d80de41903775296ca6
class BinaryImageRotation def initialize(input) l, @binary = input.split(":") @l = l.to_i end def solve n = (@l ** 2 / 4.0).ceil * 4 ans = @binary.chars.map {|c| c.to_i(16).to_s(2).rjust(4, "0")} .join[0, @l ** 2].chars.map(&:to_i).each_slice(@l) .to_a.reverse.transpose .join.ljust(n, "0").chars.each_slice(4) .map {|ary| ary.join.to_i(2).to_s(16)}.join "#{@l}:" + ans end def self.exec(input) new(input).solve end end if __FILE__ == $0 require 'minitest/autorun' describe 'BinaryImageRotation' do [ ["3:5b8", "3:de0"], ["1:8", "1:8"], ["2:8", "2:4"], ["2:4", "2:1"], ["2:1", "2:2"], ["3:5d0", "3:5d0"], ["4:1234", "4:0865"], ["5:22a2a20", "5:22a2a20"], ["5:1234567", "5:25b0540"], ["6:123456789", "6:09cc196a6"], ["7:123456789abcd", "7:f1a206734b258"], ["7:fffffffffffff", "7:ffffffffffff8"], ["7:fdfbf7efdfbf0", "7:ffffffffffc00"], ["8:123456789abcdef1", "8:f0ccaaff78665580"], ["9:112233445566778899aab", "9:b23da9011d22daf005d40"] ].each do |input, expect| it input do assert_equal BinaryImageRotation.exec(input), expect end end end end
Bit Tetris
http://nabetani.sakura.ne.jp/hena/ord2/
module BitTetris module_function def solve(input) field = input.split("-").map { _1.to_i(16) } to_be_erased = to_a(field.inject(:&)) field.map { "%02x" % erase(_1, to_be_erased) }.join("-") end def erase(i, to_be_erased) to_a(i).zip(to_be_erased).map { |s, t| t == "1" ? "" : s }.join.to_i(2) end def to_a(i) sprintf("%08b", i).chars end end if __FILE__ == $0 require 'minitest/autorun' describe 'BitTetris' do [ ["ff-2f-23-f3-77-7f-3b", "1f-03-00-1c-0d-0f-06"], ["01", "00"], ["00", "00"], ["7a-4e", "0c-02"], ["56-b6", "08-14"], ["12-12-12", "00-00-00"], ["de-ff-7b", "0a-0f-05"], ["95-be-d0", "05-1e-20"], ["7c-b0-bb", "1c-20-2b"], ["7a-b6-31-6a", "3a-56-11-2a"], ["32-0e-23-82", "18-06-11-40"], ["ff-7f-bf-df-ef", "0f-07-0b-0d-0e"], ["75-df-dc-6e-42", "35-5f-5c-2e-02"], ["62-51-ef-c7-f8", "22-11-6f-47-78"], ["0c-47-8e-dd-5d-17", "04-23-46-6d-2d-0b"], ["aa-58-5b-6d-9f-1f", "52-28-2b-35-4f-0f"], ["ff-55-d5-75-5d-57", "0f-00-08-04-02-01"], ["fe-fd-fb-f7-ef-df-bf", "7e-7d-7b-77-6f-5f-3f"], ["fd-fb-f7-ef-df-bf-7f", "7e-7d-7b-77-6f-5f-3f"], ["d9-15-b5-d7-1b-9f-de", "69-05-55-67-0b-4f-6e"], ["38-15-fd-50-10-96-ba", "18-05-7d-20-00-46-5a"], ["fe-fd-fb-f7-ef-df-bf-7f", "fe-fd-fb-f7-ef-df-bf-7f"] ].each do |input, expect| it input do assert_equal BitTetris.solve(input), expect end end end end
ボールカウント(野球)
https://qiita.com/Nabetani/items/ebd8a56b41711ba459f9
module BallCount def self.solve(input) out = strike = ball = 0 sb_zero = ->{ strike = ball = 0 } input.each_char.map {|c| case c when "s" strike += 1 if strike == 3 sb_zero.() out += 1 end when "b" ball += 1 sb_zero.() if ball == 4 when "h" sb_zero.() when "p" out += 1 sb_zero.() when "f" strike += 1 if strike <= 1 end out = strike = ball = 0 if out == 3 "#{out}#{strike}#{ball}" }.join(",") end end if __FILE__ == $0 require 'minitest/autorun' describe 'BallCount' do [ ["s", "010"], ["sss", "010,020,100"], ["bbbb", "001,002,003,000"], ["ssbbbb", "010,020,021,022,023,000"], ["hsbhfhbh", "000,010,011,000,010,000,001,000"], ["psbpfpbp", "100,110,111,200,210,000,001,100"], ["ppp", "100,200,000"], ["ffffs", "010,020,020,020,100"], ["ssspfffs", "010,020,100,200,210,220,220,000"], ["bbbsfbppp", "001,002,003,013,023,000,100,200,000"], ["sssbbbbsbhsbppp", "010,020,100,101,102,103,100,110,111,100,110,111,200,000,100"], ["ssffpffssp", "010,020,020,020,100,110,120,200,210,000"] ].each do |input, expect| it input do assert_equal BallCount.solve(input), expect end end end end
Y字路巡り
http://nabetani.sakura.ne.jp/hena/ord3ynode/
module YshapedRoadTour Graph = {"A"=>"DCB", "B"=>"CEA", "C"=>"FBA", "D"=>"EFA", "E"=>"DBF", "F"=>"ECD"} def self.solve(input) input = input.each_char result = "" go = ->(s, e) { result << e idx = Graph[e].index(s) case input.next when "b" go.(e, s) when "r" i = (idx - 1) % 3 when "l" i = (idx + 1) % 3 end go.(e, Graph[e][i]) } go.("B", "A") rescue StopIteration result end end if __FILE__ == $0 require 'minitest/autorun' describe 'YshapedRoadTour' do [ ["b", "AB"], ["l", "AD"], ["r", "AC"], ["bbb", "ABAB"], ["rrr", "ACBA"], ["blll", "ABCAB"], ["llll", "ADEBA"], ["rbrl", "ACADE"], ["brrrr", "ABEDAB"], ["llrrr", "ADEFDE"], ["lrlll", "ADFEDF"], ["lrrrr", "ADFCAD"], ["rllll", "ACFDAC"], ["blrrrr", "ABCFEBC"], ["brllll", "ABEFCBE"], ["bbbrrlrl", "ABABEDFCB"], ["rbllrrrr", "ACABCFEBC"], ["lbrlrrblr", "ADABCFEFCA"], ["rlbrrrrbl", "ACFCADFCFD"], ["bllrlrbrrb", "ABCADEFEBCB"], ["rllrllllbb", "ACFDEBADEDE"], ["blblrlrrlbr", "ABCBEDFCABAC"], ["lrlrrrrrbrb", "ADFEBCFEBEDE"], ["rblllrlrrlrr", "ACABCADEFDABE"], ["rbrrlrblrllb", "ACADFEBEFDACA"], ["lrrrlrllrrllr", "ADFCABEFCADEBC"], ["rrlblllrrlrrb", "ACBEBADEFDABEB"], ["brbllrrbbrlrll", "ABEBADFCFCABEFC"], ["rrrbbrlbrlblrb", "ACBABACFCABADFD"], ["lllllllllllblrr", "ADEBADEBADEBEFDE"], ["llllllrllrlbrrr", "ADEBADEFCBADABED"] ].each do |input, expect| it input do assert_equal YshapedRoadTour.solve(input), expect end end end end
フカシギの通行止め
https://qiita.com/Nabetani/items/9c514267214d3917edf2
ループによる実装。
module CountFukashigi n = 5 Goal = n * n - 1 Pathes = n.times.flat_map {|i| n.times.map {|j| a = i * n + j [a - 1, a - n, a + n, a + 1] } } Pathes[0...n].map! { _1.delete_at(1) } Pathes[-n..-1].map! { _1.delete_at(2) } 0.step(by: n, to: Goal) { |i| Pathes[i].delete_at(0) } (n - 1).step(by: n, to: Goal) { |i| Pathes[i].delete_at(-1) } def self.solve(input) table = Pathes.map(&:dup) input.split.each do |str| a, b = str.bytes.map { _1 - 97 } table[a].delete(b) table[b].delete(a) end result = 0 stack = [[0]] loop do road = stack.pop break result unless road table[road[-1]].each do |nxt| next if road.include?(nxt) if nxt == Goal result += 1 else stack << road + [nxt] end end end end end if __FILE__ == $0 require 'minitest/autorun' describe 'CountFukashigi' do [ ["", 8512], ["af", 4256], ["xy", 4256], ["pq qr rs st di in ns sx", 184], ["af pq qr rs st di in ns sx", 92], ["bg ch di ij no st", 185], ["bc af ch di no kp mr ns ot pu rs", 16], ["ab af", 0], ["ty xy", 0], ["bg ch ej gh lm lq mr ot rs sx", 11], ["ty ch hi mn kp mr rs sx", 18], ["xy ch hi mn kp mr rs sx", 32], ["ch hi mn kp mr rs sx", 50], ["ab cd uv wx", 621], ["gh mn st lq qr", 685], ["fg gl lm mr rs", 171] ].each do |input, expect| it input do assert_equal CountFukashigi.solve(input), expect end end end end
結果。
Finished in 0.332796s, 48.0774 runs/s, 48.0774 assertions/s. 16 runs, 16 assertions, 0 failures, 0 errors, 0 skips
別解。再帰を使う。
module CountFukashigi n = 5 Goal = n * n - 1 Pathes = n.times.flat_map {|i| n.times.map {|j| a = i * n + j [a - 1, a - n, a + n, a + 1] } } Pathes[0...n].map! { _1.delete_at(1) } Pathes[-n..-1].map! { _1.delete_at(2) } 0.step(by: n, to: Goal) { |i| Pathes[i].delete_at(0) } (n - 1).step(by: n, to: Goal) { |i| Pathes[i].delete_at(-1) } def self.solve(input) table = Pathes.map(&:dup) input.split.each do |str| a, b = str.bytes.map { _1 - 97 } table[a].delete(b) table[b].delete(a) end result = 0 field = Array.new(Goal + 1) field[0] = true go = ->(now) { table[now].each do |nxt| if nxt == Goal result += 1 else next if field[nxt] field[nxt] = true go.(nxt) field[nxt] = nil end end } go.(0) result end end
結果。ループよりこちらの方が速い。
Finished in 0.135252s, 118.2977 runs/s, 118.2977 assertions/s. 16 runs, 16 assertions, 0 failures, 0 errors, 0 skips
テトロミノ認識
http://nabetani.sakura.ne.jp/hena/ord4tetroid/
module FindTetromino t = [[:L, 4, ["111", "100"]], [:L, 4, ["111", "001"]], [:T, 4, ["111", "010"]], [:I, 2, ["1111"]], [:S, 2, ["110", "011"]], [:S, 2, ["011", "110"]], [:O, 1, ["11", "11"]]] Tetrominos = t.map {|s, n, pt| pt = pt.map { _1.chars.map(&:to_i) } a = n.times.map { tmp = pt pt = pt.reverse.transpose tmp }.map {|blk| blk.flat_map.with_index {|row, y| row.filter_map.with_index { |b, x| [x, y] if b == 1 } } } [s.to_s] + a } N = 10 module_function def each_tetromino Tetrominos.each do |name, *pts| pts.each { |pt| yield(name, pt) } end end def do(input) field = Array.new(N) { Array.new(N) } input.split(",").each do |str| str.chars.map(&:to_i).tap { |x, y| field[y][x] = true } end answer = "-" N.times do |y| N.times do |x| each_tetromino do |name, pattern| f = pattern.all? {|dx, dy| x1 = x + dx y1 = y + dy next if x1 < 0 || x1 >= N next if y1 < 0 || y1 >= N field[y1][x1] } answer = name if f end end end answer end end if __FILE__ == $0 require 'minitest/autorun' describe 'FindTetromino' do [ ["55,55,55,55", "-"], ["39,28,27,29", "L"], ["63,62,43,53", "L"], ["32,42,43,44", "L"], ["81,72,91,71", "L"], ["62,64,72,63", "L"], ["45,25,35,24", "L"], ["12,20,22,21", "L"], ["66,46,67,56", "L"], ["44,46,45,43", "I"], ["04,24,14,34", "I"], ["43,42,41,40", "I"], ["48,38,58,68", "I"], ["31,20,22,21", "T"], ["69,79,78,89", "T"], ["42,33,44,43", "T"], ["16,25,05,15", "T"], ["27,37,28,38", "O"], ["13,24,23,14", "O"], ["63,72,62,73", "O"], ["73,63,62,74", "S"], ["56,57,47,66", "S"], ["88,99,98,87", "S"], ["62,43,52,53", "S"], ["86,95,87,96", "S"], ["84,83,73,94", "S"], ["32,33,41,42", "S"], ["86,85,75,96", "S"], ["97,76,96,77", "-"], ["53,55,45,43", "-"], ["73,93,94,84", "-"], ["31,33,41,42", "-"], ["21,32,11,12", "-"], ["73,75,65,64", "-"], ["64,65,45,54", "-"], ["12,00,01,10", "-"], ["94,85,75,74", "-"], ["87,86,77,75", "-"], ["56,56,56,56", "-"], ["41,42,41,52", "-"], ["61,60,63,61", "-"], ["03,13,33,13", "-"], ["92,96,94,93", "-"], ["15,25,55,45", "-"], ["17,14,16,13", "-"], ["72,83,83,92", "-"], ["40,40,42,51", "-"], ["81,80,93,82", "-"], ["51,61,30,41", "-"], ["17,37,35,15", "-"] ].each do |input, expect| it input do assert_equal FindTetromino.do(input), expect end end end end
Rails on Tiles
http://nabetani.sakura.ne.jp/hena/ord5railsontiles/
module RailsOnTiles Tiles = [[2, 3, 0, 1], [1, 0, 3, 2], [3, 2, 1, 0]] Dirs = [[0, -1], [1, 0], [0, 1], [-1, 0]] module_function def go(input) field = input.chars.map(&:to_i).each_slice(3).to_a solve(field).map { |i| ("A".."I").to_a[i] }.join end def solve(field, x=1, y=-1, dir=2, route=[]) dx, dy = Dirs[dir] x += dx y += dy return route if x < 0 || x > 2 || y < 0 || y > 2 rev = Tiles[0][dir] nxt = Tiles[field[y][x]][rev] tile_num = y * 3 + x solve(field, x, y, nxt, route + [tile_num]) end end if __FILE__ == $0 require 'minitest/autorun' describe 'RailsOnTiles' do [ ["101221102", "BEDGHIFEH"], ["000000000", "BEH"], ["111111111", "BCF"], ["222222222", "BAD"], ["000211112", "BEFIHEDGH"], ["221011102", "BADGHIFEBCF"], ["201100112", "BEHIFCBADEF"], ["000111222", "BEFIH"], ["012012012", "BC"], ["201120111", "BEDABCFI"], ["220111122", "BADEHGD"], ["221011022", "BADG"], ["111000112", "BCFIHEBA"], ["001211001", "BEFI"], ["111222012", "BCFEHIF"], ["220111211", "BADEHI"], ["211212212", "BCFEBAD"], ["002112210", "BEFC"], ["001010221", "BEF"], ["100211002", "BEFIHG"], ["201212121", "BEFCBAD"] ].each do |input, expect| it input do assert_equal RailsOnTiles.go(input), expect end end end end
大貧民
http://nabetani.sakura.ne.jp/hena/ord5dahimi/
class Card Rank = %W(3 4 5 6 7 8 9 T J Q K A 2) def initialize(str) @value = str @rank = (str == "Jo") ? 13 : Rank.index(str[1]) end attr_reader :value, :rank alias to_s value end module Daihinmin module_function def play(input) table, hand = input.split(",") return "-" unless hand hand = hand.scan(/../).map { |c| Card.new(c) } joker = hand.find {|c| c.value == "Jo"} table = table.scan(/../).map { |c| Card.new(c) } t_rank = table.map(&:rank).min t_num = table.size cs = hand.group_by(&:rank).select { |k, v| k > t_rank }.values result = cs.select { |ary| ary.size >= t_num } .flat_map { |ary| ary.combination(t_num).to_a } if joker && t_num >= 2 result += cs.select { |ary| ary.size >= t_num - 1 && ary[0] != joker } .flat_map {|ary| ary.combination(t_num - 1).map { |cards| cards + [joker] } } end result.empty? ? "-" : result.map(&:join).join(",") end end if __FILE__ == $0 def same?(input, expect) inputs = input.split(",") expects = expect.split(",") return false unless inputs.size == expects.size equal = ->(a, b) { a == b || a.scan(/../).sort == b.scan(/../).sort } is_found = ->(ans) { s = expects.find { |e| equal.(e, ans) } return false unless s expects.delete(s) true } inputs.all?(&is_found) end [ ["DJ,", "-"], ["H7,HK", "HK"], ["S3,D4D2", "D4,D2"], ["S9,C8H4", "-"], ["S6,S7STCK", "CK,ST,S7"], ["H4,SAS8CKH6S4", "S8,CK,H6,SA"], ["ST,D6S8JoC7HQHAC2CK", "Jo,C2,CK,HA,HQ"], ["SA,HAD6S8S6D3C4H2C5D4CKHQS7D5", "H2"], ["S2,D8C9D6HQS7H4C6DTS5S6C7HAD4SQ", "-"], ["Jo,HAC8DJSJDTH2", "-"], ["S4Jo,CQS6C9DQH9S2D6S3", "DQCQ,D6S6,H9C9"], ["CTDT,S9C2D9D3JoC6DASJS4", "JoC2,SJJo,DAJo"], ["H3D3,DQS2D6H9HAHTD7S6S7Jo", "JoHA,JoD6,JoH9,D6S6,D7S7,JoS6,HTJo,JoDQ,S2Jo,JoD7,JoS7"], ["D5Jo,CQDAH8C6C9DQH7S2SJCKH5", "CQDQ"], ["C7H7,S7CTH8D5HACQS8JoD6SJS5H4", "HAJo,JoSJ,H8S8,H8Jo,CQJo,CTJo,JoS8"], ["SAHA,S7SKCTS3H9DJHJH7S5H2DKDQS4", "-"], ["JoC8,H6D7C5S9CQH9STDTCAD9S5DAS2CT", "CTDT,H9D9,S9D9,DACA,CTST,H9S9,DTST"], ["HTST,SJHJDJCJJoS3D2", "DJCJ,SJDJ,JoHJ,CJHJ,SJJo,HJSJ,DJJo,JoCJ,JoD2,SJCJ,DJHJ"], ["C7D7,S8D8JoCTDTD4CJ", "D8S8,JoS8,CTJo,DTJo,JoCJ,CTDT,D8Jo"], ["DJSJ,DTDKDQHQJoC2", "JoDK,HQDQ,DQJo,C2Jo,JoHQ"], ["C3H3D3,CKH2DTD5H6S4CJS5C6H5S9CA", "S5H5D5"], ["D8H8S8,CQHJCJJoHQ", "JoCQHQ,JoHJCJ"], ["H6D6S6,H8S8D8C8JoD2H2", "D2H2Jo,D8JoS8,D8S8C8,C8D8H8,JoC8S8,H8JoC8,S8H8C8,JoS8H8,C8JoD8,D8H8S8,D8JoH8"], ["JoD4H4,D3H3S3C3CADASAD2", "DACASA"], ["DJHJSJ,SQDQJoHQCQC2CA", "SQJoCQ,DQCQJo,JoSQHQ,SQCQHQ,DQHQSQ,HQDQCQ,HQDQJo,SQDQCQ,CQJoHQ,SQJoDQ"], ["H3D3Jo,D4SKH6CTS8SAS2CQH4HAC5DADKD9", "HASADA"], ["C3JoH3D3,S2S3H7HQCACTC2CKC6S7H5C7", "-"], ["H5C5S5D5,C7S6D6C3H7HAH6H4C6HQC9", "C6D6S6H6"], ["H7S7C7D7,S5SAH5HAD5DAC5CA", "SADACAHA"], ["D4H4S4C4,S6SAH6HAD6DAC6CAJo", "C6H6S6D6,SAJoDACA,S6H6C6Jo,SACAJoHA,HADASAJo,HADAJoCA,CADAHASA,D6C6JoH6,S6D6C6Jo,H6JoS6D6"], ["DTCTSTHT,S3SQH3HQD3DQC3CQJo", "HQSQJoDQ,SQCQDQJo,DQCQHQJo,SQHQJoCQ,CQDQHQSQ"], ["JoS8D8H8,S9DTH9CTD9STC9CAC2", "H9C9D9S9"], ].each do |input, expect| p same? Daihinmin.play(input), expect end end
続柄
http://nabetani.sakura.ne.jp/hena/ord6kinship/
module Relationship module_function def solve(start, goal) tree = Hash.new { |h, k| h[k] = [] } (1..40).each do |i| tree[i] << (i + 1) / 3 if i != 1 (i*3-1..i*3+1).each { |j| tree[i] << j } if i < 14 end result = move(tree, start, goal) table = {""=>:me, "-"=>:mo, "+"=>:da, "-+"=>:si, "--+"=>:au, "-++"=>:ni, "--++"=>:co} table.default = :- table[result] end def move(tree, start, goal, before=0, route="") return route if start == goal (tree[start] - [before]).each do |nxt| next_route = route + (nxt < start ? "-" : "+") return next_route if nxt == goal a = move(tree, nxt, goal, start, next_route) return a if a end nil end end if __FILE__ == $0 require 'minitest/autorun' describe 'Relationship' do [ [[5, 2], :mo], [[28, 10], :au], [[1, 1], :me], [[40, 40], :me], [[27, 27], :me], [[7, 2], :mo], [[40, 13], :mo], [[9, 3], :mo], [[4, 1], :mo], [[1, 3], :da], [[12, 35], :da], [[3, 8], :da], [[6, 19], :da], [[38, 40], :si], [[9, 8], :si], [[4, 2], :si], [[15, 16], :si], [[40, 12], :au], [[10, 4], :au], [[21, 5], :au], [[8, 2], :au], [[3, 5], :ni], [[11, 39], :ni], [[2, 13], :ni], [[13, 32], :ni], [[14, 22], :co], [[40, 34], :co], [[5, 8], :co], [[12, 10], :co], [[1, 27], :-], [[8, 1], :-], [[12, 22], :-], [[2, 40], :-], [[32, 31], :-], [[13, 14], :-], ].each do |input, expect| it input do assert_equal Relationship.solve(*input), expect end end end end