1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

オフラインリアルタイムどう書くE13「六角形のテトロミノ」をRubyで解いてみた。

Posted at

問題

六角形のマスをつなげたハニカム構造のマス目がある。
入力は、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
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?