Pyxelでマルバツゲーム(三目並べ)を作る

###始めに
今回初めてQiitaに記事を投稿させていただきます。PyxelどころかPythonも始めてなので、間違いがありましたらご指摘お願いします。

##作るもの
〇と×を交互において、縦横斜めいずれかに3列そろえたら勝ちのゲーム「マルバツゲーム(もしくは三目並べ)」を作ります。この〇と×や盤面の部分をPythonのモジュールであるPyxelの機能で描画します。

##動作環境
```
Microsoft Windows [Version 10.0.17134.590]
Python 3.7.1
Pyxel 1.0.1
```

##レイアウト
まずは碁盤を作ります。
盤面の上の方には今後使うことなるマウスの座標の情報をとりあえず表示させておきます。

```py
import pyxel
class App:
    #ゲームの初期設定
    def __init__(self):
        #幅64ドット 高さ73ドット
        pyxel.init(65,77,caption='three')
        #マウスカーソルを表示する
        pyxel.mouse(True)
        #毎フレームごとにupdate関数とdraw関数を実行する
        #この命令は__init__関数の一番下に持ってくるように記述してください!
        pyxel.run(self.update, self.draw)

    #ゲームを管理する部分 まだ何も書いてない
    def update(self):
        pass

    #ゲームのグラフィックを表示する部分
    def draw(self):
        #背景をカラーパレット11で塗りつぶす
        pyxel.cls(11)
        #区切り線を引く
        pyxel.line(0,33,64,33,7)
        pyxel.line(0,55,64,55,7)
        pyxel.line(21,12,21,76,7)
        pyxel.line(43,12,43,76,7)

        #確認用にマウスの現在座標を出力する
        pyxel.text(0,0,"x:"+str(pyxel.mouse_x),7)
        pyxel.text(16,0,"y:"+str(pyxel.mouse_y),7)

App()


```

