0
0

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 3 years have passed since last update.

Bit Tetris (どう書く)

Last updated at Posted at 2020-12-14

http://nabetani.sakura.ne.jp/hena/ord2/

ビットで表現されたテトリスの揃った行を消すという問題です。

Ruby
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

まずは消すべき行をビット演算で求めて(field.inject(:&))、あとはそれぞれの列で消すべきビットをeraseメソッドで消しています。ビットを消すのにどうすべきかなと迷いました。結局、2進表現してから Array に直して(to_aメソッド)、mapで消しています。String の2進数表現と16進数表現、それに Integer をどう使いわけるかという問題なのかなと思います。

なお、eraseメソッドでワンライナーでやっている ary1.zip(ary2).map {|a, b| ...}みたいな書き方はわたしのよくやるところで、zipで Array を作り直しているところは効率がよくないのですが、表現が簡潔になることがあります。愚直に(?)やると、こんな感じかな?

  def erase(i, to_be_erased)
    a = to_a(i)
    result = ""
    a.length.times do |j|
      result << a[j] if to_be_erased[j] != "1"
    end
    result.to_i(2)
  end

こちらの方が早くて効率がよい筈ですが。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?