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.

五目並べ問題をrubyで解いてみる

Posted at

五目並べ問題をrubyで解いてみる

最近PAIZAの勉強をしており、その練習問題に出てきた問題。
正直解答を見てもよくわからなかったので、一行ずつ読み解いてみます。
自分用のメモなので、他の方にはわかりにくいかもしれません。

問題はこちら

PAIZA

問題文

5行5列の五目並べの盤面が与えられます。
盤面の各マスには、"O"か"X"か"."が書かれています。
"O"と"X"は、それぞれプレイヤーの記号を表します。
同じ記号が縦か横か斜めに連続で5つ並んでいれば、その記号のプレイヤーが勝者となります。
勝者の記号を1行で表示してください。
勝者がいない場合は、引き分けとして、"D"を表示してください。

それではいきます〜〜

qiita.rb

# `$'で始まる変数はグローバル変数で、プログラムのどこからでも参照できます
$board = []

# 盤面の初期化
# 5回入力する(二次元配列を作る)
(1..5).each { $board.push(gets.chomp.split('')) }

この段階で、例えば入力値を
CVGFH
GBHHN
DFVHN
EFRTY
ZXCVB
と入力後、
puts $board[0][1]をすると、0回目に入力された行(CVGFH)の中から1番目の文字が出力されるので、Vが出力されます。

対象の文字列が5つ並んでいた時のそれぞれの定義をしていきます

qiita.rb

# 5つ並んでいるかどうか
def aligned?(o, x)
  if o == 5
    'O'  #oが5つ並んでいたらOを出力する
  elsif x == 5
    'X'  #xがXつ並んでいたらOを出力する
  else
    'D'  # それ以外はD
  end
end

まずは横に5回連続して並ぶことで勝つパターンの定義をします。

qiita.rb

# 横並びを定義
def row_aligned?
  result = ''

  #入力値を行に分解する
  $board.each do |row|
    #o,xの初期値を定義
    o = 0 #oが横に0回並んでいる
    x = 0 #xが横に0回並んでいる

    #行に書かれている値にさらに分解していく
    #(0..4)になっているのは5文字ずつ入力されているから0番目〜4番目を展開していくということになるということ
    (0..4).each do |i|
      # 展開した行のi番目がOであればoに1足していく
      if row[i] == 'O'
        o = o + 1
      # 展開した行のi番目がXであればxに1足していく
      elsif row[i] == 'X'
        x = x + 1
      else
        break
      end
    end
    #先ほど定義したaligned?(o, x)をresultに代入する
    result = aligned?(o, x)
    break if result != 'D'
  end

  result
end

続いて縦に5回連続して並ぶことで勝つパターンの定義をします。

qiita.rb

# 縦並びを定義
def collum_aligned?
  result = ''

  (0..4).each do |i|
    o = 0 #oが縦に0回並んでいる
    x = 0 #xが縦に0回並んでいる
    #入力値を列ごとに分解
    $board.each do |row|
      #展開した列のi番目がOであればoに1足していく
      if row[i] == 'O'
        o = o + 1
      #展開した列のi番目がXであればxに1足していく
      elsif row[i] == 'X'
        x = x + 1
      end
    end

    result = aligned?(o, x)
    break if result != 'D'
  end

  result
end

最後に斜めに5回連続して並ぶことで勝つパターンの定義をする。

斜めで記号が揃うパターンは、0 から 4 までの i に対して board[i][i] が同じ記号か、board[i][4 - i] が同じ記号の 2 パターン。
board[i][i] が同じ記号なのは左上から右下まで一直線に揃うパターン、board[i][4 - i] が同じ記号なのは右上から左下まで一直線に揃うパターンです。

qiita.rb

# 斜めを定義
def oblique_aligned?
  result = ''

  #0はboard[i][i] が同じ記号であるパターン
  #1はboard[i][4 - i] が同じ記号であるパターン
  (0..1).each do |time|

#i,j,o,xそれぞれの初期値を定義していく。
    i = 0

    #if time == 0と意味は同じらしい
    if time.zero?
      j = 0
    else
      j = 4
    end

    o = 0
    x = 0
    
    (1..5).each do
      #i列目のj番目がOの時oに1足していく
      if $board[i][j] == 'O'
        o = o + 1
      #i列目のj番目がXの時xに1足していく
      elsif $board[i][j] == 'X'
        x = x + 1
      end

   #iとjをそれぞれ更新していく

      i = i + 1

      if time.zero?
        j = j + 1
      else
        j = j - 1
      end
    end

    result = aligned?(o, x)
    break if result != 'D'
  end

  result
end

疲れてきた、、
最後の最後に、
横列 or 縦列 or 斜めにOが並んだ場合はOを出力、
横列 or 縦列 or 斜めにXが並んだ場合はXを出力、
それ以外はDを出力するif文を書く!

qiita.rb

if row_aligned? == 'O' || collum_aligned? == 'O' || oblique_aligned? == 'O'
  puts 'O'
elsif row_aligned? == 'X' || collum_aligned? == 'X' || oblique_aligned? == 'X'
  puts 'X'
else
  puts 'D'
end

以上でした

メモとして書いているのでわかりづらかったらすみません。

0
0
1

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?