サイトアイコン BergamotMagic

おそるおそるSwift 4-3 ハイローゲームを作る ~処理結果を表示する~

Swift5+Xcode11.6

今回のゴール

 おそるおそる機能を追加していくことにして、前回作成した基盤部分の処理結果をデバッグウィンドウではなく、画面に表示させます。

https://bergamotmagic.tokyo/wp-content/uploads/2020/09/0abe1aab0e4a066679de99ca0ef81db0.mp4
今回のゴールのプレビュー

配列の値が存在しないときの処理は?

 とりあえず、ContentView.Swiftのコードです。結果を表示させるテキストフィールドを追加しています(67〜71行目)。また、後で説明しますが、抽選履歴の表示部分をprocessor.num(x)に書き換えています(29〜37行目)。

import SwiftUI

struct ContentView: View {
    @ObservedObject var processor = Processor()
    
    var body: some View {
        VStack {
            Text("High&Low Game!")
                .font(.largeTitle)
                .fontWeight(.heavy)
                .foregroundColor(Color.white)
                .background(Color.orange)
            Spacer()
            HStack {
                Spacer()
                Text("3回前")
                    .frame(width: 50.0)
                Text("2回前")
                    .frame(width: 50.0)
                Text("前回")
                    .frame(width: 50.0)
                Text("今回")
                    .font(.title)
                    .frame(width: 80.0)
                Spacer()
            }
            HStack {
                Spacer()
                Text(processor.num(times:4))
                    .frame(width: 50.0)
                Text(processor.num(times:3))
                    .frame(width: 50.0)
                Text(processor.num(times:2))
                    .frame(width: 50.0)
                Text(processor.num(times:1))
                    .font(.largeTitle)
                    .frame(width: 80.0)
                Spacer()
            }
                Spacer()
            HStack {
                Spacer()
                Button(action: {
                    self.processor.judge(choice: "high")
                }) {
                    Text("High")
                        .font(.largeTitle)
                        .fontWeight(.bold)
                        .foregroundColor(Color.white)
                }
                .frame(width: 100.0)
                .background(Color.red)
                Spacer()
                Button(action: {
                    self.processor.judge(choice: "low")
                }) {
                    Text("Low")
                    .font(.largeTitle)
                    .fontWeight(.bold)
                    .foregroundColor(Color.white)
                }
                .frame(width: 100.0)
                .background(Color.blue)
                Spacer()
            }
            Spacer()
            Text(processor.result)
                .font(.title)
                .fontWeight(.heavy)
                .foregroundColor(Color.orange)
                .multilineTextAlignment(.center)
            Text("$1")
                .font(.largeTitle)
                .fontWeight(.black)
                .foregroundColor(Color.red)
            Spacer()
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

 さて、これまでの抽選履歴を「3回前」「2回前」「前回」と表示させる設計にしましたが、ゲームスタートの段階では、配列には値が1つ(history[0] = 5)しかありません。このとき3回前の値をhistory[history.endIndex – 4]で取り出そうとしても、Out of Rangeエラーか何かが返ってくるのは容易に想像できます。
 「オプショナル型とやらを使うのか?それともエラーが出たときの処理を書くのか?」等と悩んだのですが、history.endIndexの数を数えさせることにしました。ContentViewのTextフィールドにif文を置けないようなので、Processorクラスにnum関数を定義しました。
 また、結果を表示させるためには戻り値では都合が悪いため、returnを止めてresult変数に代入させることにしました。
 改造後のprocessorx.swiftです。

import Foundation

class Processor : ObservableObject {
    @Published var history :[Int] = [5] //history:抽選数字履歴保持用配列
    @Published var result: String = ""
    var randNum: Int = 0     //randNum:乱数
    
//    func judge(choice:String) -> String {
    func judge(choice:String) {
        randNum = Int.random(in:1...9)
        history.append(self.randNum)
        for (index, his) in history.enumerated() { 
            print("history[\(index)]: \(his)")
        }
        print("endIndex:\(history.endIndex)")
        let prevNum:Int = history[history.endIndex - 2] //prevNum:1つ前の抽選数字
        print ("prevNum:\(prevNum)")
        let nowNum:Int = history[history.endIndex - 1]  //nowNum:今回の抽選数字
        print ("NowNum:\(nowNum)")
        if (nowNum == prevNum) || ((nowNum >= prevNum)&&(choice == "high")) || ((nowNum <= prevNum)&&( choice == "low")) {
            result = "Win"
        } else {
            result = "lose"
        }
    }
    
    func num(times:Int) -> String {
        if history.endIndex >= times {
            return String(history[history.endIndex - times])
        } else {
            return "-"
        }
    }
}

 何回前の抽選履歴を引いてくるのかを引数timesで指定させています。今回はそれほど面倒ではありませんでしたが、selfの使い方がまだよく飲み込めていません。そのうちピカーンと閃くことを期待しつつ、今のところはごまかしごまかし進めます。
 それと、今までは何となく@State宣言した変数がないと動作しないような気がしていたのですが、このコードには1つもないことに気づきました(という私的発見のつぶやきです)。

次回は

 ハイ&ローゲームの醍醐味は、成功すれば賞金が倍増する一方で、1回でも失敗したら全てを失うところなので、その辺りを作り込んでみようと思います(今のところ、ピクリとも動かない”$1″の辺りです)。

モバイルバージョンを終了