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

paiza×Qiita記事投稿キャンペーンということで、paizaラーニングレベルアップ問題集の[神経衰弱](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration)をやってみました。
2024年8月15日に[神経衰弱](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_00)の問題の解き方について学習できる問題群が追加されました。今回は「[STEP:2 神経衰弱を解くために:part1](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_01)」から「[STEP:6 神経衰弱](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_05)」まで、Python3で解いていきたいと思います。
- - -
###### [part1：入力を1行受け取ってみましょう](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_01)
1行目に並べられたトランプの縦方向の枚数$H$と横方向の枚数$W$、プレイヤーの数$N$が半角スペース区切りで与えられます。
入力の1行目で与えられる$H,W,N$を受け取って、そのまま出力しましょう。
```py
# 縦方向の枚数H、横方向の枚数M、プレイヤーの数Nを受け取る
H, W, N = map(int, input().split())
# H, M, Nを出力する
print(H, W, N)
```
- - -
###### [part2：`H`行の入力を受け取ってみましょう](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_02)
$2$行目から$H+1$行目までの$H$行にかけて$i$（$1\le i\le H$）行$j$（$1\le j\le W$）列に並べられたトランプに書かれた数字が半角スペース区切りで与えられます。
このトランプのデータを受け取ってみましょう。

:::note info
トランプのデータは数字で与えられますが、加減乗除等の演算はしないので、文字列型のままで結構です。数値型に変換する必要はありません。
:::

```py
H, W, N = map(int, input().split())
#print(H, W, N)

# トランプのデータを受け取る
t = []
for i in range(H):
	t.append(input().split())

# トランプのデータを出力する
for i in range(H):
	print(*t[i])
```
:::note info
二次元配列の受け取り方は言語によってかなり異なります。
一例としてC++のコードも掲載いたします。
```cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
	int H, W, N;
	cin >> H >> W >> N;
	// cout << H << W << N << endl;
	vector<vector<string>> t(H, vector<string>(W));
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			cin >> t[i][j];
		}
	}
	for (int i = 0; i < H; i++) {
		cout << t[i][0];
		for (int j = 1; j < W; j++) {
			cout << " " << t[i][j];
		}
		cout << endl;
	}
	return 0;
}
```
:::

- - -
###### [part3：捲られたトランプが揃っているか判定してみましょう](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_03)
- $H+2$行目に記録の長さ$L$が与えられます。
- $H+3$行目から$H+L+3$行目までの$L$行にかけて、捲られたトランプの記録が時系列順で与えられます。これは、$a_i$行$b_i$列のトランプと$A_i$行$B_i$列のトランプが捲られたことを表します。

捲られたトランプの記録を受け取って、捲られたトランプが揃っているか判定してみましょう。
$L$個の記録それぞれについて、捲られたカードが揃っていれば`YES`を、揃っていなければ`NO`を1行に出力します。

:::note info
$a_i,b_i,A_i,B_i$の入力は1-based indexで与えられますが、プログラム内部では0-based indexで処理します。
:::

```py
H, W, N = map(int, input().split())
t = []
for i in range(H):
	t.append(input().split())

# 記録の長さLを受け取る
L = int(input())

# L個の記録それぞれについて、捲られたカードが揃っていればYESを、揃っていなければNOを出力する
for i in range(L):
	a, b, A, B = map(lambda x: int(x) - 1, input().split())
	if t[a][b] == t[A][B]: # 揃っていればYESを出力する。
		print("YES")
	else: # 揃っていなければNOを出力する。
		print("NO")
```
- - -
###### [part4：ゲームの手順をシミュレーションしてみましょう](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_04)
手番のプレイヤーの番号とある時点での捲られたトランプの記録が与えられるので、捲った2枚のトランプに同じ数字が書かれていたかどうかと、次の手番のプレイヤーの番号を出力しましょう。
```py
H, W, N = map(int, input().split())
t = []
for i in range(H):
	t.append(input().split())

# 手番のプレイヤーの番号Pを受け取る。
P = int(input())

# ある時点で捲られたトランプの記録を受け取る。
# これは、a行b列のトランプとA行B列のトランプが捲られたことを表す。
a, b, A, B = map(lambda x: int(x) - 1, input().split())

if t[a][b] == t[A][B]:
	# 揃っていればYESを出力する。
	print("YES")

else:
	# 揃っていなければNOを出力する。
	print("NO")

	# 次のプレイヤーの手番となる。
	if P == N:
		# N番のプレイヤーの次のプレイヤーは1番のプレイヤー
		P = 1
	else:
		P += 1

# 次の手番のプレイヤーの番号を出力する
print(P)
```
- - -
###### [part5：もう一度「神経衰弱」の問題を解いてみましょう](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration_05)
各プレイヤーが取り除いたトランプの枚数を出力しましょう。

:::note info
問題文には
> プレイヤーが$N$人おり、それぞれ$1$〜$N$で番号付けられているものとします。
ゲームが始まると、$1$番の人から以下の手順でプレイしていきます。
> ここで、$N$番のプレイヤーの次のプレイヤーは$1$番のプレイヤーであるとします。


と書かれていますが、プログラム内部では
> プレイヤーが$N$人おり、それぞれ$0$〜$N-1$で番号付けられているものとします。
ゲームが始まると、$0$番の人から以下の手順でプレイしていきます。
> ここで、$N-1$番のプレイヤーの次のプレイヤーは$0$番のプレイヤーであるとします。

として処理します。
:::
:::note info
> $a_i$行$b_i$列および$A_i$行$B_i$列のトランプは取り除かれていない

ことが保証されていますので、場からトランプを取り除く（`t[a][b]=""`にする）処理や、
> トランプが全て取り除かれていれば、ゲームを終了する。

ことを判定する処理は不要です。
:::

```py
H, W, N = map(int, input().split())
t = []
for i in range(H):
	t.append(input().split())

# 各プレイヤーが取り除いたトランプの枚数
C = [0] * N

# 0番の人からプレイ
P = 0

L = int(input())
for i in range(L):
	a, b, A, B = map(lambda x: int(x) - 1, input().split())
	if t[a][b] == t[A][B]:
		# print("YES")
		# 2枚のトランプを取り除き、自分のものとする。
		C[P] += 2
	else:
		# print("NO")
		if P == N - 1:
			P = 0
		else:
			P += 1

# 各プレイヤーが取り除いたトランプの枚数を出力する。
for i in range(N):
	print(C[i])
```
- - -
###### [オリジナル：制約や問題文がスキルチェックに出題されていたものと全く同じ問題です](https://paiza.jp/works/mondai/b_rank_skillcheck_archive/concentration)
```py
H, W, N = map(int, input().split())
t = [input().split() for _ in range(H)]
p, *C = [0] * -~N
for i in range(int(input())):
	a, b, A, B = map(lambda x: ~-int(x), input().split())
	if t[a][b] == t[A][B]:
		C[p] += 2
	else:
		p = -~p % N
print(*C, sep='\n')
```