Header
2020-04-02
2020-05-27

paiza(パイザ)Bランク練習問題|神経衰弱のRubyサンプルコードと解説

2020 04 02 e9cc750129ca3303e19f56b1fdb46a9f s

paiza(パイザ)Bランク相当の練習問題 神経衰弱の解説とサンプルコード、Rubyサンプルコードの解説を記載します。

問題の要件と概要は以下から

神経衰弱

以下から公式の抜粋を元にプログラム化する際の思考の流れとサンプルコードを記載します

関連問題

paiza(パイザ)Bランク練習問題|日別訪問者数の最大平均区間のRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|5以上の整数の合計のRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|検索履歴のRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|宝くじのRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|アルファベット探しのRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|単語のカウントのRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|野球の審判のRubyサンプルコードと解説

paiza(パイザ)Cランク練習問題|【競技7】奇数大好き山田さんのRubyサンプルコードと解説

目次


Bランク問題の神経衰弱のカウントの入出力値

以下公式抜粋

神経衰弱と呼ばれるトランプゲームのシミュレーションをしましょう。
今回は数字が書かれたトランプのみを考え、ジョーカーは考えません。

まず、トランプを縦 H 枚、横 W 枚の長方形の形に並べた状態でスタートします。
H × W 枚のトランプには 1 〜 13 の数字のうちどれか1つが書かれています。
また、同じ数字が書かれたトランプが複数あります。

プレイヤーが N 人おり、それぞれ 1 〜 N で番号付けられています。
ゲームが始まると、1番の人から、このような手順でプレイしていきます。

・並べられたトランプから2枚のトランプを選び、めくります。
・めくった2枚のトランプに異なる数字が書かれていれば、次のプレイヤーの手番となります。同じ数字であれば、次の操作をおこないます。
・まず、2枚のトランプはめくったプレーヤーのものとなり、取り除かれます。
・トランプがすべて取り除かれた場合、ゲームは終了となります。
・トランプが残っている場合、同じプレーヤーがまた最初の手順に戻り、トランプをめくります。

ここで、N 番のプレイヤーの次のプレイヤーは 1 番のプレイヤーであるとします。

ゲームの初期状態におけるトランプの配置と、ゲームが終わるまでに捲られたトランプに関する時系列順の記録が与えられます。
その記録を用いて、各プレイヤーが取り除いたトランプの枚数を求めてください。

たとえば、入力例1は以下のようになります。

入力値

入力は以下のフォーマットで与えられます。

H W N
t_{1,1} t_{1,2} ... t_{1,W}
t_{2,1} t_{2,2} ... t_{2,W}
...
t_{H,1} t_{H,2} ... t_{H,W}
L
a_1 b_1 A_1 B_1
a_2 b_2 A_2 B_2
...
a_L b_L A_L B_L

1行目には3つの整数 H, W, Nが入力されます。
H と W はそれぞれ並べられたトランプの縦方向の枚数と横方向の枚数で、N はプレイヤーの数を表します。

続く H 行には、配置されたトランプに書かれた数字が入力されます。
t_{i,j} は i 行 j 列に置かれたトランプに書かれた数字を表します。

次の行には、記録の長さ L が与えられます。

続く L 行には、捲られたトランプの記録が時系列順で与えられます。
これは、a_i 行 b_i 列のトランプと A_i 行 B_i 列のトランプが捲られたことを表します。

期待する出力

i 行目には i 番目のプレイヤーが取り除いたトランプの枚数を出力してください。
各行の最後は改行し、余計な文字、空行を含んではいけません。

入出力例(公式から抜粋)

入力例1
2 3 2
1 2 3
2 1 3
5
1 1 2 1
1 1 1 2
1 1 2 2
1 3 2 3
1 2 2 1

出力例1
6
0

入力例2
2 5 3
5 8 8 6 3
3 6 3 3 5
8
1 4 2 2
1 3 2 1
2 4 2 3
1 3 1 5
2 5 1 1
2 1 1 2
1 5 2 1
1 2 1 3

出力例2
6
2
2

問題をプログラム化する際の考え方

入力値で以下のように記載されています。

入力例1

2 3 2
1 2 3
2 1 3
5
1 1 2 1
1 1 1 2
1 1 2 2
1 3 2 3
1 2 2 1

ここで分かる事は

1:数字を指定している

2:この例では 1行目の 2(縦)行分の回数指定がある

3:縦の回数分、配置されたトランプに書かれた数字を取得する為の処理をしている事が分かります

4:捲られたトランプの記録、5行分が時系列順で表示されているので、その回数分だけ処理を行うという事が分かります

5:(1,1)で1枚目のカードを捲り、(2,1)は2枚目のカードを捲った記録になる事が分かります

次に出力例を見ると

出力例1
6
0

1:こちらも数字を指定しており

