Problem with showing the sudoku in the front-end written in swift ui

53 Views Asked by At

I made a simple sudoku game in swift for IOS the problem is that I made that the generated number will be bold so the user will see that he cant change them and that they are the generated number. To that I made a class that will hold the number and a boolean variable that will represent if the number is generated or set by the user. The problem is that it wont work now and the sudoku is neither generated to the user can put a number in the boxes. Here is code for the sudoku since they are at two different files.

import SwiftUI

// Enumeration that is used to display the result if checking a sudoku.
public enum ResultsOfCheckedSudoku {
    case notChecked
    case notFilled
    case correct
    case incorrect
}

// Class that is used to create a custom numbers for the UI.
class Number {
    // Variable that will hold the number.
    private var num: String
    // Variable that is used to determine if the number was generated.
    private var isGenerated: Bool
    
    // Simple initialiser.
    init(num: String, isGenerated: Bool) {
        self.num = num
        self.isGenerated = isGenerated
    }
    
    // Getters and setters.
    public func getNum() -> String {
        return num
    }
    
    public func setNum(num: String) {
        self.num = num
    }
    
    public func getIsGenerated() -> Bool {
        return isGenerated
    }
    
    public func setIsGenerated(isGenerated: Bool) -> Void {
        self.isGenerated = isGenerated
    }
}

struct ContentView: View {
    
    var sudoku = Sudoku()
    @State var numbers: [[Number]] = Array(repeating: Array(repeating: Number(num: "", isGenerated: true), count: 9), count: 9)
    @State var selectedNumber: String = ""
    @State var selectedDifficulty: Difficulties = .easy
    @State var resultOfCheckedSudoku: ResultsOfCheckedSudoku = .notChecked
    @State var checked: Bool = false
    
