Swift5+Xcode11.6
今回のゴール
おそるおそる機能を追加していくことにして、前回作成した基盤部分の処理結果をデバッグウィンドウではなく、画面に表示させます。
配列の値が存在しないときの処理は?
とりあえず、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″の辺りです)。