From 0ea4eec5dd2122c6704216971eb1249276297867 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Fri, 19 Jun 2026 18:20:26 -0400 Subject: shop fixes, 'toggle' completely removed, movement speed increased --- internal/game/hacking/hacking_mastermind.go | 177 ++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 internal/game/hacking/hacking_mastermind.go (limited to 'internal/game/hacking/hacking_mastermind.go') diff --git a/internal/game/hacking/hacking_mastermind.go b/internal/game/hacking/hacking_mastermind.go new file mode 100644 index 0000000..8d4eb1c --- /dev/null +++ b/internal/game/hacking/hacking_mastermind.go @@ -0,0 +1,177 @@ +package hacking + +import ( + "fmt" + "math/rand" + "strings" +) + +type MastermindGame struct { + code [4]int + guesses []MastermindGuess + maxGuess int + gameOver bool + won bool +} + +type MastermindGuess struct { + Digits [4]int + Exact int + Partial int +} + +func NewMastermindGame() *MastermindGame { + return &MastermindGame{ + maxGuess: 10, + } +} + +func (m *MastermindGame) Name() string { + return "Code Breaker" +} + +func (m *MastermindGame) Init(level int) string { + pool := []int{1, 2, 3, 4, 5, 6} + rand.Shuffle(len(pool), func(i, j int) { pool[i], pool[j] = pool[j], pool[i] }) + copy(m.code[:], pool[:4]) + m.guesses = nil + m.gameOver = false + m.won = false + + var sb strings.Builder + sb.WriteString("=== CODE BREAKER ===\n") + sb.WriteString("\n") + sb.WriteString("The encryption module is running a 4-digit cipher using symbols 1-6.\n") + sb.WriteString("No symbol repeats. You have 10 attempts to crack the code.\n") + sb.WriteString("\n") + sb.WriteString("After each guess, you'll see:\n") + sb.WriteString(" {40}[X]{/} = correct symbol in correct position\n") + sb.WriteString(" {226}[O]{/} = correct symbol in wrong position\n") + sb.WriteString(" [ ] = symbol not in code\n") + sb.WriteString("\n") + sb.WriteString("Commands:\n") + sb.WriteString(" <4 digits> - Guess the code (e.g., 1234)\n") + sb.WriteString(" status - Show previous guesses\n") + sb.WriteString(" jack out - Disconnect (forfeit)\n") + return sb.String() +} + +func (m *MastermindGame) HandleInput(input string) (string, bool, bool) { + input = strings.TrimSpace(input) + lower := strings.ToLower(strings.TrimSpace(input)) + + if lower == "status" { + return m.doStatus(), false, false + } + + if len(input) != 4 { + return "Enter exactly 4 digits (1-6, no repeats).", false, false + } + + var guess [4]int + seen := make(map[int]bool) + for i, ch := range input { + if ch < '1' || ch > '6' { + return "Each digit must be 1-6.", false, false + } + d := int(ch - '0') + if seen[d] { + return "No repeating digits allowed.", false, false + } + seen[d] = true + guess[i] = d + } + + exact := 0 + partial := 0 + for i := 0; i < 4; i++ { + if guess[i] == m.code[i] { + exact++ + } else { + for j := 0; j < 4; j++ { + if guess[i] == m.code[j] { + partial++ + break + } + } + } + } + + m.guesses = append(m.guesses, MastermindGuess{ + Digits: guess, + Exact: exact, + Partial: partial, + }) + + var sb strings.Builder + sb.WriteString(fmt.Sprintf("Attempt %d/%d: ", len(m.guesses), m.maxGuess)) + for i, d := range guess { + match := "[ ]" + if guess[i] == m.code[i] { + match = "{40}[X]{/}" + } else { + for j := 0; j < 4; j++ { + if guess[i] == m.code[j] { + match = "{226}[O]{/}" + break + } + } + } + sb.WriteString(fmt.Sprintf("%d%s ", d, match)) + } + sb.WriteString(fmt.Sprintf(" (%d locked, %d found)", exact, partial)) + + if exact == 4 { + m.gameOver = true + m.won = true + sb.WriteString("\n\nCode cracked! The encryption module yields.\nConnection terminated.") + return sb.String(), true, true + } + + if len(m.guesses) >= m.maxGuess { + m.gameOver = true + m.won = false + sb.WriteString(fmt.Sprintf("\n\nOut of attempts. The code was: %d %d %d %d.\nConnection terminated.", + m.code[0], m.code[1], m.code[2], m.code[3])) + return sb.String(), true, false + } + + return sb.String(), false, false +} + +func (m *MastermindGame) doStatus() string { + if len(m.guesses) == 0 { + return fmt.Sprintf("No guesses yet. Remaining: %d/%d", m.maxGuess, m.maxGuess) + } + var sb strings.Builder + sb.WriteString("=== Attempts ===\n") + for i, g := range m.guesses { + sb.WriteString(fmt.Sprintf(" %2d: %d %d %d %d -> ", i+1, g.Digits[0], g.Digits[1], g.Digits[2], g.Digits[3])) + for j, d := range g.Digits { + match := "[ ]" + if g.Digits[j] == m.code[j] { + match = "{40}[X]{/}" + } else { + found := false + for k := 0; k < 4; k++ { + if g.Digits[j] == m.code[k] { + found = true + break + } + } + if found { + match = "{226}[O]{/}" + } + } + _ = d + sb.WriteString(match) + } + sb.WriteString(fmt.Sprintf(" (%d locked, %d found)\n", g.Exact, g.Partial)) + } + sb.WriteString(fmt.Sprintf("Remaining: %d/%d\n", m.maxGuess-len(m.guesses), m.maxGuess)) + return sb.String() +} + +func (m *MastermindGame) BonusXP() int { + return (m.maxGuess - len(m.guesses)) * 15 +} -- cgit v1.2.3