├── .vscode └── settings.json ├── Mastermind ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── Mastermind.png │ │ └── Contents.json │ ├── Pegs │ │ ├── Contents.json │ │ ├── Correct.colorset │ │ │ └── Contents.json │ │ ├── Misplaced.colorset │ │ │ └── Contents.json │ │ └── Unselected.colorset │ │ │ └── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── Background.colorset │ │ └── Contents.json │ └── Unselected.colorset │ │ └── Contents.json ├── Domain │ ├── FeedbackPeg.swift │ ├── RoundNumber.swift │ ├── Rounds.swift │ ├── SecretMaker.swift │ ├── Feedback.swift │ ├── Tests │ │ ├── GameTests.swift │ │ ├── CodeChoiceTests.swift │ │ ├── SecretTests.swift │ │ ├── SecretMakerTests.swift │ │ ├── RoundTests.swift │ │ └── FeedbackTests.swift │ ├── CodeChoice.swift │ ├── Round.swift │ ├── Game.swift │ └── Secret.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── UI │ ├── Tests │ │ ├── __Snapshots__ │ │ │ └── CheckButtonSnapshotTests │ │ │ │ ├── enabledColor.1.png │ │ │ │ └── disabledColor.1.png │ │ ├── FeedbackPeg+ColorTests.swift │ │ ├── InspectChangingView.swift │ │ ├── CheckButtonSnapshotTests.swift │ │ ├── RoundViewTests.swift │ │ ├── FeedbackViewTests.swift │ │ └── GameScreenTests.swift │ ├── TestableView.swift │ ├── FeedbackPeg+Color.swift │ ├── RoundView.swift │ ├── InspectableSheet.swift │ ├── CheckButton.swift │ ├── CodeGuessView.swift │ ├── FeedbackView.swift │ └── GameScreen.swift └── MastermindApp.swift ├── .windsurf ├── README.md ├── scripts │ └── commit.sh ├── processes │ ├── BashScripts.process.md │ ├── TDD.creating_tests.process.md │ ├── TDD.implement_production.process.md │ └── TDD.refactoring.process.md └── rules │ ├── no-comments-in-tests.md │ ├── agent.md │ ├── tdd-kent-beck.md │ └── commit-messages-arlo-belshee.md ├── Mastermind.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcshareddata │ └── xcschemes │ │ └── Mastermind.xcscheme └── project.pbxproj ├── MastermindTests.xctestplan ├── .github └── workflows │ └── build.yml ├── LICENSE.txt ├── .gitignore ├── README.md ├── XcodeWarnings.xcconfig └── CursorWroteTheseRules.mdc /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Mastermind/Domain/FeedbackPeg.swift: -------------------------------------------------------------------------------- 1 | enum FeedbackPeg { 2 | case empty 3 | case correct 4 | case misplaced 5 | } 6 | -------------------------------------------------------------------------------- /Mastermind/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/AppIcon.appiconset/Mastermind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonreid/Mastermind/HEAD/Mastermind/Assets.xcassets/AppIcon.appiconset/Mastermind.png -------------------------------------------------------------------------------- /.windsurf/README.md: -------------------------------------------------------------------------------- 1 | These files originate from this video: [Process files: Blueprints for Agentic AI - Llewellyn Falco | Craft 2025](https://www.youtube.com/watch?v=MMqahx1PRQo) 2 | -------------------------------------------------------------------------------- /Mastermind/UI/Tests/__Snapshots__/CheckButtonSnapshotTests/enabledColor.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonreid/Mastermind/HEAD/Mastermind/UI/Tests/__Snapshots__/CheckButtonSnapshotTests/enabledColor.1.png -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Pegs/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Mastermind/UI/Tests/__Snapshots__/CheckButtonSnapshotTests/disabledColor.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonreid/Mastermind/HEAD/Mastermind/UI/Tests/__Snapshots__/CheckButtonSnapshotTests/disabledColor.1.png -------------------------------------------------------------------------------- /Mastermind.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Mastermind/Domain/RoundNumber.swift: -------------------------------------------------------------------------------- 1 | struct RoundNumber { 2 | let value: Int 3 | 4 | init(value: Int) { 5 | assert(1 <= value) 6 | assert(value <= 10) 7 | self.value = value 8 | } 9 | 10 | var index: Int { 11 | value - 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Mastermind.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Mastermind.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.windsurf/scripts/commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Error: Commit message is required." 5 | echo "Usage: $0 \"\"" 6 | exit 1 7 | fi 8 | set -euo pipefail 9 | COMMIT_MESSAGE="$1" 10 | 11 | git add . 12 | git commit -m "$COMMIT_MESSAGE" 13 | git push 14 | echo "✅ Changes committed and pushed" 15 | exit 0 -------------------------------------------------------------------------------- /Mastermind/UI/TestableView.swift: -------------------------------------------------------------------------------- 1 | // TestableView by Jon Reid, https://qualitycoding.org 2 | // Copyright 2024 Jonathan M. Reid. https://github.com/jonreid/TestableView/blob/main/LICENSE.txt 3 | // SPDX-License-Identifier: MIT 4 | 5 | import SwiftUI 6 | 7 | @MainActor 8 | protocol ViewInspectorHook { 9 | var viewInspectorHook: ((Self) -> Void)? { get set } 10 | } 11 | 12 | typealias TestableView = View & ViewInspectorHook 13 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Pegs/Correct.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0", 9 | "green" : "0", 10 | "red" : "0" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Mastermind/MastermindApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct ProductionApp: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | if isProduction { 8 | GameScreen(game: try! Game(numberOfCodeChoices: 4, secretSize: 4, numberOfRounds: 10, SecretMaker())) 9 | } 10 | } 11 | } 12 | 13 | private var isProduction: Bool { 14 | NSClassFromString("XCTestCase") == nil 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Background.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "234", 9 | "green" : "231", 10 | "red" : "227" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Pegs/Misplaced.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "255", 9 | "green" : "255", 10 | "red" : "255" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Unselected.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "198", 9 | "green" : "195", 10 | "red" : "185" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Mastermind/Assets.xcassets/Pegs/Unselected.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "198", 9 | "green" : "195", 10 | "red" : "185" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Mastermind/Domain/Rounds.swift: -------------------------------------------------------------------------------- 1 | final class Rounds { 2 | private let rounds: [Round] 3 | 4 | init(secretSize: Int, numberOfRounds: Int) { 5 | self.rounds = (1...numberOfRounds).map { 6 | roundNumber in Round(secretSize: secretSize, roundNumber: RoundNumber(value: roundNumber)) 7 | } 8 | } 9 | 10 | var count: Int { rounds.count } 11 | 12 | func round(_ roundNumber: RoundNumber) -> Round { 13 | rounds[roundNumber.index] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Mastermind/UI/FeedbackPeg+Color.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | extension FeedbackPeg { 4 | func feedbackColor() -> Color { 5 | switch self { 6 | case .empty: 7 | return .Pegs.unselected 8 | case .correct: 9 | return .Pegs.correct 10 | case .misplaced: 11 | return .Pegs.misplaced 12 | } 13 | } 14 | 15 | func colorAroundPegToShowThatPegIsFilled() -> Color { 16 | if self == .empty { return Color.clear } 17 | return feedbackColor() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.windsurf/processes/BashScripts.process.md: -------------------------------------------------------------------------------- 1 | # Bash Script Style Process 2 | 3 | STARTER_CHARACTER =💻 4 | 5 | - Use `#!/usr/bin/env bash` as shebang. 6 | - Always use `set -euo pipefail` for safety and debugging. 7 | - Keep scripts minimal: no unnecessary comments or echoes. 8 | - Only do minimal input validation; print a usage message to stderr and exit if inputs are missing or invalid. 9 | - Do not check for installed commands if failure will be obvious on use. 10 | - Make script executable: `chmod +x