プログラミング初心者がSwiftでマルバツゲームのiOSアプリ作ってみた

#はじめに
研究室の同期たちとの第三回ハッカソンが開催されたのでその記録。
他のメンバーの記事はこちら。
[指定したユーザーのツイートをしゃべるRaspberry Piの作り方](https://qiita.com/hayashi1989/items/dabd1a4f7b747ef7c4e1)
[位置情報を使ってSlackのステータスを更新してみた](https://qiita.com/Rtakaha/items/63b54c45c9e544ac878e)
はじめはtemiロボット用のアプリを作ろうと思ったが、色々うまくいかず断念...
そこで、今回は研究用にiOSアプリを作るためなんとなくSwiftを勉強した記憶を思い出しつつ何か作ってみる。
今回は、夏に作りかけていた簡単なマルバツゲーム:o::heavy_multiplication_x:を完成させて、追加要素としてマルバツゲームの盤面のベクトルを変更できるようにしてみる。

以下のサイトが参考になった。
[Swiftで初めてiPhoneゲーム開発する人向チュートリアル（マルバツゲームを例にStep by Step解説）](http://xavier.hateblo.jp/entry/2014/09/07/144059)

#準備編
###準備したもの
MacBook Air
iPad Pro 
Xcode 10.3
Swift 5.0
マルバツゲームの盤面の画像
マル・バツの画像

###プロジェクトの作成
Xcodeを起動して、「Single View App」でプロジェクト作成。
保存場所とかは好きなところで、プロジェクト名は適当に「MyGame」にした。
![スクリーンショット 2020-02-12 17.34.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/002e4fcb-fcc1-cafb-562e-a236636cd886.png)

###アプリ画面の準備
1.画面左上の「ProjectNavigater」からMain.storyboardファイルを選択。
![スクリーンショット 2020-02-12 17.39.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/aa23771e-bf03-ae07-85b5-391f853a72f8.png)

2.画面右上の「Show the Object Library」から、「Button」や「Text Field」、「Image View」など必要なものをstoryboard画面にドラッグ＆ドロップで配置。

3.画面右上のアイコン「Show the Assistant editor」をクリックして、storyboard画面の隣に「ViewController.swift」を表示。
![スクリーンショット 2020-02-12 17.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/5706c640-b24d-78b7-b86b-604a663220ae.png)

4.それぞれ配置したオブジェクトをクリックして、青くなった状態でCtrlキーを押しながらViewControllerへドラッグ&ドロップする。出てきたポップアップ上でコネクション情報を設定。
![スクリーンショット 2020-02-12 17.57.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/448075a4-09b7-f9cf-1a7f-3594d1f5c652.png)

5.nameをそれぞれに対応したものに設定を完了。以下の例はターンを表示するラベルのText Field。

```swift:ViewController.swift
@IBOutlet weak var turnLabel: UILabel!
```
コネクションをそれぞれのオブジェクトで設定して画面は完成。
実装編でそれぞれの機能を作っていく。
いるものを全部配置したらこんな感じ。
![スクリーンショット 2020-02-12 17.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/0a6a8aa4-994b-5e31-0ed4-aca0addd03e8.png)



#実装編
###マルバツゲーム:o::heavy_multiplication_x:を作ってみる
まずはシンプルなマルバツゲームを作成する。
全体を通して思いつきでやってる部分もあるのでかなり雑なコードになった...

各マスの座標を設定したり、マル・バツを置くたびにターンを変更したりする。
さらに、それぞれのマスのマル・バツを更新する関数を作る。

```swift:ViewController.swift
    @IBOutlet weak var turnLabel: UILabel!
    var turn: Int = 0
    
    //座標とかを設定
    var status: [Int] = [0,0,0,0,0,0,0,0,0]
    var squares: [[Int]] = [[-1,1,0],[0,1,0],[1,1,0],
                            [-1,0,0],[0,0,0],[1,0,0],
                            [-1,-1,0],[0,-1,0],[1,-1,0]]
    let winMaru: [Int] = [1,1,1]
    let winBatsu: [Int] = [-1,-1,-1]


    //プレイヤーのターンを管理
    @IBAction func tap(_ sender: UIButton) {
        let button = (sender as UIButton)
        
        if (turn % 2) == 0 {
            button.setImage(UIImage(named: "mark_maru"), for: UIControl.State())
            turnLabel.text =  "X の番です"
            status[sender.tag - 1] = 1
        }
        else{
            button.setImage(UIImage(named: "mark_batsu"), for: UIControl.State())
            turnLabel.text =  "◯ の番です"
            status[sender.tag - 1] = -1
        }
        check(status)
        turn += 1
    }
    
    func update(_ statusArray: [Int], _ squaresArray: inout [[Int]]){
        for i in 0...8{
            squaresArray[i][2] = statusArray[i]
        }
    }

　　 //中略

    //各マスの情報を更新
    func updateImage(_ squaresArray: [Int]){
        if squaresArray[0] == 1{
            button0.setImage(UIImage(named: "mark_maru"), for: UIControl.State())//まるにする
        }
        else if squaresArray[0] == -1{
            button0.setImage(UIImage(named: "mark_batsu"), for: UIControl.State())//ばつにする
        }
        else{
            button0.setImage(UIImage(named: "white"), for: UIControl.State())//しろにする
        }
        
        if squaresArray[1] == 1{
            button1.setImage(UIImage(named: "mark_maru"), for: UIControl.State())//まるにする
        }
        else if squaresArray[1] == -1{
            button1.setImage(UIImage(named: "mark_batsu"), for: UIControl.State())//ばつにする
        }
        else{
            button1.setImage(UIImage(named: "white"), for: UIControl.State())//しろにする
        }
        
        if squaresArray[2] == 1{
            button2.setImage(UIImage(named: "mark_maru"), for: UIControl.State())//まるにする
        }
        else if squaresArray[2] == -1{
            button2.setImage(UIImage(named: "mark_batsu"), for: UIControl.State())//ばつにする
        }
        else{
            button2.setImage(UIImage(named: "white"), for: UIControl.State())//しろにする
        }

//中略
        
        if squaresArray[8] == 1{
            button8.setImage(UIImage(named: "mark_maru"), for: UIControl.State())//まるにする
        }
        else if squaresArray[8] == -1{
            button8.setImage(UIImage(named: "mark_batsu"), for: UIControl.State())//ばつにする
        }
        else{
            button8.setImage(UIImage(named: "white"), for: UIControl.State())//しろにする
        }
    }
```

次に勝利条件をチェックする関数も作る。

```swift:ViewController.swift
    func check(_ squaresArray: [Int]){
        print(squaresArray)
        for i in 0...2{
            if (squaresArray[3 * i] == 1) && (squaresArray[(3 * i) + 1] == 1) && (squaresArray[(3 * i) + 2] == 1){
                turnLabel.text = "◯ の勝ち!!"
                break
            }
            if (squaresArray[3 * i] == -1) && (squaresArray[(3 * i) + 1] == -1) && (squaresArray[(3 * i) + 2] == -1){
                turnLabel.text = "X の勝ち!!"
                break
            }
            if (squaresArray[0 + i] == 1) && (squaresArray[3 + i] == 1) && (squaresArray[6 + i] == 1){
                turnLabel.text = "◯ の勝ち!!"
                break
            }
            if (squaresArray[0 + i] == -1) && (squaresArray[3 + i] == -1) && (squaresArray[6 + i] == -1){
                turnLabel.text = "X の勝ち!!"
                break
            }
            if (squaresArray[0] == 1) && (squaresArray[4] == 1) && (squaresArray[8] == 1){
                turnLabel.text = "◯ の勝ち!!"
                break
            }
            if (squaresArray[0] == -1) && (squaresArray[4] == -1) && (squaresArray[8] == -1){
                turnLabel.text = "X の勝ち!!"
                break
            }
            if (squaresArray[2] == 1) && (squaresArray[4] == 1) && (squaresArray[6] == 1){
                turnLabel.text = "◯ の勝ち!!"
                break
            }
            if (squaresArray[2] == -1) && (squaresArray[4] == -1) && (squaresArray[6] == -1){
                turnLabel.text = "X の勝ち!!"
                break
            }
        }
    }
```
とりあえずここまではこんな感じ。
![スクリーンショット 2020-02-12 18.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/658880d8-04dd-9bdf-e044-6d3348caf438.png)
進めていくと
![スクリーンショット 2020-02-12 18.28.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/e2022429-2dbd-5058-65c3-5f95a996f8e1.png)
こんな感じで勝ちのプレイヤーが表示される。

###マルバツゲームの盤面のベクトルを変えれるようにする
上下左右に対応したボタンを押すと、その方向にベクトルがかかって一度置いたマル・バツがずれるようにしたい。
なんか重力操れるみたいでかっこいいよね。

「up」ボタンを押したら上方向のベクトルがかかるようにする関数を作成。

```swift:ViewController.swift
//上方向のベクトル
func gravityU(_ squaresArray: inout [Int]){
        var line1: [Int] = [squaresArray[0],squaresArray[3],squaresArray[6]]
        var line2: [Int] = [squaresArray[1],squaresArray[4],squaresArray[7]]
        var line3: [Int] = [squaresArray[2],squaresArray[5],squaresArray[8]]
        var lineArray: [Int] = []
        /*-------------------------------*/
        for i in line1{
            if i != 0{
                lineArray.append(i)
            }
            line1 = lineArray
        }
        
        let line1Count = line1.count
        if line1Count == 0{
            line1 = [0,0,0]
        }
        else if line1Count == 1{
            line1.append(0)
            line1.append(0)
        }
        else if line1Count == 2{
            line1.append(0)
        }
        squaresArray[0] = line1[0]
        squaresArray[3] = line1[1]
        squaresArray[6] = line1[2]
        lineArray = []
        /*-------------------------------*/
        for i in line2{
            if i != 0{
                lineArray.append(i)
            }
            line2 = lineArray
        }
        let line2Count = line2.count
        if line2Count == 0{
            line2 = [0,0,0]
        }
        else if line2Count == 1{
            line2.append(0)
            line2.append(0)
        }
        else if line2Count == 2{
            line2.append(0)
        }
        squaresArray[1] = line2[0]
        squaresArray[4] = line2[1]
        squaresArray[7] = line2[2]
        lineArray = []
        /*-------------------------------*/
        for i in line3{
            if i != 0{
                lineArray.append(i)
            }
            line3 = lineArray
        }
        let line3Count = line3.count
        if line3Count == 0{
            line3 = [0,0,0]
        }
        else if line3Count == 1{
            line3.append(0)
            line3.append(0)
        }
        else if line3Count == 2{
            line3.append(0)
        }
        squaresArray[2] = line3[0]
        squaresArray[5] = line3[1]
        squaresArray[8] = line3[2]
        lineArray = []
        /*-------------------------------*/
    }
```

上下左右、他の方向分の関数も作成。

#完成
とりあえず、完成。
動かしてみるとこんな感じ。
![スクリーンショット 2020-02-12 17.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/646b889d-8273-71e4-f84a-8fe280d273a4.png)
ここで「up」ボタンを押すと
![スクリーンショット 2020-02-12 17.25.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449214/46db85e2-e9ec-ebf6-5394-52c9303f8342.png)
こんな風に上にマル・バツがずれる。:arrow_double_up:
勝利条件のチェックも問題なくできるので、とりあえずこれでok。

#終わりに
久しぶりにSwift触ってみたけど、自分のアイデアとかが目に見える形で実際に動くのは面白い。
まだUIとかボタンの制約とかが荒削りなので、今後これをもっと作り込みたい。

以上、第三回研究室ハッカソン備忘録。