├── .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