あれとかこれとかそれとか

気まぐれプログラマーのブログです。簡単なことから小難しいことまで必死に勉強した内容を書き留めていきます。プログラム以外にも気になったことや面白かったことをまとめていこうと思います。

【Swift】 ArrayとDictionaryのネスト

Array型とDictionary型のネストのさせ方にハマりました。
データを作ったは良いが、配列の中身を確認する方法が少し難しかったのでおさらい。

データ構造:

  • section[data[item]]

①列挙体で、Dictionary型に使用するキー文字列を用意

②item(Dictionary型) を含む data(Array型) を用意

③data(Array型) を含む section(Dictionary型) を用意

④sectionからdataを辿り、itemのデータを表示

Array Dictionary 入れ子
Array 別の型 入れ子 ネスト 格納

【Swift】 リバーシを作りましょう #3 オブジェクトの配置と判定の追加

前回の記事はこちらから
aretoka-koretoka-soretoka.hatenablog.com

オブジェクトを打つため、setObject 関数を作成します。
引数では、打つ予定のオブジェクトタイプと打つ座標をもらいます。

①打てない条件のうち、
> 盤面の範囲外には打てない
をチェックし、条件に当てはまる場合には無処理で返ります。

②打てない条件のうち、
> 既にオブジェクトが打たれている座標には打てない
をチェックし、条件に当てはまる場合には無処理で返ります。
指定座標が " "(空白) 以外の場合、既にオブジェクトが打たれていると判断します。

③打てない条件のうち、
> 別種のオブジェクトをひっくり返せない座標には打てない
をチェックし、条件に当てはまる場合には無処理で返ります。

④指定した座標にオブジェクトを配置します。

// オブジェクトを配置(x:X座標,y:Y座標,type:オブジェクトタイプ(0 ■,!0 ●))
func setObject(x:Int,y:Int,type:Int) {
    // ①
    // 範囲外の場合はエラー
    if(workArray.count <= y || workArray[y].count <= x || y < 0 || x < 0) {
        print("over position")
        return
    }
    // ②
    // 既に何かが置かれている場合置けない
    if(workArray[y][x] != " ") {
        print("not put1")
        return
    }
    
    // ③
    // オブジェクトが置けるか検索
    if searchObject(x,y:y,type:type) {
        // ④
        // オブジェクトを配置
        workArray[y][x] = object[type]
    }
    else {
        print("not put2")
    }

    print("end")
}

以上で完成です。

setObject(6,y:5,type:0)

といった感じで使用することで workArray が書き変わります。
配列の中身を確認するために、以下のような関数を作成して確認してみましょう。

// 配列状態を表示
func printArray() {
    print("printArray")
    print("____0____1____2____3____4____5____6____7____8____9__")
    for var idx0 = 0; idx0 < workArray.count; idx0++ {
        print(idx0,workArray[idx0])
        for var idx1 = 0; idx1 < workArray[idx0].count; idx1++ {
        }
    }
}

完成したソースコードはこちらから。

reversi_for_swift · GitHub

確認は Playground や、SwiftStub何かを使用すると楽ちんです。

swiftstub.com

【Swift】 リバーシを作りましょう #2 周辺座標に存在するオブジェクトを検索する

前回の記事はこちらから
aretoka-koretoka-soretoka.hatenablog.com

周辺座標に存在するオブジェクトを確認するため、searchObject 関数を作成します。
引数では、打つ予定のオブジェクトタイプと打つ座標をもらいます。

処理の内容は

①ローカル変数を用意しています。

②周辺座標検索テーブルを仕様して、周辺8マスの状態を確認します。
 id0 は Y座標 id1 は X座標 を表します。

③引数で貰った座標に対して、オフセット座標を足し合わせて現在位置を作成します。
 現在位置が範囲外を差した場合は、何もせずに次の座標に進みます。

④現在位置に打たれているオブジェクトの状態をチェックします。
 引数で指定したオブジェクトと別のものが存在する場合は処理を継続します。

⑤指定座標からオブジェクトが同一オブジェクトではさみこめるかをチェックします。

⑥オフセット座標の方向10マス分先から順にオブジェクトの状態を確認していきます。
 この時、現在位置が範囲外を差した場合は、何もせずに次の座標に進みます。

⑦同じオブジェクトが存在する場合、pinch = true とし、次の座標からオブジェクトをひっくり返してゆく。

⑧はさみこみ判定を初期化して、次のオフセット座標をチェックしていく。

となっています。

