ChatGPTでカードゲーム（神経衰弱）を作ってみた

### 目標

神経衰弱のカードゲームに挑戦

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/5d177f12-068a-9927-a726-6cd02a2550e7.png)

### 結論
2時間ほどで出来上がりました。

### ポイントまとめ
* 12枚のカードを用意
* 1から6までのペアの数値を12枚のカードにランダムに振る
* カードをめくり、1枚目のカードの数値と2枚目のカードの数値を比較
* 数値が同じだったら、カード確定するため、めくることをできなくする
* 数値が異なる場合、0.4秒後にカードを裏返す
* めくれるカードがなくなったらクリア

### 実装
カードの配置（card.kv)
```YML
#: kivy 2.3.0
<MemoryGame>
    BoxLayout:
        id: content
        orientation: 'vertical'
        spacing: 10
        pos_hint: {'center_x': 0 }
        pos_hint_x: 1
```
ImageButtonクラスを用意
```py
class ImageButton(ButtonBehavior, Image):
    def __init__(self, source, front_source, back_source, text, **kwargs):
        super().__init__(**kwargs)
        # イメージパス
        self.source = source
        # 裏側
        self.back_source = back_source
        # 表側
        self.font_source = front_source
        # テキスト(判定用）画像比較はやりません。
        self.text = text
```
神経衰弱ゲーム本体クラス
コンストラクタ
```py
class MemoryGame(BoxLayout):
    def __init__(self, **kwargs):
        super(MemoryGame, self).__init__(**kwargs)
        # １から６までの数値を2ペア生成
        self.cards = list(range(1,  7)) *  2
        # シャフルする
        random.shuffle(self.cards)
        # 裏返し(フリップ用リスト）
        self.flipped = []
        # ボタン登録用リスト
        self.buttons = []
        # ボード作成メソッド（ゲーム画面カード作成）
        self.create_board()
```
カード配置メソッド

初期配置
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/104b2833-6306-f7a2-bd9b-a4e82f04fde6.png)
```py
def create_board(self):
        for i in range(3):  #  3 rows for  4 columns
            inner_layout = BoxLayout(orientation='horizontal', height=300, width=300, size_hint_y=None, spacing=10)
            for j in range(4):  #  4 columns
                index =  4 * i + j
                if index < len(self.cards):  # Ensure we don't go out of range
                    btn = ImageButton(source="./f.png",
                                      front_source= "./f.png",
                                      back_source=f"./{self.cards[index]}.png",text=" ")
                    btn.index = index
                    btn.bind(on_press=self.card_click)
                    self.buttons.append(btn)
                    inner_layout.add_widget(btn)
            self.ids['content'].add_widget(inner_layout) 
```
カードめくった時（カードクリック）のアルゴリズム
```py
 def card_click(self, instance):
    # Check if the card is already flipped
    if instance.text != " ":
        return  # If the card is already flipped, do nothing

    if instance.source == "f.png":
        instance.source = f"./{self.cards[instance.index]}.png"
        
    # Flip the card
    instance.text = str(self.cards[instance.index])
    # instance.font_size = '50sp'

    # Check if this is the first card flipped
    if not self.flipped:
        self.flipped.append(instance)
        self.first_card = self.cards[instance.index]
        self.first_card_index = instance.index
    else:
        # This is the second card flipped
        self.second_card = self.cards[instance.index]
        self.second_card_index = instance.index

        # Check if the cards match
        if self.first_card != self.second_card:
            # If the cards do not match, flip them back after a delay
            Clock.schedule_once(lambda dt: self.flip_back(self.first_card_index, self.second_card_index),  1)

        # Reset the flipped list for the next pair
        self.flipped = []

        # Check if all cards are matched
        if len([btn for btn in self.buttons if btn.text == " "]) ==  0:
            print("Clear")
           
```
カード判定
```py
# Check if the cards match
if self.first_card != self.second_card:
    # If the cards do not match, flip them back after a delay
    Clock.schedule_once(lambda dt: self.flip_back(self.first_card_index, self.second_card_index),  1)

```

カードを裏返す処理
```py
def flip_back(self, first_card_index, second_card_index):
        self.buttons[first_card_index].text = " "
        self.buttons[second_card_index].text = " "
        self.buttons[first_card_index].source = './f.png'
        self.buttons[second_card_index].source = './f.png'
```

### 感想

最初はいろいろ難しく考えすぎて、わけわかめ状態でしたが、整理するとそんなに難しいアルゴリズム使ったわけでもありませんでした。普段はこういうゲーム特性あまり考えていないので、やはりすこし悩みました。