    var body: some View {
        GeometryReader { geo in
            VStack {
                RoundedRectangle(cornerRadius: 25.0)
                    .fill(Color.blue)
                    .frame(width: geo.size.width / 1.5, height: geo.size.height / 10)
                    .overlay(alignment: .center) {
                        Text("Sudoku")
                            .foregroundStyle(Color.white)
                            .font(.largeTitle)
                    }
                    .padding(.bottom)
                
                Grid(width: geo.size.width / 1.05,
                     numbers: $numbers,
                     selectedNumber: $selectedNumber)
                .padding(.bottom)
                
                HStack {
                    Button(action: {
                        onGenerateButtonClicked()
                    }, label: {
                        RoundedRectangle(cornerRadius: 25.0)
                            .fill(Color.blue)
                            .frame(width: geo.size.width / 3.5 , height: geo.size.height / 10)
                            .overlay(alignment: .center) {
                                Text("Start")
                                    .foregroundStyle(Color.white)
                                    .font(.title)
                            }
                    })
                    
                    Picker("Chose difficulty", selection: $selectedDifficulty) {
                        Text("Easy")
                            .tag(Difficulties.easy)
                        Text("Normal")
                            .tag(Difficulties.normal)
                        Text("Hard")
                            .tag(Difficulties.hard)
                        
                    }
                    .padding(.horizontal)
                    
                    Button(action: {
                        onCheckButtonClicked()
                    }, label: {
                        RoundedRectangle(cornerRadius: 25.0)
                            .fill(Color.blue)
                            .frame(width: geo.size.width / 3.5 , height: geo.size.height / 10)
                            .overlay(alignment: .center) {
                                Text("Check")
                                    .foregroundStyle(Color.white)
                                    .font(.title)
                            }
                        
                    })
                }
                .padding(.bottom)
                
                HStack(spacing: 20) {
                    ForEach(1..<10) { i in
                        if selectedNumber == String(i) {
                            Button(action: {
                                selectedNumber = String(i)
                            }, label: {
                                Text(String(i))
                                    .font(.largeTitle)
                                    .bold()
                                    .underline()
                            })
                        }
                        else {
                            Button(action: {
                                selectedNumber = String(i)
                            }, label: {
                                Text(String(i))
                                    .font(.largeTitle)
                            })
                        }
                    }
                }
                
                if resultOfCheckedSudoku == .correct {
                    Text("The sudoku is correct")
                        .foregroundStyle(Color.green)
                        .font(.largeTitle)
                }
                else if resultOfCheckedSudoku == .incorrect {
                    Text("The sudoku is incorrect")
                        .foregroundStyle(Color.red)
                        .font(.largeTitle)
                }
                else if resultOfCheckedSudoku == . notFilled {
                    Text("The sudoku is not filled")
                        .foregroundStyle(Color.red)
                        .font(.largeTitle)
                }
                
                Spacer()
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
    
    func onGenerateButtonClicked() -> Void {
        let grid: [[Int]] = sudoku.generateSudoku(difficulty: selectedDifficulty)
        for i in 0..<9 {
            for j in 0..<9 {
                if grid[i][j] != 0 {
                    numbers[i][j].setNum(num: String(grid[i][j]))
                    numbers[i][j].setIsGenerated(isGenerated: true)
                }
                else {
                    numbers[i][j].setNum(num: "")
                    numbers[i][j].setIsGenerated(isGenerated: false)
                }
            }
        }
        
        resultOfCheckedSudoku = .notChecked
    }
    
    func onCheckButtonClicked() -> Void {
        var grid: [[Int]] = Array(repeating: Array(repeating: 0, count: 9), count: 9)
        
        for i in 0..<9 {
            for j in 0..<9 {
                if let num = Int(numbers[i][j].getNum()) {
                    grid[i][j] = num
                }
                else {
                    resultOfCheckedSudoku = .notFilled
                    return
                }
            }
        }
        
        resultOfCheckedSudoku = Sudoku.checkSudoku(grid: grid)
    }
}

struct Grid: View {
    let width: CGFloat
    @Binding var numbers: [[Number]]
    @Binding var selectedNumber: String
    
    var body: some View {
        Rectangle()
            .fill(Color.clear)
            .frame(width: width)
            .aspectRatio(1, contentMode: .fit)
            .overlay(alignment: .top) {
                VStack(spacing: 0) {
                    ForEach(0..<3) { i in
                        HStack(spacing: 0) {
                            ForEach(0..<3) { j in
                                Box(width: width / 3,
                                    x: i,
                                    y: j,
                                    numbers: $numbers,
                                    selectedNumber: $selectedNumber)
                            }
                        }
                    }
                }
            }
    }
}

struct Box: View {
    let width: CGFloat
    let x: Int
    let y: Int
    @Binding var numbers: [[Number]]
    @Binding var selectedNumber: String
    
    var body: some View {
        Rectangle()
            .stroke(Color.black, lineWidth: 3)
            .frame(width: width)
            .aspectRatio(1, contentMode: .fit)
            .overlay(alignment: .top) {
                VStack(spacing: 0) {
                    ForEach(0..<3) {i in
                        HStack(spacing: 0) {
                            ForEach(0..<3) {j in
                                InnerBox(width: width / 3,
                                         x: x * 3 + i,
                                         y: y * 3 + j,
                                         numbers: $numbers,
                                         selectedNumber: $selectedNumber)
                            }
                        }
                    }
                }
            }
    }
}

struct InnerBox: View {
    let width: CGFloat
    let x: Int
    let y: Int
    @Binding var numbers: [[Number]]
    @Binding var selectedNumber: String
    
    var body: some View {
        if numbers[x][y].getIsGenerated() {
            Button(action: {
            }, label: {
                Rectangle()
                    .stroke(Color.black)
                    .frame(width: width)
                    .aspectRatio(1, contentMode: .fit)
                    .overlay(alignment: .center) {
                        Text(numbers[x][y].getNum())
                            .foregroundStyle(Color.black)
                            .bold()
                    }
            })
        }
        else {
            Button(action: {
                numbers[x][y].setNum(num: selectedNumber)
            }, label: {
                Rectangle()
                    .stroke(Color.black)
                    .frame(width: width)
                    .aspectRatio(1, contentMode: .fit)
                    .overlay(alignment: .center) {
                        Text(numbers[x][y].getNum())
                            .foregroundStyle(Color.black)
                    }
            })
        }
    }
}

#Preview {
    ContentView()
}

And here is the swift UI code.

import SwiftUI

// Enumeration that is used to display the result if checking a sudoku.
public enum ResultsOfCheckedSudoku {
    case notChecked
    case notFilled
    case correct
    case incorrect
}

// Class that is used to create a custom numbers for the UI.
class Number {
    // Variable that will hold the number.
    private var num: String
    // Variable that is used to determine if the number was generated.
    private var isGenerated: Bool
    
    // Simple initialiser.
    init(num: String, isGenerated: Bool) {
        self.num = num
        self.isGenerated = isGenerated
    }
    
    // Getters and setters.
    public func getNum() -> String {
        return num
    }
    
    public func setNum(num: String) {
        self.num = num
    }
    
    public func getIsGenerated() -> Bool {
        return isGenerated
    }
    
    public func setIsGenerated(isGenerated: Bool) -> Void {
        self.isGenerated = isGenerated
    }
}

struct ContentView: View {
    
    var sudoku = Sudoku()
    @State var numbers: [[Number]] = Array(repeating: Array(repeating: Number(num: "", isGenerated: true), count: 9), count: 9)
    @State var selectedNumber: String = ""
    @State var selectedDifficulty: Difficulties = .easy
    @State var resultOfCheckedSudoku: ResultsOfCheckedSudoku = .notChecked
    @State var checked: Bool = false
    
    var body: some View {
        GeometryReader { geo in
            VStack {
                RoundedRectangle(cornerRadius: 25.0)
                    .fill(Color.blue)
                    .frame(width: geo.size.width / 1.5, height: geo.size.height / 10)
                    .overlay(alignment: .center) {
                        Text("Sudoku")
                            .foregroundStyle(Color.white)
                            .font(.largeTitle)
                    }
                    .padding(.bottom)
                
                Grid(width: geo.size.width / 1.05,
                     numbers: $numbers,
                     selectedNumber: $selectedNumber)
                .padding(.bottom)
                
                HStack {
                    Button(action: {
                        onGenerateButtonClicked()
                    }, label: {
                        RoundedRectangle(cornerRadius: 25.0)
                            .fill(Color.blue)
                            .frame(width: geo.size.width / 3.5 , height: geo.size.height / 10)
                            .overlay(alignment: .center) {
                                Text("Start")
                                    .foregroundStyle(Color.white)
                                    .font(.title)
                            }
                    })
                    
                    Picker("Chose difficulty", selection: $selectedDifficulty) {
                        Text("Easy")
                            .tag(Difficulties.easy)
                        Text("Normal")
                            .tag(Difficulties.normal)
                        Text("Hard")
                            .tag(Difficulties.hard)
                        
                    }
                    .padding(.horizontal)
                    
                    Button(action: {
                        onCheckButtonClicked()
                    }, label: {
                        RoundedRectangle(cornerRadius: 25.0)
                            .fill(Color.blue)
                            .frame(width: geo.size.width / 3.5 , height: geo.size.height / 10)
                            .overlay(alignment: .center) {
                                Text("Check")
                                    .foregroundStyle(Color.white)
                                    .font(.title)
                            }
                        
                    })
                }
                .padding(.bottom)
                
                HStack(spacing: 20) {
                    ForEach(1..<10) { i in
                        if selectedNumber == String(i) {
                            Button(action: {
                                selectedNumber = String(i)
                            }, label: {
                                Text(String(i))
                                    .font(.largeTitle)
                                    .bold()
                                    .underline()
                            })
                        }
                        else {
                            Button(action: {
                                selectedNumber = String(i)
                            }, label: {
                                Text(String(i))
                                    .font(.largeTitle)
                            })
                        }
                    }
                }
                
                if resultOfCheckedSudoku == .correct {
                    Text("The sudoku is correct")
                        .foregroundStyle(Color.green)
                        .font(.largeTitle)
                }
                else if resultOfCheckedSudoku == .incorrect {
                    Text("The sudoku is incorrect")
                        .foregroundStyle(Color.red)
                        .font(.largeTitle)
                }
                else if resultOfCheckedSudoku == . notFilled {
                    Text("The sudoku is not filled")
                        .foregroundStyle(Color.red)
                        .font(.largeTitle)
                }
                
                Spacer()
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
    
    func onGenerateButtonClicked() -> Void {
        let grid: [[Int]] = sudoku.generateSudoku(difficulty: selectedDifficulty)
        for i in 0..<9 {
            for j in 0..<9 {
                if grid[i][j] != 0 {
                    numbers[i][j].setNum(num: String(grid[i][j]))
                    numbers[i][j].setIsGenerated(isGenerated: true)
                }
                else {
                    numbers[i][j].setNum(num: "")
                    numbers[i][j].setIsGenerated(isGenerated: false)
                }
            }
        }
        
        resultOfCheckedSudoku = .notChecked
    }
    
    func onCheckButtonClicked() -> Void {
        var grid: [[Int]] = Array(repeating: Array(repeating: 0, count: 9), count: 9)
        
        for i in 0..<9 {
            for j in 0..<9 {
                if let num = Int(numbers[i][j].getNum()) {
                    grid[i][j] = num
                }
                else {
                    resultOfCheckedSudoku = .notFilled
                    return
                }
            }
        }
        
        resultOfCheckedSudoku = Sudoku.checkSudoku(grid: grid)
    }
}

struct Grid: View {
    let width: CGFloat
    @Binding var numbers: [[Number]]
    @Binding var selectedNumber: String
    
    var body: some View {
        Rectangle()
            .fill(Color.clear)
            .frame(width: width)
            .aspectRatio(1, contentMode: .fit)
            .overlay(alignment: .top) {
                VStack(spacing: 0) {
                    ForEach(0..<3) { i in
                        HStack(spacing: 0) {
                            ForEach(0..<3) { j in
                                Box(width: width / 3,
                                    x: i,
                                    y: j,
                                    numbers: $numbers,
                                    selectedNumber: $selectedNumber)
                            }
                        }
                    }
                }
            }
    }
}

struct Box: View {
    let width: CGFloat
    let x: Int
    let y: Int
    @Binding var numbers: [[Number]]
    @Binding var selectedNumber: String
    
    var body: some View {
        Rectangle()
            .stroke(Color.black, lineWidth: 3)
            .frame(width: width)
            .aspectRatio(1, contentMode: .fit)
            .overlay(alignment: .top) {
                VStack(spacing: 0) {
                    ForEach(0..<3) {i in
                        HStack(spacing: 0) {
                            ForEach(0..<3) {j in
                                InnerBox(width: width / 3,
                                         x: x * 3 + i,
                                         y: y * 3 + j,
                                         numbers: $numbers,
                                         selectedNumber: $selectedNumber)
                            }
                        }
                    }
                }
            }
    }
}

struct InnerBox: View {
    let width: CGFloat
    let x: Int
    let y: Int
    @Binding var numbers: [[Number]]
    @Binding var selectedNumber: String
    
    var body: some View {
        if numbers[x][y].getIsGenerated() {
            Button(action: {
            }, label: {
                Rectangle()
                    .stroke(Color.black)
                    .frame(width: width)
                    .aspectRatio(1, contentMode: .fit)
                    .overlay(alignment: .center) {
                        Text(numbers[x][y].getNum())
                            .foregroundStyle(Color.black)
                            .bold()
                    }
            })
        }
        else {
            Button(action: {
                numbers[x][y].setNum(num: selectedNumber)
            }, label: {
                Rectangle()
                    .stroke(Color.black)
                    .frame(width: width)
                    .aspectRatio(1, contentMode: .fit)
                    .overlay(alignment: .center) {
                        Text(numbers[x][y].getNum())
                            .foregroundStyle(Color.black)
                    }
            })
        }
    }
}

#Preview {
    ContentView()
}

Thanks for the help in advance.

I tried to debug it using the build in Xcode debugger and print the values, but none of those work.

0

There are 0 best solutions below