paizaラーニングレベルアップ問題集の「神経衰弱」をやってみた

paiza×Qiita記事投稿キャンペーンということで、paizaラーニングレベルアップ問題集の[神経衰弱](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration)をやってみました。
- - -

問題を解く時は、入出力部分を`main`部に、処理部分を別関数にして、以下の様な雛型を作って
```py
'''Python3の場合'''


def solve('''入力値''') -> list:
    answer = list()  # 出力はリストなので仮置き
    return answer


if __name__ == "__main__":
    '''
    入力値を受け取る
    '''

    # 処理
    answer = solve('''入力値''')

    # 出力
    for a in answer:
        print(a)
```
問題文（の要点）をコメントとして記述して考えるのも一つでしょう。
```py
def solve('''入力値''') -> list:
    answer = list()  # 出力はリストなので仮置き

    '''
    プレイヤーがN人おり、それぞれ1〜Nで番号付けられています。
    '''
    # ゲームが始まると、1番の人から、このような手順でプレイしていきます。
        # 並べられたトランプから2枚のトランプを選び、めくります。
        # めくった2枚のトランプに異なる数字が書かれていれば、
            # 次のプレイヤーの手番となります。
            # （ここで、N番のプレイヤーの次のプレイヤーは1番のプレイヤーであるとします。）
        # 同じ数字であれば、次の操作をおこないます。
            # まず、2枚のトランプはめくったプレーヤーのものとなり、取り除かれます。
            # トランプがすべて取り除かれた場合、
                # ゲームは終了となります。
            # トランプが残っている場合、
                # 同じプレーヤーがまた最初の手順に戻り、トランプをめくります。

    # 各プレイヤーが取り除いたトランプの枚数を返却
    return answer


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

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

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

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

    # 処理
    answer = solve('''入力値''')

    # 出力
    for a in answer:
        print(a)
```
これをプログラムしていきます。
※問題文は添字が$1,2,...,N$で与えられることが多いですが、プログラミングする時は適宜$0,1,...,N-1$で読み換えます。
```py
def solve(n_cards: int, cards: list, n_players: int, first: list, second: list) -> list:
    '''
    n_cards: 残っているトランプの枚数
    cards: 配置されたトランプに書かれた数字
    n_players: プレイヤーの数
    first: 捲られたトランプの記録（１枚目）
    second: 捲られたトランプの記録（２枚目）
    '''
    # 各プレイヤーが取り除いたトランプの枚数
    scores = [0] * n_players

    # ゲームが始まると、0番の人から、このような手順でプレイしていきます。
    player = 0

    for f, s in zip(first, second):
        # 並べられたトランプから2枚のトランプを選び、めくります。
        i, j = f
        card0 = cards[i][j]
        k, l = s
        card1 = cards[k][l]

        if card0 != card1:  # めくった2枚のトランプに異なる数字が書かれていれば、
            # 次のプレイヤーの手番となります。
            player += 1

            # ここで、N-1番のプレイヤーの次のプレイヤーは0番のプレイヤーであるとします。
            player %= n_players

        else:  # 同じ数字であれば、次の操作をおこないます。
            # まず、2枚のトランプはめくったプレーヤーのものとなり、
            scores[player] += 2

            # 場から取り除かれます。
            cards[i][j] = ""
            cards[k][l] = ""
            n_cards -= 2

            # トランプがすべて取り除かれた場合、
            if n_cards == 0:
                # ゲームは終了となります。
                break

            # トランプが残っている場合、
            else:
                # 同じプレーヤーがまた最初の手順に戻り、トランプをめくります。
                continue

    # 各プレイヤーが取り除いたトランプの枚数を返却
    return scores


if __name__ == "__main__":
    # 1行目には3つの整数 H, W, Nが入力されます。
    # HとWはそれぞれ並べられたトランプの縦方向の枚数と横方向の枚数で、
    # Nはプレイヤーの数を表します。
    H, W, N = map(int, input().split())

    # 続くH行には、配置されたトランプに書かれた数字が入力されます。
    # t_{i,j}はi行j列に置かれたトランプに書かれた数字を表します。
    T = []
    for i in range(H):
        T.append(input().split())  # 今回はintに変換する必要は無い

    # 次の行には、記録の長さ L が与えられます。
    L = int(input())

    # 続くL行には、捲られたトランプの記録が時系列順で与えられます。
    # これは、a_k行b_k列のトランプとA_k行B_k列のトランプが
    # 捲られたことを表します。
    first = []
    second = []
    for k in range(L):
        a, b, A, B = map(int, input().split())
        first.append((a-1, b-1))  # 入力は1～だが添字は0～
        second.append((A-1, B-1))

    # 処理
    scores = solve(H*W, T, N, first, second)

    # 出力
    for score in scores:
        print(score)
```
制約条件に「$a_i$行$b_i$列および$A_i$行$B_i$列のトランプは取り除かれていない」とあるので、問題を解くのに`solve`関数内の`cards[i][j]==""`から`continue`までの行は不要です（トランプがすべて取り除かれた場合、入力は来ない）。その部分を除いて、プログラムの部分だけ取り出すと、以下のように書けます。
```py
H, W, N = map(int, input().split())
T = []
for i in range(H):
    T.append(input().split())
scores = [0] * N
player = 0
L = int(input())
for k in range(L):
    a, b, A, B = map(int, input().split())
    card0 = T[a-1][b-1]
    card1 = T[A-1][B-1]
    if card0 != card1:
        player = (player + 1) % N
    else:
        scores[player] += 2

for score in scores:
    print(score)
```