問題
六角形のマスをつなげたハニカム構造のマス目がある。
入力は、4つのマス目を示す文字列で指定される。
出力は、入力値が形成する図形が、リンク先の図形に該当する場合は識別子を、しない場合は-
を返す。
考え方
任意のマス目から東、南東、南西、西、北西、北東のマスを計算するロジックを作成する。
BDIJLNOSYZ
の図形は、任意のマス目をa, b, c, d
と定義し、a
を原点a→b
を東方向への単位ベクトルとして正規化する。
c, d
は、a, b
およびa→b
のベクトルをもとに相対的な位置関係を正規化する。
そうすると、任意の位置をa
に特定し、a→b
のベクトルと残りの三点がb, c, d
を計算することができる。
入力値の一点を任意にa
と仮定し、残りの3点がb, c, d
に一致する図形が存在するかを調査する。
ちなみに、ハニカム構造を二次元配列として扱うのは難しかったので諦めた。
コード
hexom.rb
require 'test/unit'
DIRECTIONS = %i(e se sw w nw ne)
# NOTE: a〜yのマス目を0〜22の数値として扱う
class Integer
# NOTE: -1 を要素なしのマジックナンバーとして使う
def unkown?
self == -1
end
def east_edge?
%w(e i n r w).map(&:to_idx).include? self
end
def far_east_edge?
%w(e n w).map(&:to_idx).include? self
end
def west_edge?
%w(a f j o s).map(&:to_idx).include? self
end
def far_west_edge?
%w(a j s).map(&:to_idx).include? self
end
def north_edge?
%w(a b c d e).map(&:to_idx).include? self
end
def south_edge?
%w(s t u v w).map(&:to_idx).include? self
end
# NOTE: 東、南東、南西、西、北西、北東の要素番号を返す
# NOTE: 要素が列の東の端の場合、それより東の要素はない
def e
return -1 if unkown?
return -1 if east_edge?
self + 1
end
# NOTE: 要素が東の端から凸状態の場合、それより南東の要素はない
def se
return -1 if unkown?
return -1 if far_east_edge?
return -1 if south_edge?
self + 5
end
def sw
return -1 if unkown?
return -1 if far_west_edge?
return -1 if south_edge?
self + 4
end
def w
return -1 if unkown?
return -1 if west_edge?
self - 1
end
def nw
return -1 if unkown?
return -1 if far_west_edge?
return -1 if north_edge?
self - 5
end
def ne
return -1 if unkown?
return -1 if far_east_edge?
return -1 if north_edge?
self - 4
end
end
class String
# NOTE: to_i を override すると unit/test が落っこちる
def to_idx
[*"a".."w"].find_index self
end
end
# NOTE:
# 1. 各方角の要素を算出するmethodを呼び出す
# 2. 方角を回転させて呼び出すmethodを切り替える
# 3. method chainしたい
# を同時に満たすため、Symbol classを拡張しています
class Symbol
# NOTE: 方角を時計回りに1つ回す
def rotate
next_direction_idx = DIRECTIONS.find_index(self) + 1
DIRECTIONS[next_direction_idx % 6]
end
# NOTE: 方角を反時計回りに1つ回す
def reverse
next_direction_idx = DIRECTIONS.find_index(self) - 1
DIRECTIONS[next_direction_idx % 6]
end
end
# NOTE: 各パターンにマッチするかを探索
# `a`と`a→b`のベクトルから b, c, dを生成し、入力値を完全に含んでいるかを検査する
def i? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction)
d = c.send(direction)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def b? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction)
d = b.send(direction.reverse)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def d? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction)
d = b.send(direction.rotate)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def j? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction)
d = c.send(direction.rotate)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def l? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction)
d = c.send(direction.reverse)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def n? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction.rotate)
d = c.send(direction.rotate.rotate)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def o? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction.rotate.rotate)
d = c.send(direction.rotate.rotate.rotate)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def s? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction.reverse)
d = c.send(direction)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def y? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = a.send(direction.rotate.rotate)
d = a.send(direction.reverse.reverse)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
def z? ints
ints.any? do |a|
DIRECTIONS.any? do |direction|
b = a.send(direction)
c = b.send(direction.rotate)
d = c.send(direction)
true if [b, c, d].all?{ |x| ints.include? x }
end
end
end
# NOTE: メイン関数
def hexom_pattern input
splited = input.split("").sort.uniq
return "-" if splited.length < 4
ints = splited.map(&:to_idx)
# NOTE: 全種類の図形との該当を検査する場合はここをアンコメント
# %w(b d i j l n o s y z).each do |s|
%w(b d i).each do |s|
return s.upcase if send((s + "?").to_sym, ints)
end
return "-"
end
class TestHexom < Test::Unit::TestCase
def test_hexom_pattern
assert_equal hexom_pattern("glmq"), "B"
assert_equal hexom_pattern("fhoq"), "-"
assert_equal hexom_pattern("lmpr"), "-"
assert_equal hexom_pattern("glmp"), "-"
assert_equal hexom_pattern("dhkl"), "-"
assert_equal hexom_pattern("glpq"), "D"
assert_equal hexom_pattern("hlmq"), "-"
assert_equal hexom_pattern("eimq"), "I"
assert_equal hexom_pattern("cglp"), "-"
assert_equal hexom_pattern("chlq"), "-"
assert_equal hexom_pattern("glqr"), "-"
assert_equal hexom_pattern("cdef"), "-"
assert_equal hexom_pattern("hijk"), "-"
assert_equal hexom_pattern("kpqu"), "B"
assert_equal hexom_pattern("hklm"), "B"
assert_equal hexom_pattern("mqrw"), "B"
assert_equal hexom_pattern("nrvw"), "B"
assert_equal hexom_pattern("abfj"), "B"
assert_equal hexom_pattern("abcf"), "B"
assert_equal hexom_pattern("mrvw"), "D"
assert_equal hexom_pattern("ptuv"), "D"
assert_equal hexom_pattern("lmnr"), "D"
assert_equal hexom_pattern("hklp"), "D"
assert_equal hexom_pattern("himr"), "D"
assert_equal hexom_pattern("dhil"), "D"
assert_equal hexom_pattern("hlpt"), "I"
assert_equal hexom_pattern("stuv"), "I"
assert_equal hexom_pattern("bglq"), "I"
assert_equal hexom_pattern("glmn"), "-"
assert_equal hexom_pattern("fghm"), "-"
assert_equal hexom_pattern("cdgk"), "-"
assert_equal hexom_pattern("lpst"), "-"
assert_equal hexom_pattern("imrw"), "-"
assert_equal hexom_pattern("dinr"), "-"
assert_equal hexom_pattern("cdin"), "-"
assert_equal hexom_pattern("eghi"), "-"
assert_equal hexom_pattern("cdeg"), "-"
assert_equal hexom_pattern("bgko"), "-"
assert_equal hexom_pattern("eimr"), "-"
assert_equal hexom_pattern("jotu"), "-"
assert_equal hexom_pattern("kotu"), "-"
assert_equal hexom_pattern("lqtu"), "-"
assert_equal hexom_pattern("cdim"), "-"
assert_equal hexom_pattern("klot"), "-"
assert_equal hexom_pattern("kloq"), "-"
assert_equal hexom_pattern("kmpq"), "-"
assert_equal hexom_pattern("qrvw"), "-"
assert_equal hexom_pattern("mnqr"), "-"
assert_equal hexom_pattern("kopt"), "-"
assert_equal hexom_pattern("mnpq"), "-"
assert_equal hexom_pattern("bfko"), "-"
assert_equal hexom_pattern("chin"), "-"
assert_equal hexom_pattern("hmnq"), "-"
assert_equal hexom_pattern("nqrw"), "-"
assert_equal hexom_pattern("bchi"), "-"
assert_equal hexom_pattern("inrw"), "-"
assert_equal hexom_pattern("cfgj"), "-"
assert_equal hexom_pattern("jnpv"), "-"
assert_equal hexom_pattern("flmp"), "-"
assert_equal hexom_pattern("adpw"), "-"
assert_equal hexom_pattern("eilr"), "-"
assert_equal hexom_pattern("bejv"), "-"
assert_equal hexom_pattern("enot"), "-"
assert_equal hexom_pattern("fghq"), "-"
assert_equal hexom_pattern("cjms"), "-"
assert_equal hexom_pattern("elov"), "-"
assert_equal hexom_pattern("chlm"), "D"
assert_equal hexom_pattern("acop"), "-"
assert_equal hexom_pattern("finr"), "-"
assert_equal hexom_pattern("qstu"), "-"
assert_equal hexom_pattern("abdq"), "-"
assert_equal hexom_pattern("jkln"), "-"
assert_equal hexom_pattern("fjkn"), "-"
assert_equal hexom_pattern("ijmn"), "-"
assert_equal hexom_pattern("flqr"), "-"
end
end
実行結果
% ruby hexom.rb
Loaded suite hexom
Started
.
Finished in 0.416804 seconds.
--------------------------------------------------------------------------------------
1 tests, 75 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
--------------------------------------------------------------------------------------
2.40 tests/s, 179.94 assertions/s