// 周辺8マスを検索して置ける条件に当てはまれば置く(x:X座標,y:Y座標,type:オブジェクトタイプ(0 ■,!0 ●),戻り値:配置できるかどうか(true 可能, false 不可))
func searchObject(x:Int,y:Int,type:Int) -> Bool {
    // ①
    let revType = type == OBJTYPE.WHITE.rawValue ? OBJTYPE.BLACK.rawValue : OBJTYPE.WHITE.rawValue
    var ret = false     // 書き換え判定
    var pinch = false   // はさみこみ判定
    let oldArray = workArray

    print(x,y,"に",object[type],"を置こうとしています")
    
    // ②
    // 縦
    for var idx0 = 0; idx0 < searchTbl.count; idx0++ {
        // 横
        for var idx1 = 0; idx1 < searchTbl[idx0].count; idx1++ {
            // ③
            // 現在の座標
            let current:(x:Int,y:Int) = (x:x + searchTbl[idx0][idx1].x,y:y + searchTbl[idx0][idx1].y)
            let loop = searchTbl.count
            
            // 範囲外の場合はコンテニュー
            if(loop <= current.y || loop <= current.x || current.y < 0 || current.x < 0) {
                print("current continue")
                continue
            }
            print("current",current)
            
            // ④
            // 指定したオブジェクト種別と違うものが存在する場合
            if(workArray[current.y][current.x] == object[revType]) {
                print(current.x,current.y,"に",object[revType],"があります")
                
                // ⑤
                // 挟めるかチェック
                for var cnt = loop; 0 <= cnt; cnt-- {
                    // ⑥
                    // 移動後の座標
                    let next:(x:Int,y:Int) = (x: current.x + (searchTbl[idx0][idx1].x * cnt),y: (current.y + (searchTbl[idx0][idx1].y * cnt)))
                    // 範囲外の場合はコンテニュー
                    if(loop <= next.y || loop <= next.x || next.y < 0 || next.x < 0) {
                        print("next continue")
                        continue
                    }
                    print("next",next)

                    // ⑦
                    // 同じオブジェクト種別が存在するかチェック
                    if(workArray[next.y][next.x] == object[type]) {
                        print("!!true!!")
                        ret = true                      // 書き換えられた
                        pinch = true                    // はさみこまれた
                        workArray = oldArray            // 同じオブジェクトを二つ以上発見したらテーブルを元に戻す
                    }

                    // はさめる場合はひっくり返す
                    if(pinch == true) {
                        workArray[next.y][next.x] = object[type]
                    }
                }
            }
            // ⑧
            // はさみこみ判定を初期化
            pinch = false
        }
    }
    return ret
}

【Swift】 リバーシを作りましょう #1 初期化データの準備と説明

前回の記事はこちらから
aretoka-koretoka-soretoka.hatenablog.com

まずは、初期値として使用するデータを用意しておきます。

①文字列の配列を使用してリバーシの盤面を表現します。
 10x10で作成するため、10x10の2次元配列を用意します。

②オブジェクトももちろん文字列。
 それぞれ白(○)と黒(●)を用意しておきます。
 オブジェクトが区別できるように、列挙型の用意もお忘れなく。

③指定した座標から、周辺の座標を検索するためのオフセット座標を示すテーブルです。
 周辺8マスの座標を確認し、ひっくり返す条件に当てはまるかどうかを確認していきます。

// ①
let workArray:[[String]] = [
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," ","○","●"," "," "," "," "],
    [" "," "," "," ","●","○"," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
    [" "," "," "," "," "," "," "," "," "," "],
]

// ②
enum OBJTYPE:Int {
    case WHITE
    case BLACK
}

let object:[String] = ["○","●"]

// ③
// 周辺座標検索用のテーブル
let searchTbl:[[(x:Int,y:Int)]] = [
    [(x:-1,y:-1),(x: 0,y:-1),(x: 1,y:-1)],  // 左上、上、右上
    [(x:-1,y: 0),(x: 0,y: 0),(x: 1,y: 0)],  // 左 、中、右
    [(x:-1,y: 1),(x: 0,y: 1),(x: 1,y: 1)],  // 左下、下、右下
]

次回から、実際に処理に入っていきたいと思います。

【Swift】 リバーシを作りましょう #0 機能検討

最近趣味で iOS のアプリを開発し始めました。言語は Swift を使用しています。
お勉強がてらリバーシを作ってみます。

AIとかそういった難しいことは良く分からないので、
座標指定は手動で行い、指定した座標にオブジェクトを打つというシンプルなものです。

開発環境は、以下の通り。


仕様は以下の通り。基本ルールと同じハズ。

  • オブジェクトとして ● と ○ を使用する
  • ○ を ● ではさむとひっくりかえせる(○ → ● に変化)
  • ● を ○ ではさむとひっくりかえせる(● → ○ に変化)
  • 盤面は 10x10 で作成する
  • 既にオブジェクトが打たれている座標には打てない
  • 盤面の範囲外には打てない
  • 別種のオブジェクトをひっくり返せない座標には打てない


String型 の配列を使用した CUI で作っていきます。
文字列の内容に合わせてスプライトを表示するとそれっぽくなるかもしれませんね。