Skip to content

Instantly share code, notes, and snippets.

@kpmcc
Created April 5, 2022 22:15
Show Gist options
  • Save kpmcc/537e4f052131b02387b6285af7c02a24 to your computer and use it in GitHub Desktop.
Save kpmcc/537e4f052131b02387b6285af7c02a24 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"errors"
"fmt"
"math/rand"
"os"
"strings"
)
func readGuess(r *bufio.Reader, expectedLen int) []string {
input, err := r.ReadString('\n')
if err != nil {
fmt.Println("An eror occured while reading input. Please try again", err)
}
// remove the delimiter from the input string
trimmed := strings.TrimSuffix(input, "\n")
split := strings.SplitN(trimmed, "", expectedLen)
return split
}
func validateGuessLen(guess []string, expectedLen int) bool {
if len(guess) < expectedLen {
fmt.Fprintf(os.Stderr, "Error: Not enough colors in guess\n")
return false
}
lastElementIndex := expectedLen - 1
if len(guess[lastElementIndex]) != 1 {
fmt.Fprintf(os.Stderr, "Error: Too many colors in guess\n")
return false
}
return true
}
func getColorIndices(colors []string) map[string][]int {
colorIndices := make(map[string][]int)
for i := 0; i < len(colors); i++ {
c := colors[i]
colorIndices[c] = append(colorIndices[c], i)
}
return colorIndices
}
func remove(s []int, i int) []int {
// Remove the element at index i by replacing it with the last element
// in the slice, and then dropping the last element from the slice
// !! This does not preserve order of elements
s[i] = s[len(s)-1]
return s[:len(s)-1]
}
func in(s []int, e int) bool {
for i := 0; i < len(s); i++ {
v := s[i]
if e == v {
return true
}
}
return false
}
func checkGuess(guess []string, validColors map[string]bool, actual []string) (pins []string, correct bool, err error) {
var responsePins []string
for i := 0; i < len(guess); i++ {
c := guess[i]
if !validColors[c] {
return responsePins, false, errors.New("Received invalid color in guess: " + c + "\n")
}
}
if len(guess) != len(actual) {
return responsePins, false, errors.New("Mismatched lengths betwwen guess and actual\n")
}
unmatchedActual := make(map[string]int)
var unmatchedGuessIndices []int
for i := 0; i < len(guess); i++ {
gc := guess[i]
ac := actual[i]
if gc == ac {
responsePins = append(responsePins, "K")
} else {
unmatchedActual[ac]++
unmatchedGuessIndices = append(unmatchedGuessIndices, i)
}
}
if len(unmatchedGuessIndices) == 0 {
return responsePins, true, nil
} else {
for gi := 0; gi < len(unmatchedGuessIndices); gi++ {
ugi := unmatchedGuessIndices[gi]
gc := guess[ugi]
n, exists := unmatchedActual[gc]
if exists && n > 0 {
responsePins = append(responsePins, "W")
unmatchedActual[gc]--
}
}
return responsePins, false, nil
}
}
func main() {
// Setup
fmt.Println("---MASTERMIND---")
const guessLen = 4
const numGuesses = 10
validColors := []string{"R", "G", "B", "P", "O", "Y"}
validColorsMap := make(map[string]bool)
fmt.Print("Valid colors: ")
for _, c := range validColors {
validColorsMap[c] = true
fmt.Printf("%s ", c)
}
fmt.Println()
// Generate actual color list
var actual []string
for i := 0; i < guessLen; i++ {
colorIndex := rand.Int() % len(validColors)
actual = append(actual, validColors[colorIndex])
}
fmt.Println("Guesses should be entered without spaces (be nice)")
fmt.Println("Example: RBGO")
fmt.Println()
fmt.Println("After each guess, pins will be shown for the guess")
fmt.Println("Black pins ('K') indicate a correct color in the correct location")
fmt.Println("White pins ('W') indicate a correct color not in the correct location")
fmt.Println("Example: [K W W] - Indicates one correct color and position, and two correct colors in the wrong positions")
fmt.Println()
reader := bufio.NewReader(os.Stdin)
for gn := 0; gn < numGuesses; gn++ {
fmt.Printf("%d tries remaining. Please enter your guess: ", numGuesses-gn)
guess := readGuess(reader, guessLen)
if validateGuessLen(guess, guessLen) {
pins, correct, err := checkGuess(guess, validColorsMap, actual)
if err != nil {
fmt.Println("Error during guess processing")
fmt.Print(err)
}
if correct {
fmt.Printf("CORRECT! ")
break
} else {
fmt.Printf("You Guessed: %v - Response is: %v\n\n", guess, pins)
}
}
}
fmt.Printf("The answer is %v\n", actual)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment