新Swiftで行こう…第89回「ババ抜き11解説」 田部井保
btnHikuTouch関数とhiku関数をまとめます。
//
// ViewController.swift
// baba
//
// Created by 保 Tabei on 2024/10/12.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//53枚のカードを並べる
put53()
}
///4人分のカードのラベル
var eachCard: [[UILabel]] = [[],[],[],[]]
///4人の内どれを自分にするかのボタン
var eachButton: [UIButton] = []
///カードクラス、ジョーカー込みで初期化
var cardObj:Card = Card(cdCnt: Card.EnumCard.joker)
///53枚のカードを並べる関数
func put53() {
//4人分
for i in 0 ..< 4 {
//14枚(一人目)か13枚(2〜4人目)
for j in 0 ..< 14 {
//ラベルを生成
let lbl = UILabel(frame: CGRectMake(0, 0, 50, 21))
//ラベルの中心を設定
lbl.center = CGPointMake(50 + 40 * CGFloat(j % 7), 150 + 120 * CGFloat(i) +
50 * CGFloat(j / 7))
//ラベルのテキスト位置を設定
lbl.textAlignment = NSTextAlignment.center
//2人目〜4人目の14枚目は空
if i != 0 && j == 13 {
lbl.text = " "
//13枚目までと一人目の14枚目
} else {
lbl.text = "⬛️"
}
//4人分のカードラベルに追加
eachCard[i] += [lbl]
//ラベルをフォームに追加
self.view.addSubview(lbl)
}
//ボタンを生成
let btn = UIButton(frame: CGRectMake(0, 0, 50, 21)) as UIButton
//ボタンの中心を設定
btn.center = CGPointMake(20, 150 + 120 * CGFloat(i) + 25)
//ボタンの表示文字列を指定(白丸)
btn.setTitle("⚪️", for: .normal)
//ボタンのテキストカラーを設定
btn.setTitleColor(UIColor.black, for: .normal)
//ボタンが押された時に動作する関数を指定
btn.addTarget(self, action: #selector(btnTapped), for: .touchUpInside)
//ボタン式別用にタグにiを入れる
btn.tag = i
//ボタン配列に加える
eachButton += [btn]
//ボタンをフォームに追加
self.view.addSubview(btn)
}
//配る
share()
//表示する
show()
}
///自分選択が出来るか
var btnEnable = true
///自分選択ボタンが押された時の処理
@objc func btnTapped(sender: UIButton) {
//自分選択が出来ない時
if btnEnable == false {
//処理終了
return
}
//4人分ループ
for i in 0 ..< 4 {
//押されたボタンの場合
if eachButton[i] == sender {
//タイトルが白丸なら
if sender.currentTitle == "⚪️" {
//タイトルを黒丸に
sender.setTitle("⚫️", for: .normal)
//タイトルが黒丸なら
} else {
//タイトルを白丸に
sender.setTitle("⚪️", for: .normal)
}
//押されたボタン以外
} else {
//タイトルを白丸にする
eachButton[i].setTitle("⚪️", for: .normal)
}
}
}
///配る
func share() {
//自分選択が出来る様に
btnEnable = true
//初期状態にする
cardObj.reset()
//4人分
for i in 0 ..< 4 {
//最大14枚
for j in 0 ..< 14 {
//2人〜4人目14枚目
if i != 0 && j == 13 {
//無効カード
eachCard[i][j].tag = -1
} else {
//カードを引いてtagに
eachCard[i][j].tag = cardObj.put()
}
}
}
}
///表示する
func show() {
//4人分
for i in 0 ..< 4 {
//最大14枚
for j in 0 ..< 14 {
//カードのタグが0以上なら
if eachCard[i][j].tag >= 0 {
//カードの表を表示
eachCard[i][j].text = cardObj.disp(card: eachCard[i][j].tag)
//カードのタグが0より小さいなら
} else {
//カードは空白
eachCard[i][j].text = " "
}
}
}
}
///再配布ボタン
@IBAction func btnGoTouch(_ sender: Any) {
//配る
share()
//表示する
show()
}
///ペアを除くボタン押下時処理
@IBAction func btnPairTouch(_ sender: Any) {
//選択されているかフラグとりあえず選択されていない
var selected = false
//4人分調べる
for i in 0 ..< 4 {
//黒丸があったら
if eachButton[i].currentTitle == "⚫️" {
//選択されている
selected = true
//ループを抜ける
break
}
}
//選択されていない時
if !selected {
//アラートを出す
let alert = UIAlertController()
alert.title = "選択"
alert.message = "4組のうちのどれかを選択して下さい。"
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true, completion: nil)
//処理を抜ける
return
}
//自分選択が出来ない様に
btnEnable = false
//4人分ループ
for i in 0 ..< 4 {
//最大13枚ループ
for j in 0 ..< 13 {
//ジョーカーかカードのタグが−1なら次のjのループへ
if (eachCard[i][j].tag == 52) || (eachCard[i][j].tag == -1) {
//以下の処理は行わず次のjのループへ
continue
}
//jの次のカードから14枚目までループ
for k in j + 1 ..< 14 {
//ジョーカーかカードのタグが−1なら次のkのループへ
if (eachCard[i][k].tag == 52) || (eachCard[i][k].tag == -1) {
//以下の処理は行わず次のkのループへ
continue
}
//jの位置のカード番号とkの位置のカード番号が同じなら
if (eachCard[i][j].tag % 13) == (eachCard[i][k].tag % 13) {
//jの位置のカードのタグを−1に
eachCard[i][j].tag = -1
//kの位置のカードのタグを−1に
eachCard[i][k].tag = -1
//kのループは終了
break
}
}
}
//無効カードが見つかったか保持する変数
var find = false
//左側のカード位置
var k = 0
//調査するカード位置
for j in 0 ..< 14 {
//調査カードが無効カードなら
if eachCard[i][j].tag == -1 {
//無効カードが見つかった
find = true
//調査カードが無効カードでないなら
} else {
//無効カードが見つかっていたら
if find {
//カードを左側に詰める
eachCard[i][k].tag = eachCard[i][j].tag
eachCard[i][j].tag = -1
}
//左側カード位置を+1する
k += 1
}
}
}
//表示する
show()
}
///i+1番目の人のカードを次の人が引くrandmがtrueならコンピュータ、falseなら人間
func take(i: Int, randm: Bool) {
//i+1番目の人のカードの数
var kl = 14
//i+1番目の人のカードをチェックする
for j in 0 ..< 14 {
//カードが無効なら
if eachCard[i][j].tag == -1 {
//1番目の人の最後のカード+1
kl = j
break
}
}
//i+1番目の人の次の人が引いたカード
var k = 0
//randmがtrueなら
if randm {
//引く位置をランダムに指定
k = Int.random(in: 0 ..< kl)
} else {
//i+1番目の人のカード枚数分ループ
for j in 0 ..< kl {
//カード選択ボタン配列でタグが1のもの
if eachCardButton[j].tag == 1 {
//ユーザーが引くカード位置決定
k = j
//ループを抜ける
break
}
}
}
//i+1番目の人の次の人
var ii = 0
//iが1〜3番目の人の場合はiに1を足したもの
if i < 3 {
ii = i + 1
//iが4番目の人の場合は0
} else {
ii = 0
}
//引いたカードと同じナンバーのカードがあった
var stop = false
//引いたカードがジョーカー以外
if eachCard[i][k].tag != 52 {
//ii+1番目の人のカードをチェックする
for jj in 0 ..< 14 {
//引いたカードと同じナンバーのカードがあったら、詰める
if stop {
//詰める
eachCard[ii][jj - 1].tag = eachCard[ii][jj].tag
}
//無効カードだったら
if eachCard[ii][jj].tag == -1 {
//ループを抜ける
break
}
//ジョーカーなら次のループ
if eachCard[ii][jj].tag == 52 {
//次のループ
continue
}
//引いたカードと同じナンバーのカードがあったら
if (eachCard[ii][jj].tag % 13) == (eachCard[i][k].tag % 13) {
//フラグを立てる
stop = true
}
}
}
//引いたカードと同じナンバーのカードが無かったら
if stop == false {
//2番目の人のカードをチェック
for jj in 0 ..< 14 {
//無効カードが見つかったら
if eachCard[ii][jj].tag == -1 {
//引いたカードをそこに置く
eachCard[ii][jj].tag = eachCard[i][k].tag
break
}
}
}
//i+1番目の人のカード、次の人が引いたカードより後ろのカードを一つずつ詰める
for j in k + 1 ..< 14 {
eachCard[i][j - 1].tag = eachCard[i][j].tag
}
//i+1番目の人の最後のカードを無効に
eachCard[i][13].tag = -1
//表示する
show()
}
///2番目の人が1番目の人のカードを1枚引く
@IBAction func hiku(_ sender: Any) {
//1番目の人のカードを2番目の人が引く
take(i: 0, randm: true)
}
///ユーザーが引くカードを選択するボタン配列
var eachCardButton: [UIButton] = []
///2番目の人のカードをシャッフルする
@IBAction func shuffle(_ sender: Any) {
//2番目の人
let i = 1
//2番目の人のカード枚数
var kl = 14
//2番目の人のカードを取っておく配列
var cardList: [Int] = []
//2番目の人のカード、無効カードが出るまで検査
for j in 0 ..< 14 {
//無効カードが出たら
if eachCard[i][j].tag == -1 {
//2番目の人のカード枚数はj
kl = j
//ループを抜ける
break
}
//2番目の人のカードを取っておく
cardList += [eachCard[i][j].tag]
}
//2番目の人のカード枚数分ループ
for j in 0 ..< kl {
//ランダムにカードを選択、最初は2番目の人のカード枚数、順に1引いてゆく
let jj = Int.random(in: 0 ..< kl - j)
//2番目の人のカード、左から順にセットする
eachCard[i][j].tag = cardList[jj]
//ランダムに選択したカードを後ろのカードで順に詰める、段々最後のカードが1つ前に行く
for k in jj ..< kl - j - 1 {
//次のカードで今のカードを上書き
cardList[k] = cardList[k + 1]
}
}
//表示する
show()
//2番目の人のカードにボタンを付けユーザーが引けるようにする
//2番目の人のカードの数ループ
for j in 0 ..< kl {
//ボタンを生成する
let btn = UIButton(frame: CGRectMake(0, 0, 50, 21))
//ボタンの中心を指定
btn.center = CGPointMake(50 + 40 * CGFloat(j % 7), 150 + 120 * CGFloat(i) + 50 * CGFloat(j / 7))
//四角いマークをボタンのタイトルに
btn.setTitle("◼︎", for: .normal)
//ボタンを青に
btn.setTitleColor(UIColor.blue, for: .normal)
//ボタンが押された時にcardBtnTapped関数を呼ぶ
btn.addTarget(self, action: #selector(cardBtnTapped), for: .touchUpInside)
//タグを0に
btn.tag = 0
//ボタン配列に生成したボタンを追加
eachCardButton += [btn]
//ボタンを描画
self.view.addSubview(btn)
}
}
//カード選択ボタンが押された時に動作する関数
@objc func cardBtnTapped(sender: UIButton) {
//カード選択ボタン配列の全ボタンを青色に
for cardBtn in eachCardButton {
cardBtn.setTitleColor(UIColor.blue, for: .normal)
//タグを0に
cardBtn.tag = 0
}
//選んだボタンを赤色に
sender.setTitleColor(UIColor.red, for: .normal)
//タグを1に
sender.tag = 1
}
///ユーザーが2番目の人のカードを引く処理
@IBAction func btnHikuTouch(_ sender: Any) {
//2番目の人のカード3番目の人(ユーザー)が引く
take(i: 1, randm: false)
//カード選択ボタンを画面から消す
for cardBtn in eachCardButton {
cardBtn.removeFromSuperview()
}
//カード選択ボタン配列を消去する
eachCardButton.removeAll()
}
}
まとめた2つの関数、殆ど同じだったのですが、コンピュータが引くかユーザーが引くかの違いがあります。コンピュータなら乱数を発生させて引く。ユーザーなら選択したカードを引くという違いがあります。そこで、今回まとめたtake関数、Bool型のrandmという引数を用意して、randmがtrueならコンピュータ、falseならユーザーとしています。251行目からがその部分で、253行目で乱数を発生させて、コンピュータが引く位置を求めています。256行目からが、ユーザーが選択したカードの位置をカード選択ボタン配列の各要素のtagを調べることで割り出しています。
268行目から275行目で、i の次の人を割り出しています。ii に入れています。i が3より小さいなら1を足し、i が3なら0にしています。この部分は、ババ抜きをやっているとカードが無くなって抜ける人が出てくるので、最終的には手直しが必要ですが、今の内は抜ける人はまだ居ないとして、単純に次の人にしています。
hiku関数は、
take(i: 0, randm: true)
だけになりました。take関数に i の引数には0(1番目の人)、randm の引数には true(乱数を発生させる。コンピュータ)を与えています。ここの i と randm を調整する事で、色々な場合に対応できます。
btnHikuTouch関数は、
take(i: 1, randm: false)
がまず来ます。take関数に i の引数には1(2番目の人)、randm の引数には false(乱数を発生させない。ユーザー)を与えています。その後ユーザーのカード選択ボタンを消す処理を今まで通りしています。