diff --git a/.gitignore b/.gitignore index fe3596e..e00a245 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ xcuserdata # Carthage/Checkouts Carthage/Build +Board Solver/.DS_Store diff --git a/Board Solver.xcodeproj/project.pbxproj b/Board Solver.xcodeproj/project.pbxproj index ad3193f..e742754 100644 --- a/Board Solver.xcodeproj/project.pbxproj +++ b/Board Solver.xcodeproj/project.pbxproj @@ -569,10 +569,10 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -605,10 +605,10 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; diff --git a/Board Solver/LaunchScreen.storyboard b/Board Solver/LaunchScreen.storyboard index a5fdfa4..99ae58b 100644 --- a/Board Solver/LaunchScreen.storyboard +++ b/Board Solver/LaunchScreen.storyboard @@ -1,10 +1,10 @@ - - + + - - + + @@ -13,33 +13,27 @@ - + - - - - - - - - + + + - + - + - - - - - + + + + diff --git a/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7 (1).png b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7 (1).png new file mode 100644 index 0000000..8c8f7a7 Binary files /dev/null and b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7 (1).png differ diff --git a/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7 (2).png b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7 (2).png new file mode 100644 index 0000000..068647a Binary files /dev/null and b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7 (2).png differ diff --git a/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7.png b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7.png new file mode 100644 index 0000000..e6fdc60 Binary files /dev/null and b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Asset 1 7.png differ diff --git a/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json new file mode 100644 index 0000000..75bc0a2 --- /dev/null +++ b/Board Solver/Preview Content/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Asset 1 7.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Asset 1 7 (1).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Asset 1 7 (2).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8 (1).png b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8 (1).png new file mode 100644 index 0000000..685ce64 Binary files /dev/null and b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8 (1).png differ diff --git a/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8 (2).png b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8 (2).png new file mode 100644 index 0000000..65d2f47 Binary files /dev/null and b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8 (2).png differ diff --git a/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8.png b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8.png new file mode 100644 index 0000000..5e62ca9 Binary files /dev/null and b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Asset 1 8.png differ diff --git a/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Contents.json b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Contents.json new file mode 100644 index 0000000..07061ba --- /dev/null +++ b/Board Solver/Preview Content/Assets.xcassets/MenuViewLogo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Asset 1 8.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Asset 1 8 (1).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Asset 1 8 (2).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Board Solver/Views/AboutView.swift b/Board Solver/Views/AboutView.swift index 49e45ba..84dd231 100644 --- a/Board Solver/Views/AboutView.swift +++ b/Board Solver/Views/AboutView.swift @@ -8,58 +8,85 @@ import SwiftUI struct AboutView: View { + + // Environment variable to handle view dismissal @Environment(\.dismiss) private var dismiss + @Environment(\.colorScheme) var colorScheme var body: some View { - ZStack { - //Background - Color.white.ignoresSafeArea(.all) + GeometryReader { geometry in + // Calculate scaling factors based on iPhone 13 Pro Max dimensions + let baseWidth: CGFloat = 428 + let baseHeight: CGFloat = 926 + let scaleFactor = min(geometry.size.width / baseWidth, geometry.size.height / baseHeight) - VStack { + ZStack { + // Set background color to white and ignore safe area + Color.white.ignoresSafeArea(.all) - HStack { - Button { - dismiss() - } label: { - Rectangle() - .fill(.gray) - .frame(width: 80, height: 40) - .cornerRadius(15) - .overlay(Group{ - Text("BACK") - .font(.custom("PatrickHandSC-Regular", size: 25)) - .foregroundStyle(.white) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 2.5) + VStack { + HStack { + // Back button to dismiss the view + Button { + dismiss() + } label: { + Rectangle() + .fill(.gray) + .frame(width: 80 * scaleFactor, height: 40 * scaleFactor) + .cornerRadius(15 * scaleFactor) + .overlay(Group { + Text("BACK") + .font(.custom("PatrickHandSC-Regular", size: 25 * scaleFactor)) + .foregroundStyle(.white) + RoundedRectangle(cornerRadius: 15 * scaleFactor) + .stroke(Color.black, lineWidth: 2.5 * scaleFactor) }) + } + .padding(.leading, 15 * scaleFactor) + .padding(.top, 63 * scaleFactor) + .padding(.bottom, 20 * scaleFactor) + + Spacer() } - .padding() - Spacer() - } - - Text("About The BOARD SOLVER Project") - .font(.custom("PatrickHandSC-Regular", size: 40)) - .foregroundColor(Color.black) - .multilineTextAlignment(.center) - .monospacedDigit() - ScrollView { - Text("Do you ever get stuck trying to decide on your next move in a board game? Board Solver Mobile (BSM), aims to be your assistant for strategic board games. Leveraging the power of computer vision, BSM analyzes game states through your iOS device's camera and suggests the next optimal move based on pre-trained algorithms.\n\tBSM currently supports the popular game of Connect4, with hopes to support more games in the future. For each game, BSM considers various factors like piece placement, potential threats, and strategic goals to recommend the move with the highest chance of success. The difficulty level of the solver currently only returns the best move, but we plan to make the diffculty of the opponent be adjustable, allowing you to test your skills against a range of challenges.\n\tThis project is a great tool for both casual and experienced board game players. Whether you're looking for a helping hand to improve your game or simply want to explore different strategic options, BSM can be your guide to becoming a board game champion!") - .font(.custom("PatrickHandSC-Regular", size: 20)) - .foregroundColor(Color.black) - .monospacedDigit() - }.padding() - - HStack{ - Image("github-mark") - .resizable() - .frame(width: 20, height: 20) - .scaledToFit() + // Title text for the About page + Text("About The BOARD SOLVER Project") + .font(.custom("PatrickHandSC-Regular", size: 40 * scaleFactor)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .multilineTextAlignment(.center) + .monospacedDigit() + .padding(.horizontal, 20 * scaleFactor) - Link("Visit our GitHub!", destination: URL(string: "https://github.com/henryrobbinss/BoardSolverMobile")!) + // Scrollable text containing the project description + ScrollView { + Text("Do you ever get stuck trying to decide on your next move in a board game? Board Solver Mobile (BSM), aims to be your assistant for strategic board games. Leveraging the power of computer vision, BSM analyzes game states through your iOS device's camera and suggests the next optimal move based on pre-trained algorithms.\n\tBSM currently supports the popular game of Connect4, with hopes to support more games in the future. For each game, BSM considers various factors like piece placement, potential threats, and strategic goals to recommend the move with the highest chance of success. The difficulty level of the solver currently only returns the best move, but we plan to make the difficulty of the opponent adjustable, allowing you to test your skills against a range of challenges.\n\tThis project is a great tool for both casual and experienced board game players. Whether you're looking for a helping hand to improve your game or simply want to explore different strategic options, BSM can be your guide to becoming a board game champion!") + .font(.custom("PatrickHandSC-Regular", size: 20 * scaleFactor)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .monospacedDigit() + .padding(.horizontal, 20 * scaleFactor) + } + .padding(.vertical, 20 * scaleFactor) + + // HStack containing the GitHub link + HStack { + Image("github-mark") + .resizable() + .frame(width: 20 * scaleFactor, height: 20 * scaleFactor) + .scaledToFit() + + Link("Visit our GitHub!", + destination: URL(string: "https://github.com/henryrobbinss/BoardSolverMobile")!) + .font(.custom("PatrickHandSC-Regular", size: 18 * scaleFactor)) + } + .padding(.bottom, 35 * scaleFactor) } + .background(colorScheme == .dark ? Color.black : Color.white) + // Center the VStack within the GeometryReader + .frame(width: geometry.size.width, height: geometry.size.height) + .position(x: geometry.size.width / 2, y: geometry.size.height / 2) } } + .ignoresSafeArea() } } diff --git a/Board Solver/Views/BoardSolverMobile (1).fig b/Board Solver/Views/BoardSolverMobile (1).fig new file mode 100644 index 0000000..1d1bd54 Binary files /dev/null and b/Board Solver/Views/BoardSolverMobile (1).fig differ diff --git a/Board Solver/Views/FourInARowMenuView.swift b/Board Solver/Views/FourInARowMenuView.swift index fbf9504..efb348b 100644 --- a/Board Solver/Views/FourInARowMenuView.swift +++ b/Board Solver/Views/FourInARowMenuView.swift @@ -4,108 +4,119 @@ // // Created by Alex Mattoni on 7/12/24. // - import SwiftUI -struct FourInARowMenuView: View -{ +struct FourInARowMenuView: View { + @Environment(\.colorScheme) var colorScheme @Environment(\.dismiss) private var dismiss + @State var yellow: Int = 1 @State var red: Int = 0 @State var game = "four" @State var letters: String = "" + // Disable animation transitions - init() - { + init() { UINavigationBar.setAnimationsEnabled(false) } - var body: some View - { - NavigationView - { - // Navigation links - ZStack - { - // Background - Color.white.ignoresSafeArea(.all) - - - VStack { + var body: some View { + NavigationStack { + GeometryReader { geometry in + // Calculate scaling factors based on iPhone 13 Pro Max dimensions + let baseWidth: CGFloat = 428 + let baseHeight: CGFloat = 926 + let scaleFactor = min(geometry.size.width / baseWidth, geometry.size.height / baseHeight) + + ZStack { + // Set the background color to white and ignore safe area edges + Color.white.ignoresSafeArea(.all) - HStack { - Button { - dismiss() - } label: { - Rectangle() - .fill(.gray) - .frame(width: 80, height: 40) - .cornerRadius(15) - .overlay(Group{ - Text("BACK") - .font(.custom("PatrickHandSC-Regular", size: 25)) - .foregroundStyle(.white) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 2.5) + VStack { + // Back button + HStack { + Button { + dismiss() + } label: { + Rectangle() + .fill(.gray) + .frame(width: 80 * scaleFactor, height: 40 * scaleFactor) + .cornerRadius(15 * scaleFactor) + .overlay(Group { + Text("BACK") + .font(.custom("PatrickHandSC-Regular", size: 25 * scaleFactor)) + .foregroundStyle(.white) + RoundedRectangle(cornerRadius: 15 * scaleFactor) + .stroke(Color.black, lineWidth: 2.5 * scaleFactor) }) + } + .padding(.leading, 15 * scaleFactor) + .padding(.top, 63 * scaleFactor) + + Spacer() } - .padding() Spacer() - } - - Spacer() - - Text("Please Select Which\nColor Went First") - .font(.custom("PatrickHandSC-Regular", size: 40)) - .foregroundColor(.black) - .multilineTextAlignment(.center) - - HStack - { - NavigationLink - { - BufferView(playerColor: $yellow, g: $game, letters: $letters) - .navigationBarTitle("") - .navigationBarHidden(true) - } label: { - Rectangle() - .fill(.yellow) - .frame(width: 150, height: 75) - .cornerRadius(15) - .overlay(Group{ - Text("YELLOW") - .font(.custom("PatrickHandSC-Regular", size: 40)) - .foregroundStyle(.white) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 5) - }) - } - NavigationLink - { - BufferView(playerColor: $red, g: $game, letters: $letters) - .navigationBarTitle("") - .navigationBarHidden(true) - } label: - { - Rectangle() - .fill(.red) - .frame(width: 150, height: 75) - .cornerRadius(15) - .overlay(Group{ - Text("RED") - .font(.custom("PatrickHandSC-Regular", size: 40)) - .foregroundStyle(.white) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 5) + // Title text + Text("Please Select Which\nColor Went First") + .font(.custom("PatrickHandSC-Regular", size: 40 * scaleFactor)) + .foregroundColor(colorScheme == .dark ? .white : .black) + .multilineTextAlignment(.center) + .padding(.bottom, 50 * scaleFactor) + + // Buttons for selecting the first player color + HStack(spacing: 20 * scaleFactor) { + // Yellow button + NavigationLink { + BufferView(playerColor: $yellow, g: $game, letters: $letters) + .navigationBarTitle("") + .navigationBarHidden(true) + } label: { + Rectangle() + .fill(.yellow) + .frame(width: 150 * scaleFactor, height: 75 * scaleFactor) + .cornerRadius(15 * scaleFactor) + .overlay(Group { + Text("YELLOW") + .font(.custom("PatrickHandSC-Regular", size: 40 * scaleFactor)) + .foregroundStyle(.white) + RoundedRectangle(cornerRadius: 15 * scaleFactor) + .stroke(Color.black, lineWidth: 5 * scaleFactor) + }) + } + + // Red button + NavigationLink { + BufferView(playerColor: $red, g: $game, letters: $letters) + .navigationBarTitle("") + .navigationBarHidden(true) + } label: { + Rectangle() + .fill(.red) + .frame(width: 150 * scaleFactor, height: 75 * scaleFactor) + .cornerRadius(15 * scaleFactor) + .overlay(Group { + Text("RED") + .font(.custom("PatrickHandSC-Regular", size: 40 * scaleFactor)) + .foregroundStyle(.white) + RoundedRectangle(cornerRadius: 15 * scaleFactor) + .stroke(Color.black, lineWidth: 5 * scaleFactor) }) + } } + + Spacer() } - Spacer() + // Center the VStack within the GeometryReader + .frame(width: geometry.size.width, height: geometry.size.height) + .position(x: geometry.size.width / 2, y: geometry.size.height / 2) + .background(colorScheme == .dark ? Color.black : Color.white) + } } - }.navigationViewStyle(StackNavigationViewStyle()) + .ignoresSafeArea() + } } } diff --git a/Board Solver/Views/ScrambleBoardView.swift b/Board Solver/Views/ScrambleBoardView.swift index 5d31f32..8ca318d 100644 --- a/Board Solver/Views/ScrambleBoardView.swift +++ b/Board Solver/Views/ScrambleBoardView.swift @@ -120,6 +120,6 @@ struct LShape: View { } #Preview { - @Previewable @State var tempBoard: [[Character]] = Array(repeating: Array(repeating: Character("*"), count: 15), count: 15) - ScrambleBoardView(board: $tempBoard) + ScrambleBoardView(board: .constant(Array(repeating: Array(repeating: Character("*"), count: 15), count: 15))) } + diff --git "a/Board Solver/Views/Screenshot 2024-11-19 at 11.13.09\342\200\257PM.png" "b/Board Solver/Views/Screenshot 2024-11-19 at 11.13.09\342\200\257PM.png" new file mode 100644 index 0000000..b196779 Binary files /dev/null and "b/Board Solver/Views/Screenshot 2024-11-19 at 11.13.09\342\200\257PM.png" differ diff --git a/Board Solver/Views/SolverView.swift b/Board Solver/Views/SolverView.swift index f99dc95..ab8afd7 100644 --- a/Board Solver/Views/SolverView.swift +++ b/Board Solver/Views/SolverView.swift @@ -1,10 +1,3 @@ -// -// ContentView.swift -// Board Solver -// -// Created by Henry Robbins on 6/4/24. -// - import SwiftUI import CoreML import Vision @@ -12,8 +5,8 @@ import RealityKit import ARKit import UIKit -struct SolverView: View -{ +struct SolverView: View { + // Existing properties remain unchanged @ObservedObject var FClassifier: ImageClassifier @Environment(\.dismiss) private var dismiss @State private var arView = ARView(frame: .zero) @@ -30,170 +23,172 @@ struct SolverView: View @Binding var letters: String @State private var alreadyWon = false - var body: some View - { - ZStack - { - ARViewContainer(arView: $arView) - .edgesIgnoringSafeArea(.all) + var body: some View { + GeometryReader { geometry in + // Base sizes as per iPhone 13 Pro Max + let baseWidth: CGFloat = 428 + let baseHeight: CGFloat = 926 - if game == "scramble" { - ScrambleBoardView(board: $SBoard) - } + // Calculate scaling factors + let widthScalingFactor = geometry.size.width / baseWidth + let heightScalingFactor = geometry.size.height / baseHeight + let scalingFactor = min(widthScalingFactor, heightScalingFactor) - VStack - { - Spacer() + ZStack { + ARViewContainer(arView: $arView) + .edgesIgnoringSafeArea(.all) - if game == "four" { - FBoardView - .padding(.bottom, 20) - } else if game == "scramble" { - // ScrambleBoardView() + if game == "scramble" { + ScrambleBoardView(board: $SBoard) } - - HStack{ - Button - { - if game == "four" { - DispatchQueue.global().async - { - isScanning = true - withAnimation(){ - canSolve = true - captureFrame() - if let image = capturedImage - { - FResultsBoard = FClassifier.detect(uiImage: rotateImage90DegreesClockwise(image: image)!, playerColor: playerColor) - $FBoardView.wrappedValue.updateBoard(brd: FResultsBoard) - FBoardView.board = FResultsBoard + VStack { + Spacer() + + if game == "four" { + FBoardView + .padding(.bottom, 20 * scalingFactor) + } + + HStack(spacing: 20 * scalingFactor) { + // Scan Button + Button { + // Existing scan logic + if game == "four" { + DispatchQueue.global().async { + isScanning = true + withAnimation() { + canSolve = true + captureFrame() + if let image = capturedImage { + FResultsBoard = FClassifier.detect(uiImage: rotateImage90DegreesClockwise(image: image)!, playerColor: playerColor) + $FBoardView.wrappedValue.updateBoard(brd: FResultsBoard) + FBoardView.board = FResultsBoard + } } + isScanning = false } - isScanning = false - } - } else if game == "scramble" { - DispatchQueue.global().async - { - isScanning = true - withAnimation(){ - canSolve = true - captureFrame() - if let image = capturedImage - { - print(image)// Board stuff here + } else if game == "scramble" { + // Existing scramble logic + DispatchQueue.global().async { + isScanning = true + withAnimation() { + canSolve = true + captureFrame() + if let image = capturedImage { + print(image) + } } + isScanning = false } - isScanning = false + SBoard[7][7] = "F" + SBoard[7][8] = "O" + SBoard[7][9] = "C" + SBoard[7][10] = "U" + SBoard[7][11] = "S" + // Add extra padding only for scramble game + } - SBoard[7][7] = "F" - SBoard[7][8] = "O" - SBoard[7][9] = "C" - SBoard[7][10] = "U" - SBoard[7][11] = "S" - + } label: { + Rectangle() + .fill(.orange) + .frame(width: 180 * scalingFactor, height: 75 * scalingFactor) + .cornerRadius(15 * scalingFactor) + .overlay(Group { + Text("SCAN") + .font(.custom("PatrickHandSC-Regular", size: 50 * scalingFactor)) + .foregroundStyle(.black) + RoundedRectangle(cornerRadius: 15 * scalingFactor) + .stroke(Color.black, lineWidth: 5 * scalingFactor) + }) } + .frame(maxWidth: 180 * scalingFactor) - } label: { - Rectangle() - .fill(.orange) - .frame(width: 180, height: 75) - .cornerRadius(15) - .overlay(Group{ - Text("SCAN") - .font(.custom("PatrickHandSC-Regular", size: 50)) - .foregroundStyle(.black) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 5) - }) - } - .frame(maxWidth: 180) - - - Button - { - if game == "four" { - DispatchQueue.global().async - { - isSolving = true - withAnimation(){ - FResultsBoard = Board.startSolving(board: FBoard, playerColor: playerColor) - if(FResultsBoard == FBoardView.board){ - alreadyWon = true - } else { - $FBoardView.wrappedValue.updateBoard(brd: FResultsBoard) - FBoardView.board = FResultsBoard + // Solve Button + Button { + // Existing solve logic + if game == "four" { + DispatchQueue.global().async { + isSolving = true + withAnimation() { + FResultsBoard = Board.startSolving(board: FBoard, playerColor: playerColor) + if(FResultsBoard == FBoardView.board) { + alreadyWon = true + } else { + $FBoardView.wrappedValue.updateBoard(brd: FResultsBoard) + FBoardView.board = FResultsBoard + } } + isSolving = false } - isSolving = false + } else if game == "scramble" { + print("solving for scramble") } - } else if game == "scramble" { - print("solving for scramble") + } label: { + Rectangle() + .fill(.green) + .frame(width: 180 * scalingFactor, height: 75 * scalingFactor) + .cornerRadius(15 * scalingFactor) + .overlay(Group { + Text("SOLVE") + .font(.custom("PatrickHandSC-Regular", size: 50 * scalingFactor)) + .foregroundStyle(.black) + RoundedRectangle(cornerRadius: 15 * scalingFactor) + .stroke(Color.black, lineWidth: 5 * scalingFactor) + }) } + .frame(maxWidth: 180 * scalingFactor) + .disabled(!canSolve) + } + .padding(10 * scalingFactor) + .alert("Solving Error", isPresented: $alreadyWon) { + Button("OK", role: .cancel) { + alreadyWon = false + } + } message: { + Text("This Board is Already Solved!") + } + + // Back Button + Button { + dismiss() } label: { Rectangle() - .fill(.green) - .frame(width: 180, height: 75) - .cornerRadius(15) - .overlay(Group{ - Text("SOLVE") - .font(.custom("PatrickHandSC-Regular", size: 50)) - .foregroundStyle(.black) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 5) - }) + .fill(.gray) + .frame(width: 100 * scalingFactor, height: 60 * scalingFactor) + .cornerRadius(15 * scalingFactor) + .overlay(Group { + Text("BACK") + .font(.custom("PatrickHandSC-Regular", size: 30 * scalingFactor)) + .foregroundStyle(.white) + RoundedRectangle(cornerRadius: 15 * scalingFactor) + .stroke(Color.black, lineWidth: 5 * scalingFactor) + }) } - .frame(maxWidth: 180) - .disabled(!canSolve) + .frame(minWidth: 200 * scalingFactor) } - .padding() - .alert("Solving Error", isPresented: $alreadyWon) { - Button("OK", role: .cancel) { - alreadyWon = false - } - } message: { - Text("This Board is Already Solved!") - } + .padding(.bottom, geometry.size.height < 830 && game == "scramble" ? 0 :50 * scalingFactor) + + // Progress Views + ProgressView("Scanning") + .progressViewStyle(CircularProgressViewStyle()) + .background(.white) + .foregroundColor(.black) + .opacity(isScanning ? 0.9 : 0) + .frame(width: 150 * scalingFactor, height: 150 * scalingFactor) - Button { - dismiss() - } label: { - Rectangle() - .fill(.gray) - .frame(width: 100, height: 60) - .cornerRadius(15) - .overlay(Group{ - Text("BACK") - .font(.custom("PatrickHandSC-Regular", size: 30)) - .foregroundStyle(.white) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 5) - }) - } - .frame(minWidth: 200) + ProgressView("Solving") + .progressViewStyle(CircularProgressViewStyle()) + .background(.white) + .foregroundColor(.black) + .opacity(isSolving ? 0.9 : 0) + .frame(width: 150 * scalingFactor, height: 150 * scalingFactor) } - .padding(.bottom, 50) - - ProgressView("Scanning") - .progressViewStyle(CircularProgressViewStyle()) - .background(.white) - .foregroundColor(.black) - .opacity(isScanning ? 0.9 : 0) - .frame(width: 150, height: 150) - - ProgressView("Solving") - .progressViewStyle(CircularProgressViewStyle()) - .background(.white) - .foregroundColor(.black) - .opacity(isSolving ? 0.9 : 0) - .frame(width: 150, height: 150) - } .ignoresSafeArea(.all) } - private func captureFrame() - { + private func captureFrame() { let frame = arView.session.currentFrame let ciImage = CIImage(cvPixelBuffer: frame!.capturedImage) let context = CIContext() @@ -203,8 +198,8 @@ struct SolverView: View } } -struct ARViewContainer: UIViewRepresentable -{ +// ARViewContainer struct +struct ARViewContainer: UIViewRepresentable { @Binding var arView: ARView func makeUIView(context: Context) -> ARView { @@ -217,6 +212,7 @@ struct ARViewContainer: UIViewRepresentable func updateUIView(_ uiView: ARView, context: Context) {} } +// Image rotation helper function func rotateImage90DegreesClockwise(image: UIImage) -> UIImage? { guard let cgImage = image.cgImage else { return nil } diff --git a/Board Solver/Views/WordScrambleMenuView.swift b/Board Solver/Views/WordScrambleMenuView.swift index e033e0d..d3c98c3 100644 --- a/Board Solver/Views/WordScrambleMenuView.swift +++ b/Board Solver/Views/WordScrambleMenuView.swift @@ -7,131 +7,152 @@ import SwiftUI +// View for the Word Scramble menu struct WordScrambleMenuView: View { + // Environment variable to dismiss the view @Environment(\.dismiss) private var dismiss + @Environment(\.colorScheme) var colorScheme @State var pc = -1 @State var game = "scramble" + // State variable to hold the user's letter input @State private var letters: String = "" + // Maximum number of letters allowed let maxLetters = 7 var body: some View { - NavigationView { - - ZStack { - //Background - Color.white.ignoresSafeArea(.all) + NavigationStack { + GeometryReader { geometry in + // Calculate scaling factors based on iPhone 13 Pro Max dimensions + let baseWidth: CGFloat = 428 + let baseHeight: CGFloat = 926 + let scaleFactor = min(geometry.size.width / baseWidth, geometry.size.height / baseHeight) - VStack { - // Back button and title - HStack { - Button { - dismiss() - } label: { - Rectangle() - .fill(.gray) - .frame(width: 80, height: 40) - .cornerRadius(15) - .overlay(Group{ - Text("BACK") - .font(.custom("PatrickHandSC-Regular", size: 25)) - .foregroundStyle(.white) - RoundedRectangle(cornerRadius: 15) - .stroke(Color.black, lineWidth: 2.5) + ZStack { + // Background color + Color.white.ignoresSafeArea(.all) + + VStack { + // Back button + HStack { + Button { + dismiss() + } label: { + Rectangle() + .fill(.gray) + .frame(width: 80 * scaleFactor, height: 40 * scaleFactor) + .cornerRadius(15 * scaleFactor) + .overlay(Group { + Text("BACK") + .font(.custom("PatrickHandSC-Regular", size: 25 * scaleFactor)) + .foregroundStyle(.white) + RoundedRectangle(cornerRadius: 15 * scaleFactor) + .stroke(Color.black, lineWidth: 2.5 * scaleFactor) }) + } + .padding(.leading, 15 * scaleFactor) + .padding(.top, 63 * scaleFactor) + .padding(.bottom, 20 * scaleFactor) + + Spacer() } - .padding() Spacer() - } - - Spacer() - - // Main prompt text - Text("please type in your letters") - .font(.custom("PatrickHandSC-Regular", size: 30)) - .padding(.bottom, 5) - .foregroundColor(.black) - - Text("(type in a '?' for blanks)") - .font(.custom("PatrickHandSC-Regular", size: 15)) - .foregroundColor(.gray) - .padding(.bottom, 50) - - // Letter input display (interactive text boxes) - HStack(spacing: 10) { - ForEach(0..