第160回【Python】五目並べ(斜め)、五目並べ

現在取り組んでいるのは、paiza ラーニング問題集「B ランクレベルアップメニュー」になります。

はじめに

猫とキャンプと野球観戦と AWS が大好きな旦那、LeoSaki です。モフモフしたい。

Python をゼロから勉強してみよう、のコーナー 160 回目です。

事前準備の段階で満足してしまう人がいます。その人は、事前準備が 9 割 5 分くらいで、本番前にやり切った感が出てしまいます。ちょっとでも狂いが生じたらそれでパニックになって、以降、何もできなくなります。もっと気持ちにゆとりを持つように伝えるのですが、理解してくれません。

それでは、今日も頑張ってみようと思います。

今回取り組む内容について

以下は、前回までに取り組んだ問題とまったく同じなので、飛ばします。
コードは数書いてナンボとかカッコつけたこと書いてましたが、あまりにも多いので挫折しました。

STEP: 1 文字列の出力

五目並べ(斜め) (paizaランク C 相当)

5行5列の五目並べの盤面が与えられます。

盤面の各マスには、"O"か"X"か"."が書かれています。

“O"と"X"は、それぞれプレイヤーの記号を表します。

同じ記号が斜めに連続で5つ並んでいれば、その記号のプレイヤーが勝者となります。

勝者の記号を1行で表示してください。
勝者がいない場合は、引き分けとして、"D"を表示してください。

s_1
s_2
s_3
s_4
s_5

期待する出力

勝者の記号を1行で表示してください。
勝者がいない場合は、引き分けとして、"D"を表示してください。


すべてのテストケースにおいて、以下の条件をみたします。

・sの文字数は5文字
・sに含まれる文字は"O"か"X"か"."のいずれか
・勝者が2人になる盤面が、与えられることはありません。


入力例

XXOXO
OXOXX
.OXXO
OXOO.
XXXXX

出力例

D

横、縦ときたら、もちろん、斜め。5 行 5 列だと、斜めに 5 つ揃うパターンは 2 つしかない。

Python
s = [input() for _ in range(5)]

res = 'D'
stone = s[0][0]
pat = [True,False]

for cond in pat:
    if cond:
        j = 0
        j_diff = 1
    else:
        j = 4
        j_diff = -1
    
    stone = s[0][j]
    cnt = 1
    
    for i in range(1,5):
        j += j_diff
        
        if stone != '.' and stone == s[i][j]:
            cnt += 1
            
        if cnt == 5:
            res = stone
            break
    
print(res)
VBA
Sub tic_tac_toe_4()

    Dim s(4)
    res = "D"
    
    For i = 0 To 4
        s(i) = Cells(i + 1, 1)
    Next
    
    pat = Array(True, False)
    
    For Each con In pat
    
        If con Then
            j = 1
            j_diff = 1
        Else
            j = 5
            j_diff = -1
        End If
        
        stone = Mid(s(0), j, 1)
        cnt = 1
        
        For i = 1 To 4
            j = j + j_diff
            If stone <> "." And stone = Mid(s(i), j, 1) Then
                cnt = cnt + 1
            End If
            
            If cnt = 5 Then
                res = stone
                Exit For
            End If
        Next
        
    Next
    
    Debug.Print res
    
End Sub

五目並べ (paizaランク B 相当)

5行5列の五目並べの盤面が与えられます。

盤面の各マスには、"O"か"X"か"."が書かれています。

“O"と"X"は、それぞれプレイヤーの記号を表します。

同じ記号が縦か横か斜めに連続で5つ並んでいれば、その記号のプレイヤーが勝者となります。

勝者の記号を1行で表示してください。
勝者がいない場合は、引き分けとして、"D"を表示してください。

s_1
s_2
s_3
s_4
s_5

期待する出力

勝者の記号を1行で表示してください。
勝者がいない場合は、引き分けとして、"D"を表示してください。


すべてのテストケースにおいて、以下の条件をみたします。

