Переглянути джерело

feat: complete basic game mechanics with tests

Alex White 7 місяців тому
батько
коміт
d8be0af0ee
3 змінених файлів з 247 додано та 10 видалено
  1. 67 10
      fallout.go
  2. 126 0
      fallout_test.go
  3. 54 0
      games.txt

+ 67 - 10
fallout.go

@@ -8,7 +8,8 @@ import (
 )
 
 type Game struct {
-	Words map[string]*Word
+	Words  map[string]*Word
+	Length int
 }
 
 type Word struct {
@@ -38,9 +39,28 @@ func main() {
 		os.Exit(1)
 	}
 
-	// get guess and Score from stdin
+	for i := 0; i < 3; i++ {
+		// get guess and Score from stdin
+		guess, score := getGuessAndScoreFromStdin()
+		fmt.Printf("Guess: %s, Score: %d\n", guess, score)
 
-	// remove Words that don't match guess and Score
+		game.FilterWords(guess, score)
+
+		err = game.printSortedScores()
+		if err != nil {
+			fmt.Printf("Error printing sorted scores: %s\n", err)
+			os.Exit(1)
+		}
+
+		if len(game.Words) == 1 {
+			for word, _ := range game.Words {
+				fmt.Printf("The word is: %s\n", word)
+				os.Exit(0)
+			}
+		}
+	}
+
+	// iterate through multiple turns
 
 }
 
@@ -50,6 +70,44 @@ func NewGame() *Game {
 	}
 }
 
+func (g Game) FilterWords(guess string, score int) {
+	for _, word := range g.Words {
+		if !word.MatchesGuess(guess, score) {
+			delete(g.Words, word.Word)
+		}
+	}
+}
+
+func (w Word) MatchesGuess(guess string, numMatchingChars int) bool {
+
+	score := 0
+
+	for idx, letter := range w.Word {
+		if string(letter) == string(guess[idx]) {
+			score++
+		}
+	}
+
+	return score == numMatchingChars
+}
+
+func getGuessAndScoreFromStdin() (string, int) {
+	reader := bufio.NewReader(os.Stdin)
+	fmt.Print("Enter Guess: ")
+	guess, _ := reader.ReadString('\n')
+	guess = guess[:len(guess)-1]
+
+	fmt.Print("Enter Score: ")
+	var score int
+	_, err := fmt.Scanf("%d", &score)
+	if err != nil {
+		fmt.Printf("Error reading score: %s\n", err)
+		os.Exit(1)
+	}
+
+	return guess, score
+}
+
 func (g Game) printSortedScores() error {
 
 	var sortedWordScores []string
@@ -63,7 +121,8 @@ func (g Game) printSortedScores() error {
 		return g.Words[sortedWordScores[i]].Score > g.Words[sortedWordScores[j]].Score
 	})
 
-	fmt.Print("\nWords sorted by Score:\n")
+	fmt.Println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
+	fmt.Print("Words sorted by Score:\n")
 	for _, word := range sortedWordScores {
 		fmt.Printf("%s: %d\n", word, g.Words[word].Score)
 	}