実行結果
![pyxel-190306-111828.png](https://qiita-image-store.s3.amazonaws.com/0/372537/0e74c0b7-4c34-73c9-609c-b0b6862ef49f.png)


##クリック処理
このゲームは全てマウス操作でプレイしたいので、クリックした場所に応じて〇や×を置いていくようにします。その為にはマウスの座標を盤面の座標に変換しなければなりません。マウスが一番左上のマスにいるときの座標は(白線の上も含めると)

```
0<=x<=21 , 12<=y<=33   ※ 0<=y-12<=21
```
の範囲内なので座標を22で割った値を切り捨てればうまくいきそうですね！値の切り捨てを行うにはmathモジュールをインポートし、その中のfloor関数を使用します。

```.py
#追加
import math
class App:
    #ゲームの初期設定
    def __init__(self):
        #追加 
        #盤面の座標(単位はマス)
        self.field_x=0
        self.field_y=0

     #ゲームを管理する部分
    def update(self):
        #追加
        #マウスの座標を盤面の座標に変換する
        self.field_x=math.floor(pyxel.mouse_x/22)
        self.field_y=math.floor((pyxel.mouse_y-12)/22)
          
    #ゲームのグラフィックを表示する部分
    def draw(self):
        #追加
        #確認用に盤面の現在座標を出力する
        pyxel.text(33,0,"fx:"+str(self.field_x),7)
        pyxel.text(49,0,"fy:"+str(self.field_y),7)
```
実行結果
![pyxel-190306-111902.png](https://qiita-image-store.s3.amazonaws.com/0/372537/60bb49aa-f2f9-bd88-0df9-95550bbf69f8.png)

次にクリックしたらそのマスに〇と×を順番に置くようにします。turn変数が今どちらの順番かを表す変数です。

```.py
class App:
    #ゲームの初期設定
    def __init__(self):
        #追加
        #盤面の情報
        self.field=[[0,0,0],[0,0,0],[0,0,0]]
        #順番を表す
        self.turn=1

    #ゲームを管理する部分
    def update(self):
        #追加
        #クリックした場所がどこのマスかを確認し
        if pyxel.btn(pyxel.MOUSE_LEFT_BUTTON):
            self.field_x=math.floor(pyxel.mouse_x/22)
            self.field_y=math.floor((pyxel.mouse_y-12)/22)
            #そのマスの要素が0(=何もない)なら手順に対応した要素にし、手順交代
            if self.field[self.field_x][self.field_y]==0:
                self.field[self.field_x][self.field_y]=self.turn
                self.turn*=-1

    #ゲームのグラフィックを表示する部分
    def draw(self):
        #追加
        #fieldの中身を確認し、1ならそのマスに〇、-1なら×を描く
        for y in range(3):
            for x in range(3):
                if self.field[x][y]==1:
                    pyxel.circb(x*22+10,y*22+22,8,8)
                if self.field[x][y]==-1:
                    pyxel.line(x*22+3,y*22+15,x*22+17,y*22+29,12)
                    pyxel.line(x*22+17,y*22+15,x*22+3,y*22+29,12)
```
実行結果
![pyxel-190306-164619.png](https://qiita-image-store.s3.amazonaws.com/0/372537/618a0175-8739-491d-3a76-d9a9be4c3005.png)


##勝敗判定
最終段階です。先ほどの実行結果を見てもわかる通り、三つ並んでいても勝負が終わっていません。なので最後に三つ並んだらゲームを終了する関数を追加します。ついでに先ほどまでマウスの座標などが表示されていた部分は現在の順番と、試合が終了したら勝者を表示させておきます。

```.py
class App:
    #ゲームの初期設定
    def __init__(self):
        #追加
        #勝敗判定
        self.win=0

    #ゲームを管理する部分
    def update(self):
    #変更
    #まだ試合が終わっていないなら、クリックした場所がどこのマスかを確認し
        if pyxel.btn(pyxel.MOUSE_LEFT_BUTTON) and self.win==0:
            #同じ
            #そのマスの要素が0(=何もない)なら手順に対応した要素にし、手順交代したあとに勝敗判定をする
            if self.field[self.field_x][self.field_y]==0:
                #同じ
                #追加
                self.judge(self.field_x,self.field_y)
 

    #ゲームのグラフィックを表示する部分
    def draw(self):
        #追加
        #現在の順番を表示する
        if self.turn==1:
            pyxel.text(5,3,"PLAYER 1 TURN",8)
        else:
            pyxel.text(5,3,"PLAYER 2 TURN",12)

        #追加
        #試合が終了したら順番ではなく勝った方を表示する
        if self.win==1:
            pyxel.rect(5,3,60,7,11)
            pyxel.text(5,3,"PLAYER 1 WIN!",8)
        elif self.win==-1:
            pyxel.rect(5,3,60,7,11)
            pyxel.text(5,3,"PLAYER 2 WIN!",12)

    #三つ並んだか確認する
    def judge(self,x,y):
        self.judge_win=[0,0,0,0]
        #先ほど選んだマスの横の列と縦の列がそろっていないか見る
        self.judge_win[0]=self.field[x][0]+self.field[x][1]+self.field[x][2]
        self.judge_win[1]=self.field[0][y]+self.field[1][y]+self.field[2][y]
        #左上、真ん中、右下のどれかを選んだ時
        if x==y==0 or x==y==1 or x==y==2:
            self.judge_win[2]=self.field[0][0]+self.field[1][1]+self.field[2][2]
        #右上、真ん中、左下のどれかを選んだ時
        elif x+y==2:
            self.judge_win[3]=self.field[2][0]+self.field[1][1]+self.field[0][2]
        #〇が揃ったらその列の合計は3、×が揃ったら-3になるのでゲーム終了
        for i in range(4):
            if (self.judge_win[i]==3):
                self.win=1
            elif(self.judge_win[i]==-3):
                self.win=-1

```
実行結果
![pyxel-190306-151159.png](https://qiita-image-store.s3.amazonaws.com/0/372537/30e2fb2d-a678-ed08-1585-8bf960e4fd14.png)
![pyxel-190306-152016.png](https://qiita-image-store.s3.amazonaws.com/0/372537/b347575a-c628-cca9-c847-b25a6d52893a.png)

##完成！
敵AIは実装されていませんし、まだ画面は無機質で寂しいですが今回はここまでにします(逃)。今後もPyxelで色々作っていきますのでよろしくお願いします。