見出し画像

[iPad Swift Playgrounds] Sudokuアプリ作成【Step1】9x9枠作成

iPad Swift PlaygroundsでSudokuのPlay Boardを作成します。
SwiftUIの使い方をWeb情報などで学習した結果を書きます。
プログラミングすることで同時にSudoku解法の理解を深めます。


【Step1】9x9枠作成

Sudokuお馴染みの9X9の枠をアプリ画面に作成します。
背景に黒い四角を置いて、その上にブロック(3x3)を重ねて配置すると
ブロックとブロックの隙間が太い区切り線になるという構想です。

下のキャプチャーはiPad Swift Playgroundsのコードとプレビューです。
各セルにボタンを配置していますのでタップすると反応します。ボタンActionの中身は次回で対応します。

iPad Swift Playgrounds コードとプレビュー

ContentView.swift全コード

ContentView.swiftのコード全体です。ContentView.swiftに保存してSwift Playgroundsに読み込んでください。

import SwiftUI

struct ContentView: View {
    @State private var data = Array(repeating: Array(repeating: 0, count: 9), count: 9)
    @State private var data_save = Array(repeating: Array(repeating: 0, count: 9), count: 9)

    var body: some View {
        let cellSize = CGFloat(40)
        let blockLineSize = CGFloat(3)
        let lineColor = Color.black
        VStack(spacing: 0) {
            Text("Sudoku")
                .font(.system(size: 30))
                .fontWeight(.bold)
            SudokuCells(cellSize: cellSize, blockLineSize: blockLineSize, lineColor: lineColor)
        }
    }

    @ViewBuilder
    func SudokuCells(cellSize: CGFloat, blockLineSize: CGFloat, lineColor: Color) -> some View{
        ZStack {
            let backgroundSize = CGFloat(cellSize * 9 + blockLineSize * 5) // 背景の大きさを計算
            RoundedRectangle(cornerRadius: 0)
                .fill(lineColor)
                .frame(width: backgroundSize, height: backgroundSize)
            VStack(spacing: blockLineSize) {
                ForEach(0..<3, id: \.self) { brow in
                    HStack(spacing: blockLineSize) {
                        ForEach(0..<3, id: \.self){ bcol in
                            VStack(spacing:0) {
                                ForEach(0..<3, id: \.self) { crow in
                                    HStack(spacing:0) {
                                        ForEach(0..<3, id: \.self) { ccol in
                                            let row = brow * 3 + crow
                                            let col = bcol  * 3 + ccol
                                            Button(action: {
                                                selectCell(row: row, col: col)
                                            }) {
                                                Text(getCellText(row: row, col: col))
                                                    .frame(width: cellSize, height: cellSize, alignment: .center)
                                                    .border(lineColor)
                                                    .foregroundColor(.black)
                                                    .background(getCellColor(row: row, col: col))
                                                    .font(.system(size: 35))
                                                    .fontWeight(data_save[row][col] == 0 ? .regular : .semibold) // 問題は太字で表示
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private func selectCell(row: Int, col: Int) {
        // Cellを選択したときのコードを書く予定
    }

    private func getCellText(row: Int, col: Int) -> String {
        // Cellに表示する文字を返す
        // 0 の時はスペースを返す
        var answer = " "
        if data[row][col] != 0 {
            answer = String(data[row][col])
        }
        return answer
    }

    private func getCellColor(row: Int, col: Int) -> Color {
        // Cellの色を返す 今後、色々な状態を色で区別する予定
        return Color.white
    }

}

プログラムコード説明

dataはSudokuのデータで2次元配列(9X9)です
0は数値を設定していない状態で、配列の初期値は全て0です
ルール違反無く0以外の数値が全て設定されればゲームは完了です

 @State private var data = Array(repeating: Array(repeating: 0, count: 9), count: 9)

data_saveはSudokuの問題を保存しておくメモリーです

@State private var data_save = Array(repeating: Array(repeating: 0, count: 9), count: 9)

data_saveのデータが0で無いときは問題のデータなので太字で表示します

.fontWeight(data_save[row][col] == 0 ? .regular : .semibold)

表示全体はVStackでSudokuのタイトルと9x9の枠を上下に配置しています。9x9枠はSudokuCells()にまとめて定義しています。

    var body: some View {
        let cellSize = CGFloat(40)
        let blockLineSize = CGFloat(3)
        let lineColor = Color.black
        VStack(spacing: 0) {
            Text("Sudoku")
                .font(.system(size: 30))
                .fontWeight(.bold)
            SudokuCells(cellSize: cellSize, blockLineSize: blockLineSize, lineColor: lineColor)
        }
    }

@ViewBuilderを用いて9x9枠をまとめて定義しました。
ZStackで四角形RoundedRectangle()の上に3x3ブロックを重ねて配置しています。

    @ViewBuilder
    func SudokuCells(cellSize: CGFloat, blockLineSize: CGFloat, lineColor: Color) -> some View{
        ZStack {      
            let backgroundSize = CGFloat(cellSize * 9 + blockLineSize * 5) // 背景の大きさを計算
            RoundedRectangle(cornerRadius: 0)
                .fill(lineColor)            
                .frame(width: backgroundSize, height: backgroundSize)
            VStack(spacing: blockLineSize) {
                ForEach(0..<3, id: \.self) { brow in
                    HStack(spacing: blockLineSize) { 
                        ForEach(0..<3, id: \.self){ bcol in                           
                            VStack(spacing:0) {
                                ForEach(0..<3, id: \.self) { crow in
                                    HStack(spacing:0) {
                                        ForEach(0..<3, id: \.self) { ccol in
                                            let row = brow * 3 + crow
                                            let col = bcol  * 3 + ccol
                                            Button(action: {
                                                selectCell(row: row, col: col)
                                            }) {
                                                Text(getCellText(row: row, col: col))
                                                    .frame(width: cellSize, height: cellSize, alignment: .center)
                                                    .border(lineColor)
                                                    .foregroundColor(.black)
                                                    .background(getCellColor(row: row, col: col))
                                                    .font(.system(size: 35))
                                                    .fontWeight(data_save[row][col] == 0 ? .regular : .semibold) // 問題は太字で表示
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

各関数はコード内のコメントを見てください。

    private func selectCell(row: Int, col: Int) {
        // Cellを選択したときのコードを書く予定
    }

    private func getCellText(row: Int, col: Int) -> String {
        // Cellに表示する文字を返す
        // 0 の時は空白(全角スペース)を返す
        var answer = " "
        if data[row][col] != 0 {
            answer = String(data[row][col])
        }
        return answer
    }

    private func getCellColor(row: Int, col: Int) -> Color {
        // Cellの色を返す 今後、色々な状態を色で区別する予定
        return Color.white
    }

次回予定

数値設定用ボタンを追加します。


いいなと思ったら応援しよう!