-
Notifications
You must be signed in to change notification settings - Fork 1
/
animal.go
187 lines (160 loc) · 4.14 KB
/
animal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package animal
import (
"bufio"
_ "embed"
"encoding/json"
"fmt"
"io"
"strings"
)
const (
// AnswerYes is Yes
AnswerYes = "yes"
// AnswerNo is No
AnswerNo = "no"
)
// Question struct to map to the Yes and No responses
type Question struct {
Yes string // what question is next, if answer is yes
No string // what question is next, if answer is no
}
// StartingQuestion - This is the first Question
var StartingQuestion = "Does it have 4 legs?"
type game struct {
Running bool
Data map[string]Question
transcript strings.Builder
}
//go:embed data.json
var content []byte
// NewGame - Initializing a new game with Starting Data and Running State
func NewGame() (*game, error) {
var StartingData map[string]Question
err := json.Unmarshal(content, &StartingData)
if err != nil {
return nil, fmt.Errorf("Error during Unmarshal(): %s", err)
}
return &game{
Running: true,
Data: StartingData,
}, nil
}
// NextQuestion - Function to ask the Next Question
func (g game) NextQuestion(q string, r string) (string, error) {
question, ok := g.Data[q]
if !ok {
return "", fmt.Errorf("No such question: %q", q)
}
if r == AnswerYes {
return question.Yes, nil
}
return question.No, nil
}
// Play - This is the actual game Play function
func (g *game) Play(r io.Reader, w io.Writer) error {
question := StartingQuestion
var prev1, prev2 string
var err error
for g.Running {
g.Output(w, question+" ")
response, _ := g.GetUserYesOrNo(r, w)
prev2 = prev1
prev1 = question
question, err = g.NextQuestion(question, response)
if err != nil {
fmt.Fprintf(w, "Oh no, internal error! Not your fault!")
return err
}
switch question {
case "Win":
g.Output(w, "I successfully guessed your animal! Awesome!\n")
g.Running = false
case "Loss":
g.Output(w, "You stumped me! Well done!\n")
g.LearnNewAnimal(r, w, prev2)
g.Running = false
}
}
return nil
}
// Transcript function
func (g game) Transcript() string {
return g.transcript.String()
}
// Output function - will print to screen and also add to transcript
func (g *game) Output(w io.Writer, text string) {
fmt.Fprintf(w, text)
g.transcript.WriteString(text)
}
// LearnNewAnimal - Function to learn the question to add for new animal
func (g *game) LearnNewAnimal(r io.Reader, w io.Writer, pq string) {
var input string
g.Output(w, "Please tell me the animal you were thinking about: ")
scanner := bufio.NewScanner(r)
scanner.Scan()
input = scanner.Text()
g.transcript.WriteString(input + "\n")
g.Output(w, fmt.Sprintf("What would be a Yes/No question to distinguish %s from other animals: ", input))
scanner.Scan()
qDistinctive := scanner.Text()
g.transcript.WriteString(qDistinctive + "\n")
g.Output(w, fmt.Sprintf("What would be the answer to the question - \"%s\" for %s: ", qDistinctive, input))
scanner.Scan()
ans, _ := g.GetUserYesOrNo(strings.NewReader(scanner.Text()), w)
qNewAnimal := "Is it a " + input + "?"
qPrevious := g.Data[pq]
if ans == AnswerYes {
g.Data[qDistinctive] = Question{
Yes: qNewAnimal,
No: g.Data[pq].Yes,
}
qPrevious.Yes = qDistinctive
} else {
g.Data[qDistinctive] = Question{
No: qNewAnimal,
Yes: g.Data[pq].No,
}
qPrevious.No = qDistinctive
}
g.Data[pq] = qPrevious
g.Data[qNewAnimal] = Question{
Yes: "Win",
No: "Loss",
}
}
// Replay - function to replay the game
func (g *game) Replay(r io.Reader, w io.Writer) bool {
g.Output(w, "Would you like to play again (y/n)? ")
replay, _ := g.GetUserYesOrNo(r, w)
if replay == AnswerYes {
g.Running = true
return true
}
g.Output(w, "Thanks for playing!")
return false
}
// GetUserYesOrNo - function to map variations of yes/no responses
func (g *game) GetUserYesOrNo(r io.Reader, w io.Writer) (string, error) {
var input string
ans := true
var response string
for ans {
_, err := fmt.Fscanln(r, &input)
g.transcript.WriteString(input + "\n")
if err != nil {
return "", err
}
switch input {
case "yes", "y", "YES", "Yes":
response = AnswerYes
ans = false
case "no", "n", "NO", "No":
response = AnswerNo
ans = false
default:
ans = true
g.Output(w, "Please answer Yes or No (y/n)? ")
}
}
return response, nil
}