2:プレイヤーの人数は2人なので、出力は2行分になります

3:プレイヤー1番は6枚取り

プレイヤー2番は0枚取ったという結果が分かります

プログラム化する際にRuby的な処理を考える

1:1行目の縦、横、プレイヤー数を取得する

2:縦行分の配列を受け取る為の空の配列を作成

3:繰り返し処理を用いて縦行分のカードの数字を取得する

4:取得したカードの数字を 2 の空配列に追加する

5:ゲームの記録の長さを取得する

6:現在のプレイヤーを記録する変数を作成する

7:取り除いたトランプを記録する配列の作成

以下からゲームを開始

8:繰り返し処理を用いて、ゲームの記録(回数)分のトランプの捲られた記録を取得する

9:条件分岐を用いて 1枚目と2枚目の捲った数字が同じなら 7. の配列の2(枚)追加する

10:違うなら、次の人に交代する処理を記述する

11:最後に各プレイヤーが取り除いたトランプの枚数を出力する

paizaBランク問|神経衰弱のRubyサンプルコード

# 縦、横、プレイヤー数の取得
vertical, horizontal, player_number = gets.chomp.split(" ").map(&:to_i)

# 縦行分の配列を受け取る為の空の配列を作成する
trump_numbers = []

# 縦行分の数字を取得し、空配列(trump_numbers)に入れて、二次元配列にする
vertical.times do
  trump_number = gets.chomp.split(" ").map(&:to_i)
  trump_numbers << trump_number
end

# 時系列の長さを取得する
drawn_trump_order = gets.chomp.to_i

# 手番を持つプレイヤーを表す変数
player = 1

# 各プレイヤーから取り除いたトランプの枚数
count = []
player_number.times do
  count << 0
end

# ゲームの手順の記録を受け取る
drawn_trump_order.times do
  a_1,b_1,a_2,b_2 = gets.chomp.split.map(&:to_i)

  first_card = trump_numbers[a_1 - 1][b_1 - 1]
  second_card = trump_numbers[a_2 - 1][b_2 - 1]

  if first_card == second_card
    count[player - 1] += 2
  else
    player += 1
    if player == player_number + 1
      player = 1
    end
  end
end

puts count

ゲームの記録が4列分あるので、a1,b1,a2,b2という変数にしています。

  first_card = trump_numbers[a_1 - 1][b_1 - 1]

1枚目のカードについての記述をしています。

trump_numbers[a_1][b_1] 

でも(−1を記述しなくても)良いのではないかと最初感じたのですが、インデックス番号は 0 から数える為、行列(a1,b1,a2,b2)に -1 をして記述する必要があります。

インデックス番号は0 からスタートするので a1〜b2 までの全ての行、列の数字を [-1] したという事です。

こちらは入力例1での考え方です

 1    2    3
(0, 0)  (0, 1)  (0, 2)
 2    1    3
(1, 0)  (1, 1)  (1, 2)

それらと同様に、countのインデックス番号も 0 から数える為、count[player - 1] とし、一度に取り除かれるカードは2枚であるという処理を記述しています。

if player == player_number + 1
  player = 1
end

こちらは最後の手番を超えたら、一番手のプレイヤーに戻る記述です。

最後に、1番目のプレイヤーから順に取り除いたカード枚数を出力しています。

以上になります

Rubyで以下のような練習問題を用意しているので、回答できなかった方はまずは以下練習問題を試してみてください

Rubyの練習問題:配列編|初心者・独学者向け入門コンテンツ

Rubyの練習問題:文字列編|初心者・独学者向け入門コンテンツ

Rubyの練習問題:ハッシュ編|初心者・独学者向け入門コンテンツ

Rubyの練習問題:繰り返し処理編|初心者・独学者向け入門コンテンツ

Rubyの練習問題:ファイル操作編|初心者・独学者向け入門コンテンツ

Rubyでバブルソートを行う

Rubyで二分探索(バイナリサーチ)を行う

paiza(パイザ)に慣れるとAtCoderアットコーダーもお勧めです

その他関連記事

20代のITエンジニアは転職する前に自分の市場価値を把握しよう

27歳から未経験で自社サービス会社のエンジニアに転職された方の勉強法や通学したプログラミングスクール

27歳から未経験で自社サービス会社のエンジニアに転職された方の転職媒体やエンジニア情報の収集先など

未経験からエンジニアに転職した人間が考える、今からエンジニアに就職する方法

低単価で海外ノマドのフリーランスや旅するように仕事するのは危険

SESからフリーランスになる際のメリットとデメリット|法人化した人間が解説

職歴を作るためにSESに就職して、Web系エンジニアへ転職は可能か

プログラミングで挫折する人の特徴|未経験からエンジニアに転職した人間が解説

独学プログラミングの勉強手順|未経験からエンジニアに転職した人間が解説

前の記事
次の記事