ルビー3.0の出現-日05 -バイナリ搭乗


ルビー3.0はちょうどリリースされたので、我々は実験に時間がかかると、すべての楽しい新機能がそこにあるかを参照してください年の陽気な時間です.
この一連の投稿では、Ruby 2.7と3.0の機能をいくつか紹介しますsolve Advent of Code problems . ソリューション自体は、機能の新しい使用を示すために最も効率的であることを意味していません.
これらのポストの各々が次第に長く、より関与するように、私は個々の日までにこれらを壊しています.
そう言ってしまおうじゃないか


Day 05 - パート01 -バイナリ搭乗
今日は面白いタイトルを選んだ.バイナリ搭乗.我々はおそらくそれに注意を払う必要がありますまた、事実がある128 , or 2**7 , 列の列.
ウェイトウェイト、彼らはまた、最初に使用したい7 搭乗券の文字は、我々はどの行を決定するか?一致することはできません.
最後の3つならば、それはさらに偶然であるでしょう.2^3 , どうにか8 . あまりにも悪い私たちはそれらを結合することはできません.
Every seat also has a unique seat ID: multiply the row by 8, then add the column. In this example, the seat has ID 44 * 8 + 5 = 357.
よく何を知っている、それはバイナリ文字列の前面です!
ソリューションから始めましょう.
FRONT = 'F'.freeze
BACK  = 'B'.freeze
LEFT  = 'L'.freeze
RIGHT = 'R'.freeze

def find_position(pass) = pass.gsub(/./, {
  FRONT => 0,
  LEFT  => 0,
  BACK  => 1,
  RIGHT => 1
}).to_i(2)

def positions(passes) = passes.map { find_position(_1) }
def max_position(...) = positions(...).max

File.readlines(ARGV[0]).then { puts max_position(_1) }


バイナリ?何?
問題テキストには興味深いものがあります.
For example, consider just the first seven characters of FBFBBFFRLR:

Start by considering the whole range, rows 0 through 127.
F means to take the lower half, keeping rows 0 through 63.
B means to take the upper half, keeping rows 32 through 63.
F means to take the lower half, keeping rows 32 through 47.
B means to take the upper half, keeping rows 40 through 47.
B keeps rows 44 through 47.
F keeps rows 44 through 45.
The final F keeps the lower of the two, row 44.
下半分と上半分、またはotherwords、オンとオフ.0 and 1 :
FBFBBFF
0101100
何が、数としてその翻訳ですか?
'0101100'.to_i(2)
# => 44
...を返します.
The final F keeps the lower of the two, row 44.
ビンゴ.最後の3つを見てみましょう.RLR , or '101' :
'101'.to_i(2)
# => 5
...テキストに戻る
So, decoding FBFBBFFRLR reveals that it is the seat at row 44, column 5.
もう一つのヒット!それでは、乗算で何ですか8 では?配列を変更した場合のオフセットです.
Dec: 512  256  128  64  32  16  8  4  2  1
Bin:  0    1    0   1   1   0   0  1  0  1
Str:  F    B    F   B   B   F   F  R  L  R

256 + 64 + 32 + 4 + 1 = 357
だからかなりよくそれをシール、“バイナリ搭乗”本当に!
gsub を取るHash ?
今、私たちはパスをバイナリ文字列に変換する必要がありますgsub 私たちのために非常に簡単にする気の利いたツールがあります
FRONT = 'F'.freeze
BACK  = 'B'.freeze
LEFT  = 'L'.freeze
RIGHT = 'R'.freeze

def find_position(pass) = pass.gsub(/./, {
  FRONT => 0,
  LEFT  => 0,
  BACK  => 1,
  RIGHT => 1
}).to_i(2)
我々は、すべての文字に対して一致している/./ , とHash 私たちはそれを翻訳テーブルです.私たちは定数を少し読みやすくするために使用していますが、さもなければ、私たちは前と左に翻訳したいだけです0 背中と右に1 .
一旦我々がそうするならば、我々は使うことができますto_i(2) を整数にする.The 2 基数はベースです.それは間違いなく10 , または10進数.あなたは8進数や16進数のようないくつかの他の一般的なものを使用することができますが、バイナリは、この1つに関連するものです.

誰でも
今、私たちはカウントを得る必要があります.
def positions(passes) = passes.map { find_position(_1) }
def max_position(...) = positions(...).max

File.readlines(ARGV[0]).then { puts max_position(_1) }
最初の機能は、各パスの位置を抽出し、2番目のラップは、最高の番号を取得するという概念をラップします.その後、我々は完了し、我々は解決策を持っています.

日05 -パート02 -これは徹底的です
パート2は悪いことではない、私たちはただ、スポットが特定の範囲内にある場所を見つける必要があります.最初と最後の行がなくなっているので、我々の席を見つける前に上下の境界を見つける必要があります.
ソリューションから始めましょう.
FRONT = 'F'.freeze
BACK  = 'B'.freeze
LEFT  = 'L'.freeze
RIGHT = 'R'.freeze

def find_position(pass) = pass.gsub(/./, {
  FRONT => 0,
  LEFT  => 0,
  BACK  => 1,
  RIGHT => 1
}).to_i(2)

def positions(passes) = passes.map { find_position(_1) }

def minmax_position(passes)
  all_positions    = positions(passes)
  min_pos, max_pos = all_positions.minmax

  (min_pos..max_pos).to_a - all_positions
end

File.readlines(ARGV[0]).then { puts minmax_position(_1) }

minmax 行を見つけるing
残りの関数はminimal_position 同じままですが、現在、我々は可能な席の上下の境界を見つける必要があります.最後に、我々はマックスを必要としました、しかし、現在、我々は両方を必要とします.
ルビーはminmax この場合、コレクション内の最小値と最大値の配列ペアを返します.
そこから我々はすべての可能な座席を列挙することができます.(min_pos..max_pos).to_a , 既知の位置を減算し、座席を取得します.
(min_pos..max_pos).to_a - all_positions
今、これを行うには、より効率的な方法がありますか?おそらく、Set or Range#contain? , しかし、我々はそれを実験への運動として読者に任せるつもりです.

日05ラップ
それは5日目にラップすることについて、我々はこれらの問題の各々を通して働き続けて、次の数日と数週間にわたって彼らの解決と方法論を調査し続けるでしょう.
場合は、元のソリューションのすべてをチェックアウトするthe Github repo 完全にコメントソリューションです.