背景
待ちを判断する能力が欲しい。。前回Pythonを使って待ちの判定をしてもらうプログラムを作ってみたがそんなもの実践で使えるわけもなく。。
地道な努力あるのみ!ということでクイズアプリにして練習することにしました。
使用言語はswiftUIです。下に製品のコードほとんど全部載っけてます笑
完成品
完成品はこちらからダウンロードできます。
こんなものを作ってみました。
問題についてはPythonを使って自動生成してますのでこちらを見てみてください。
コード
メイン機能の実装全て載せてます笑
特に通信を行なっていないので問題ないはず、、、
バグ見つけたり悪い書き方してたりを発見してたらご一報のほどよろしくお願いします。
import UIKit class ViewController: UIViewController, NextDelegate{ let userDefaults = UserDefaults.standard var mode = "endless" override func viewDidLoad() { super.viewDidLoad() userDefaults.register(defaults: ["koukaonn": true]) userDefaults.register(defaults: ["time": "--:--:--"]) userDefaults.register(defaults: ["count": "0"]) userDefaults.register(defaults: ["color": 0]) userDefaults.register(defaults: ["buy" : 0]) userDefaults.register(defaults: ["paisyu" : 0]) let haikei_tmp: Int = userDefaults.object(forKey: "color") as! Int if haikei_tmp == 0 { view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) } else{ view.backgroundColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) } // Do any additional setup after loading the view. } @IBAction func start(_ sender: Any) { mode = "timeattack" performSegue(withIdentifier: "next", sender: nil) } @IBAction func endless(_ sender: Any) { mode = "endless" performSegue(withIdentifier: "next", sender: nil) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "next"{ let nextVC = segue.destination as! NextViewController nextVC.delegate = self nextVC.mode = mode } } }
import UIKit protocol ResultDelegate { } class ResultViewController: UIViewController,ResultAnswerDelegate { @IBOutlet weak var correctStackView: UIStackView! var received_answer = [Bool]() var random_array = [Int]() var time = "00:00:00" var all_user_answers = [[Bool]]() var mode = "" var pai_list = [Int]() let userDefaults = UserDefaults.standard @IBOutlet weak var seikaisuLabel: UILabel! @IBOutlet weak var resultTime: UILabel! @IBOutlet var resultButton: [UIButton]! override func viewDidLoad() { super.viewDidLoad() var count = 0 for i in 0...9{ let maru_pic = UIImage(named: "maru")?.withRenderingMode(.alwaysOriginal) let batsu_pic = UIImage(named: "batsu")?.withRenderingMode(.alwaysOriginal) if received_answer[i] == true{ resultButton[i].setImage(maru_pic, for: .normal) count += 1 } else{ resultButton[i].setImage(batsu_pic, for: .normal) } } resultTime.text = String(time) seikaisuLabel.text = String(count) + "問/10問" if count == 10{ userDefaults.set(time,forKey: "time") } let haikei_tmp: Int = userDefaults.object(forKey: "color") as! Int if haikei_tmp == 0 { view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) } else{ view.backgroundColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) } // Do any additional setup after loading the view. } @IBAction func showAnswer(_ sender: UIButton) { performSegue(withIdentifier: "resultanswer", sender: sender.tag) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "resultanswer"{ let resultAnswerVC = segue.destination as! ResultDetailViewController let tmp = sender as! Int resultAnswerVC.received_answer = received_answer resultAnswerVC.random_array = random_array resultAnswerVC.received_button_num = tmp resultAnswerVC.all_user_answers = all_user_answers resultAnswerVC.resulttime = time resultAnswerVC.mode = mode resultAnswerVC.pai = pai_list[tmp] resultAnswerVC.pai_list = pai_list } } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destination. // Pass the selected object to the new view controller. } */ }
import UIKit protocol ResultAnswerDelegate { } class ResultDetailViewController: UIViewController ,NextDelegate{ var received_answer = [Bool]() // random_array はrandom_array で出題した問題番号 var random_array = [Int]() var received_button_num = 0 let all_question = QuestionList() var resulttime = "" var all_user_answers = [[Bool]]() var mode = "" var user_answer = [Bool]() var correct_answer = [Bool]() var count = 0 var pai = 0 var pai_list = [Int]() let userDefaults = UserDefaults.standard @IBOutlet weak var back_b: UIButton! @IBOutlet weak var next_b: UIButton! @IBOutlet var questionImage: [UIImageView]! @IBOutlet var correctAnswer: [UIImageView]! @IBOutlet var yourAnswer: [UIImageView]! @IBOutlet weak var seikaiImage: UIImageView! override func viewDidLoad() { super.viewDidLoad() var show_num = 0 var question_image_list = ["1"] var answer_image_list = [false] if mode == "timeattack"{ next_b.isHidden = true seikaiImage.isHidden = true show_num = random_array[received_button_num] user_answer = all_user_answers[received_button_num] question_image_list = all_question.list[show_num].question answer_image_list = all_question.list[show_num].answer } else if mode == "endless"{ back_b.isHidden = true show_num = random_array[count] question_image_list = all_question.list[show_num].question answer_image_list = all_question.list[show_num].answer if user_answer == correct_answer{ seikaiImage.image = UIImage(named: "maru") } else { seikaiImage.image = UIImage(named: "batsu") } } if userDefaults.object(forKey: "color") as! Int == 0 { view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) } else if userDefaults.object(forKey: "color") as! Int == 1{ view.backgroundColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) } for i in 0...12{ var image_name = String(question_image_list[i]) if pai == 1{ image_name = String(question_image_list[i])+"_sou" } else if pai == 2{ image_name = String(question_image_list[i])+"_man" }else{ image_name = String(question_image_list[i]) } questionImage[i].image = UIImage(named: image_name) } for i in 0...8{ if answer_image_list[i] == false{ let image_name = String(i+1) var tmp = UIImage(named: image_name) if pai == 1{ tmp = UIImage(named: image_name + "_sou") } else if pai == 2{ tmp = UIImage(named: image_name + "_man") } else { tmp = UIImage(named: image_name) } correctAnswer[i].image = tmp }else { let image_name_kurai = String(i+1) var tmp_kurai = UIImage(named: image_name_kurai) if pai == 1{ tmp_kurai = UIImage(named: image_name_kurai + "_sou"+"_kurai") } else if pai == 2{ tmp_kurai = UIImage(named: image_name_kurai + "_man"+"_kurai") } else { tmp_kurai = UIImage(named: image_name_kurai + "_kurai") } correctAnswer[i].image = tmp_kurai } } for i in 0...8{ if user_answer[i] == false{ let image_name = String(i+1) var tmp = UIImage(named: image_name) if pai == 1{ tmp = UIImage(named: image_name + "_sou") } else if pai == 2{ tmp = UIImage(named: image_name + "_man") } else { tmp = UIImage(named: image_name) } yourAnswer[i].image = tmp }else { let image_name_kurai = String(i+1) var tmp_kurai = UIImage(named: image_name_kurai) if pai == 1{ tmp_kurai = UIImage(named: image_name_kurai + "_sou"+"_kurai") } else if pai == 2{ tmp_kurai = UIImage(named: image_name_kurai + "_man"+"_kurai") } else { tmp_kurai = UIImage(named: image_name_kurai + "_kurai") } yourAnswer[i].image = tmp_kurai } } // Do any additional setup after loading the view. } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "back"{ let resultVC = segue.destination as! ResultViewController resultVC.received_answer = received_answer resultVC.random_array = random_array resultVC.all_user_answers = all_user_answers resultVC.time = resulttime resultVC.mode = mode resultVC.pai_list = pai_list } else if segue.identifier == "next"{ let nextVC = segue.destination as! NextViewController nextVC.random_array = random_array nextVC.count = count nextVC.mode = mode } } @IBAction func backButton(_ sender: Any) { performSegue(withIdentifier: "back", sender: nil) } @IBAction func nextButton(_ sender: Any) { count += 1 performSegue(withIdentifier: "next", sender: nil) } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destination. // Pass the selected object to the new view controller. } */ }
import UIKit import AVFoundation var player:AVAudioPlayer! protocol NextDelegate { } class NextViewController: UIViewController,ResultDelegate,ResultAnswerDelegate { var delegate:NextDelegate? var mode = "" var pai = 0 var pai_list = [Int]() let userDefaults = UserDefaults.standard @IBOutlet weak var question_count: UILabel! @IBOutlet weak var timerMinute: UILabel! @IBOutlet weak var timerSecond: UILabel! @IBOutlet weak var timerMSec: UILabel! @IBOutlet var answerButton: [UIButton]! @IBOutlet var questionImageView: [UIImageView]! var correct_answer = [Bool]() var count = 0 var random_array = [Int]() var question_num = 0 var question_image_list = [String]() var user_answer = [Bool]() var user_correct = [Bool]() var all_user_answers = [[Bool]]() weak var timer: Timer! var startTime = Date() let maru_path = Bundle.main.url(forResource: "maruSound", withExtension:"mp3")! let batsu_path = Bundle.main.url(forResource: "batsuSound", withExtension:"mp3")! let all_question = QuestionList() override func viewDidLoad() { super.viewDidLoad() // 問題をシャッフルする。インデックスが入ってる。 random_array = [Int](0...all_question.list.count-1) random_array = random_array.shuffled() // 次の問題 nextQuestion() if timer != nil{ // timerが起動中なら一旦破棄する timer.invalidate() } startTimer() if userDefaults.object(forKey: "color") as! Int == 0 { view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) } else if userDefaults.object(forKey: "color") as! Int == 1{ view.backgroundColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1) } // Do any additional setup after loading the view. } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(true) timer.invalidate() } // ここからの機能はボタンごとに押した時の動作を記述 // 基本的には選択の状態のみを保持 @IBAction func onepai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func twopai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func threepai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func fourpai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func fivepai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func sixpai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func sevenpai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func eightpai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } @IBAction func ninepai(_ sender: UIButton) { sender.switchAction(onAction: { }) { } } func nextQuestion(){ pai = userDefaults.object(forKey: "paisyu") as! Int if pai == 3{ pai = Int.random(in: 0..<3) } pai_list.append(pai) if mode == "timeattack"{ if count > 9{ timer.invalidate() performSegue(withIdentifier: "result", sender: nil) }else{ for i in answerButton{ if pai == 1{ let tmp = UIImage(named: String(i.tag) + "_sou") let tmp_kurai = UIImage(named: String(i.tag) + "_sou" + "_kurai") i.setImage(tmp, for: .normal) i.setImage(tmp_kurai, for: .selected) } else if pai == 2{ let tmp = UIImage(named: String(i.tag) + "_man") let tmp_kurai = UIImage(named: String(i.tag) + "_man" + "_kurai") i.setImage(tmp, for: .normal) i.setImage(tmp_kurai, for: .selected) } else { let tmp = UIImage(named: String(i.tag)) let tmp_kurai = UIImage(named: String(i.tag) + "_kurai") i.setImage(tmp, for: .normal) i.setImage(tmp_kurai, for: .selected) } i.isSelected = true } question_num = random_array[count] question_image_list = all_question.list[question_num].question for i in 0...12{ var image_name = String(question_image_list[i]) if pai == 1{ image_name = String(question_image_list[i])+"_sou" } else if pai == 2{ image_name = String(question_image_list[i])+"_man" }else{ image_name = String(question_image_list[i]) } questionImageView[i].image = UIImage(named: image_name) } correct_answer = all_question.list[question_num].answer count += 1 user_answer = [] question_count.text = String(count) + "問/10問" } } else if mode == "endless"{ for i in answerButton{ if pai == 1{ let tmp = UIImage(named: String(i.tag) + "_sou") let tmp_kurai = UIImage(named: String(i.tag) + "_sou" + "_kurai") i.setImage(tmp, for: .normal) i.setImage(tmp_kurai, for: .selected) } else if pai == 2{ let tmp = UIImage(named: String(i.tag) + "_man") let tmp_kurai = UIImage(named: String(i.tag) + "_man" + "_kurai") i.setImage(tmp, for: .normal) i.setImage(tmp_kurai, for: .selected) }else { let tmp = UIImage(named: String(i.tag)) let tmp_kurai = UIImage(named: String(i.tag) + "_kurai") i.setImage(tmp, for: .normal) i.setImage(tmp_kurai, for: .selected) } i.isSelected = true } question_num = random_array[count] question_image_list = all_question.list[question_num].question for i in 0...12{ var image_name = String(question_image_list[i]) if pai == 1{ image_name = String(question_image_list[i])+"_sou" } else if pai == 2{ image_name = String(question_image_list[i])+"_man" }else{ image_name = String(question_image_list[i]) } questionImageView[i].image = UIImage(named: image_name) } correct_answer = all_question.list[question_num].answer question_count.text = String(count+1) + "問目" timerMinute.isHidden = true timerSecond.isHidden = true timerMSec.isHidden = true } } @IBAction func answer(_ sender: Any) { for i in answerButton{ user_answer.append(i.isSelected) } if mode == "timeattack"{ all_user_answers.append(user_answer) if user_answer == correct_answer{ let url = maru_path if userDefaults.object(forKey: "koukaonn") as! Bool{ do { player = try AVAudioPlayer(contentsOf: url) player?.play() } catch { // couldn't load file :( } } user_correct.append(true) let tmp: String = userDefaults.object(forKey: "count") as! String userDefaults.setValue(String(Int(tmp)!+1 ), forKey: "count") nextQuestion() }else{ let url = batsu_path if userDefaults.object(forKey: "koukaonn") as! Bool{ do { player = try AVAudioPlayer(contentsOf: url) player?.play() } catch { // couldn't load file :( } } user_correct.append(false) nextQuestion() } }else if mode == "endless"{ if user_answer == correct_answer{ let url = maru_path if userDefaults.object(forKey: "koukaonn") as! Bool{ do { player = try AVAudioPlayer(contentsOf: url) player?.play() } catch { // couldn't load file :( } } let tmp: String = userDefaults.object(forKey: "count") as! String userDefaults.setValue(String(Int(tmp)!+1 ), forKey: "count") performSegue(withIdentifier: "resultanswer", sender: nil) }else{ let url = batsu_path if userDefaults.object(forKey: "koukaonn") as! Bool{ do { player = try AVAudioPlayer(contentsOf: url) player?.play() } catch { // couldn't load file :( } } performSegue(withIdentifier: "resultanswer", sender: nil) } } } func startTimer() { timer = Timer.scheduledTimer( timeInterval: 0.01, target: self, selector: #selector(self.timerCounter), userInfo: nil, repeats: true) } @objc func timerCounter() { // タイマー開始からのインターバル時間 let currentTime = Date().timeIntervalSince(startTime) // fmod() 余りを計算 let minute = (Int)(fmod((currentTime/60), 60)) // currentTime/60 の余り let second = (Int)(fmod(currentTime, 60)) // floor 切り捨て、小数点以下を取り出して *100 let msec = (Int)((currentTime - floor(currentTime))*100) // %02d: 2桁表示、0で埋める let sMinute = String(format:"%02d", minute) let sSecond = String(format:"%02d", second) let sMsec = String(format:"%02d", msec) timerMinute.text = sMinute timerSecond.text = sSecond timerMSec.text = sMsec } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "result"{ let resultVC = segue.destination as! ResultViewController resultVC.received_answer = user_correct resultVC.random_array = random_array resultVC.time = String(timerMinute.text!) + ":" + String(timerSecond.text!) + ":" + String(timerMSec.text!) resultVC.all_user_answers = all_user_answers resultVC.mode = mode resultVC.pai_list = pai_list } else if segue.identifier == "resultanswer"{ let resultAnswerVC = segue.destination as! ResultDetailViewController resultAnswerVC.mode = mode resultAnswerVC.user_answer = user_answer resultAnswerVC.correct_answer = correct_answer resultAnswerVC.count = count resultAnswerVC.random_array = random_array resultAnswerVC.pai = pai } } } extension UIButton { func switchAction(onAction: @escaping ()->Void, offAction: @escaping ()->Void) { //選択状態を反転 self.isSelected = !self.isSelected switch self.isSelected { case true: //ONにする時に走らせたい処理 onAction() case false: //OFFにする時に走らせたい処理 offAction() } } }
ここまで長々と載せていますが意味がわからないですね、、
全部は難しいですが、苦労したところなどを解説していきたいと思います。
コメント