@@ -104,8 +163,6 @@ func (g Game) getWordsFromStdin() error {
 
 	fmt.Println("Enter Words, one per line. Enter a period to end input.")
 
-	wordLen := 0
-
 	for {
 		reader := bufio.NewReader(os.Stdin)
 		word, _ := reader.ReadString('\n')
@@ -115,11 +172,11 @@ func (g Game) getWordsFromStdin() error {
 			break
 		}
 
-		if wordLen == 0 {
-			wordLen = len(word)
+		if g.Length == 0 {
+			g.Length = len(word)
 		} else {
-			if len(word) != wordLen {
-				fmt.Printf("Error: All words must be the same length (%d), skipping: %s\n", wordLen, word)
+			if len(word) != g.Length {
+				fmt.Printf("Error: All words must be the same length (%d), skipping: %s\n", g.Length, word)
 				continue
 			}
 		}

+ 126 - 0
fallout_test.go

@@ -50,3 +50,129 @@ func Test_scoreWordsByCommonLetterLocations(t *testing.T) {
 		})
 	}
 }
+
+func TestWord_MatchesGuess(t *testing.T) {
+	type fields struct {
+		Word  string
+		Score int
+	}
+	type args struct {
+		guess            string
+		numMatchingChars int
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   bool
+	}{
+		{
+			name:   "no letters in common",
+			fields: fields{Word: "aaa"},
+			args:   args{guess: "bbb", numMatchingChars: 0},
+			want:   true,
+		},
+		{
+			name:   "one letter in common",
+			fields: fields{Word: "aaa"},
+			args:   args{guess: "abb", numMatchingChars: 1},
+			want:   true,
+		},
+		{
+			name:   "one letter in common where expecting 2",
+			fields: fields{Word: "aaa"},
+			args:   args{guess: "aba", numMatchingChars: 1},
+			want:   false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			w := Word{
+				Word:  tt.fields.Word,
+				Score: tt.fields.Score,
+			}
+			if got := w.MatchesGuess(tt.args.guess, tt.args.numMatchingChars); got != tt.want {
+				t.Errorf("MatchesGuess() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGame_FilterWords(t *testing.T) {
+	type fields struct {
+		Words  map[string]*Word
+		Length int
+	}
+	type args struct {
+		guess string
+		score int
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   map[string]*Word
+	}{
+		{
+			name: "no words filtered with score = 0",
+			fields: fields{
+				Words: map[string]*Word{
+					"aaa": {Word: "aaa"},
+					"bbb": {Word: "bbb"},
+				},
+			},
+			args: args{guess: "ccc", score: 0},
+			want: map[string]*Word{
+				"aaa": {Word: "aaa"},
+				"bbb": {Word: "bbb"},
+			},
+		},
+		{
+			name: "no words filtered with score = 1",
+			fields: fields{
+				Words: map[string]*Word{
+					"aac": {Word: "aac"},
+					"bbc": {Word: "bbc"},
+				},
+			},
+			args: args{guess: "ccc", score: 1},
+			want: map[string]*Word{
+				"aac": {Word: "aac"},
+				"bbc": {Word: "bbc"},
+			},
+		},
+		{
+			name: "some words filtered",
+			fields: fields{
+				Words: map[string]*Word{
+					"aac": {Word: "aac"},
+					"bbc": {Word: "bbc"},
+					"ccc": {Word: "ccc"},
+				},
+			},
+			args: args{guess: "ccc", score: 1},
+			want: map[string]*Word{
+				"aac": {Word: "aac"},
+				"bbc": {Word: "bbc"},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := Game{
+				Words:  tt.fields.Words,
+				Length: tt.fields.Length,
+			}
+			g.FilterWords(tt.args.guess, tt.args.score)
+			if len(g.Words) != len(tt.want) {
+				t.Errorf("Expected %d Words, got %d", len(tt.want), len(g.Words))
+			}
+			for word, _ := range tt.want {
+				if _, ok := g.Words[word]; !ok {
+					t.Errorf("Word %s was removed, expected it to remain", word)
+				}
+			}
+
+		})
+	}
+}

+ 54 - 0
games.txt

@@ -0,0 +1,54 @@
+winds
+rests
+bones
+tries
+hydes
+inner
+wakes
+sizes
+pulls
+brass
+howls
+lined
+lines *
+likes
+caves
+lives
+
+hazards
+hurting
+manages
+varying
+gabbing
+packing
+warring
+cantina
+caravan
+gangers
+falling
+waiting *
+screens
+happens
+largest
+lawless
+dangers
+variety
+
+
+mazes *
+cares
+nails
+caves
+walks
+wants
+rates
+notes
+wagon
+halls
+sadly
+gates
+favor
+hands
+range
+
+