チュートリアルStep3

![スクリーンショット 2024-10-09 22.05.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/7540b856-b5d8-bc46-6252-a6f83856a1e6.png)


![puyopuyo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/1fdf8221-96c5-fcfa-3a52-383422a6fdc3.gif)
　ぷよぷよプログラミングAI学習システムは、中高生の自己調整学習に向けて開発されました。
　どうやって、Chromebookで、１０分で、素敵な人工知能を作れるのでしょうか？
　秘密は、３つ。
　１　jupyter liteで、webクライアントがpythonコードを実行
　２　超軽量な機械学習フレームワークdezeroを採用
　３　ぷよぷよのstageとactionがコンパクト

### Github&X

https://github.com/Lunanaedu/jupyterlite-puyopuyo

https://github.com/Lunanaedu/puyopuyo-kai

https://x.com/educationai_ai

### ぷよぷよプログラミングAI学習用まとめ

https://qiita.com/educational-ai/items/50c0fa689c01794d145e

### チュートリアルまとめ

https://qiita.com/educational-ai/items/88feaf91bdda0b5e0d25

# Step3 Action選択肢と衝突判定

# 3 衝突判定をして、Action選択肢を探る。

　どこにpuyoを移動させて、回転させるかという選択肢は、幅6 x 回転4　-2 = 22　の可能性があるようにも見えますが、他のpuyoと衝突するかもしれないので、衝突判定が必要です。

step2で作った、set_puyo_to_boardを改造して、衝突判定の関数を作ります。


```python
def check_collision(board, puyo):
   rot = puyo.rotation
   if rot == 0 and puyo.x == 5:
      return True
   if rot == 2 and puyo.x == 0:
      return True
   if puyo.y >= 12:
      return True
   if puyo.y == 11 and rot == 3 :
      return True
   if board[puyo.y, puyo.x] > 0 :
      return True
   if not( rot == 1) and board[puyo.y + puyo.dy[rot], puyo.x + puyo.dx[rot]] > 0:
      return True
   return False
```

この関数は、そのブロックがboardの中に入っているか、逆に言えば、はみ出ていないか判定もしています。

check_collisionを使って、actionの選択肢をリスト化します。

actionの選択肢は、スタートする列の位置と回転数をリストとして出力します。


```python
import numpy as np
from puyo_utils import *

def create_action_list(board):
    puyo2 = Puyopuyo()
    res = []
    for rot in range(4):
        for pos1 in range(6):
            puyo2.x = pos1
            puyo2.rotation = rot
            if not check_collision(board, puyo2):   
                res.append([pos1, rot])
    return res
```

action_list　は、numpyではないので、少し注意が必要です。
それでは、使ってみましょう。


```python
board = utils.create_sample_board()
action_list=create_action_list(board)

print(action_list)

```

    [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3]]


action_listは厳密には、ぷよの横移動と回転可能性が完全には保証されていません。実ゲームでどこまで応用可能かはやってみてからの調整が必要です。

これらの関数も使いたいので、puyo_utilsに保存しておきます。


```python
%%writefile puyo_utils.py
import numpy as np
import random

class CFG:
    Height = 12
    Width = 6


class Puyopuyo:
    def __init__(self):
        self.x = 2
        self.y = 0
        self.dx = [1,  0, -1, 0]
        self.dy = [0, -1,  0, 1]
        self.centerPuyo = random.randint(1,4)
        self.movablePuyo = random.randint(1,4)
        self.rotation = 1    


class utils:
    def create_sample_board(height=CFG.Height, width=CFG.Width):
        sample_list = np.arange(width)
        random.shuffle(sample_list)
        board = np.zeros(height * width, dtype = np.int32).reshape(height, width)

        for j in range(width):
            if sample_list[j]:
                for i in range(sample_list[j]):
                    board[height - 1 - i, j] = random.randint(1, 4)

        return board

    def create_new_puyo(board):
        new_puyo = Puyopuyo()
        done = False
        if board[2, 0] > 0:
            done = True
        return new_puyo, done    

    def set_puyo_to_board(board, puyo):
        new_board = np.copy(board)
        new_board[puyo.y, puyo.x ] = puyo.centerPuyo
        puyo_dy = puyo.y + puyo.dy[puyo.rotation]
        puyo_dx = puyo.x + puyo.dx[puyo.rotation]
        if puyo_dy >= 0:
            new_board[puyo_dy, puyo_dx ] = puyo.movablePuyo
        return new_board

    def check_collision(board, puyo):
        rot = puyo.rotation
        if rot == 0 and puyo.x == 5:
            return True
        if rot == 2 and puyo.x == 0:
            return True
        if puyo.y >= 12:
            return True
        if puyo.y == 11 and rot == 3 :
            return True
        if board[puyo.y, puyo.x] > 0 :
            return True
        if not( rot == 1) and board[puyo.y + puyo.dy[rot], puyo.x + puyo.dx[rot]] > 0:
            return True
        return False
    

    def create_action_list(board):
        puyo2 = Puyopuyo()
        res = []
        for rot in range(4):
            for pos1 in range(6):
                puyo2.x = pos1
                puyo2.rotation = rot
                if not utils.check_collision(board, puyo2):   
                    res.append([pos1, rot])
        return res

```

    Overwriting puyo_utils.py


* class utils : 関数をまとめて、utilsにしました。名前がぶつからないようにします。