・sの文字数は5文字
・sに含まれる文字は"O"か"X"か"."のいずれか
・勝者が2人になる盤面が、与えられることはありません。


入力例

XXOXO
OXOXX
OOOOO
OXOX.
XOXXO

出力例

O

ここまでの集大成。全パターンについて考える。

Python
s = [input() for _ in range(5)]
res = 'D'

def row():
    
    for i in range(5):
        stone = s[i][0]
        cnt = 1
        for j in range(1,5):
            if stone != '.' and stone == s[i][j]:
                cnt += 1
            
            if cnt == 5:
                return stone
                
    return res

def column():
    
    for i in range(5):
        stone = s[0][i]
        cnt = 1
        for j in range(1,5):
            if stone != '.' and stone == s[j][i]:
                cnt += 1
        
            if cnt == 5:
                return stone
                
    return res
    
def diagonal():
    
    pat = [True,False]

    for cond in pat:
        if cond:
            j = 0
            j_diff = 1
        else:
            j = 4
            j_diff = -1
        
        stone = s[0][j]
        cnt = 1
        
        for i in range(1,5):
            j += j_diff
            
            if stone != '.' and stone == s[i][j]:
                cnt += 1
                
            if cnt == 5:
                return stone

    return res
    
row = row()
column = column()
diagonal = diagonal()

if row != 'D':
    print(row)
elif column != 'D':
    print(column)
else:
    print(diagonal)
VBA
Sub tic_tac_toe_9()

    Dim s(4)
    
    For i = 0 To 4
        s(i) = Cells(i + 1, 1)
    Next
    
    setRow = row(s)
    setColum = colum(s)
    setDiagonal = diagonal(s)
    
    If setRow <> "D" Then
        Debug.Print setRow
    ElseIf setColum <> "D" Then
        Debug.Print setColum
    Else
        Debug.Print setDiagonal
    End If
    
End Sub

Private Function row(s) As String

    row = "D"
    
    For i = 0 To 4
        stone = Mid(s(i), 1, 1)
        cnt = 1
        
        For j = 2 To 5
            If stone <> "." And stone = Mid(s(i), j, 1) Then
                cnt = cnt + 1
            End If
            
            If cnt = 5 Then
                row = stone
                Exit Function
            End If
        Next
    Next
    
End Function

Private Function colum(s) As String

    colum = "D"
    
    For i = 1 To 5
        stone = Mid(s(0), i, 1)
        cnt = 1
        
        For j = 1 To 4
            If stone <> "." And stone = Mid(s(j), i, 1) Then
                cnt = cnt + 1
            End If
            
            If cnt = 5 Then
                colum = stone
                Exit Function
            End If
        Next
    Next
    
End Function

Private Function diagonal(s) As String

    diagonal = "D"
    
    pat = Array(True, False)
    
    For Each con In pat
    
        If con Then
            j = 1
            j_diff = 1
        Else
            j = 5
            j_diff = -1
        End If
        
        stone = Mid(s(0), j, 1)
        cnt = 1
        
        For i = 1 To 4
            j = j + j_diff
            If stone <> "." And stone = Mid(s(i), j, 1) Then
                cnt = cnt + 1
            End If
            
            If cnt = 5 Then
                diagonal = stone
                Exit Function
            End If
        Next
    Next
    
End Function

最後に

本章の集大成的な? 最初は、横でも縦でも斜めでも、一旦 5 つを配列に入れてしまって、それと「OOOOO」と「XXXXX」を比較する方法とか考えたのですが、あまり応用性がないような気がして、この方法に落ち着きました。模範解答とは少し異なります。(模範解答が知りたい方は paiza へ・・・)

もっと少ない計算量で出来る方法はないか、考えてしまいます。似たようなことを繰り返しているので。比較対象が常に異なるので難しいか・・・。

引き続き、よろしくお願いいたします!

Python学習,Python,paiza

Posted by LeoSaki