refacotr picking unused word out of AssignmentRotation body

main
Bel LaPointe 2024-12-15 09:23:45 -07:00
parent 8d9815ee90
commit c18f154328
2 changed files with 88 additions and 61 deletions

View File

@ -161,8 +161,9 @@ type (
Killer string Killer string
Victim string Victim string
KillWord KillWord KillWord KillWord
KillWords map[string]KillWords AllKillWords AllKillWords
} }
AllKillWords map[string]KillWords
) )
const ( const (
@ -286,7 +287,7 @@ func (games Games) GameState(ctx context.Context, id string) (GameState, error)
result.Players[k] = v result.Players[k] = v
} }
for k, v := range assignmentRotation.KillWords { for k, v := range assignmentRotation.AllKillWords {
player := result.Players[k] player := result.Players[k]
player.KillWords = v player.KillWords = v
result.Players[k] = player result.Players[k] = player
@ -350,9 +351,6 @@ func (games Games) CreateEventPlayerLeave(ctx context.Context, id string, player
return games.createEvent(ctx, id, EventPlayerLeave{Type: PlayerLeave, ID: player}) return games.createEvent(ctx, id, EventPlayerLeave{Type: PlayerLeave, ID: player})
} }
//go:embed holiday.txt
var wordsHoliday string
func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string, killer, victim, word string, points int) error { func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string, killer, victim, word string, points int) error {
state, err := games.GameState(ctx, id) state, err := games.GameState(ctx, id)
if err != nil { if err != nil {
@ -368,7 +366,7 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
Word: word, Word: word,
Points: points, Points: points,
}, },
KillWords: map[string]KillWords{}, AllKillWords: make(AllKillWords),
} }
toAssign := []string{} toAssign := []string{}
@ -379,7 +377,7 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
toAssign = append(toAssign, k) toAssign = append(toAssign, k)
doNotAssign[k] = v.Assignee doNotAssign[k] = v.Assignee
event.KillWords[k] = KillWords{ event.AllKillWords[k] = KillWords{
Global: v.Global, Global: v.Global,
Assigned: now, Assigned: now,
Assignee: "", Assignee: "",
@ -390,13 +388,13 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
if killerState, ok := state.Players[killer]; !ok { if killerState, ok := state.Players[killer]; !ok {
} else if victimState, ok := state.Players[victim]; !ok { } else if victimState, ok := state.Players[victim]; !ok {
} else { } else {
event.KillWords[killer] = KillWords{ event.AllKillWords[killer] = KillWords{
Global: killerState.KillWords.Global, Global: killerState.KillWords.Global,
Assigned: now, Assigned: now,
Assignee: victimState.KillWords.Assignee, Assignee: victimState.KillWords.Assignee,
Assignment: killerState.KillWords.Assignment, Assignment: killerState.KillWords.Assignment,
} }
toAssign = slices.DeleteFunc(toAssign, func(s string) bool { return s == event.KillWords[killer].Assignee }) toAssign = slices.DeleteFunc(toAssign, func(s string) bool { return s == event.AllKillWords[killer].Assignee })
if killerState.KillWords.Global.Word != word { if killerState.KillWords.Global.Word != word {
victimState.KillWords.Assignment = Assignment{} victimState.KillWords.Assignment = Assignment{}
@ -407,17 +405,17 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
for !func() bool { for !func() bool {
toAssign := slices.Clone(toAssign) toAssign := slices.Clone(toAssign)
doNotAssign := maps.Clone(doNotAssign) doNotAssign := maps.Clone(doNotAssign)
eventKillWords := maps.Clone(event.KillWords) allKillWords := maps.Clone(event.AllKillWords)
for i := range toAssign { for i := range toAssign {
j := rand.Intn(i + 1) j := rand.Intn(i + 1)
toAssign[i], toAssign[j] = toAssign[j], toAssign[i] toAssign[i], toAssign[j] = toAssign[j], toAssign[i]
} }
for k, v := range eventKillWords { for k, v := range allKillWords {
if k == toAssign[0] || doNotAssign[k] == toAssign[0] { if k == toAssign[0] || doNotAssign[k] == toAssign[0] {
return false return false
} }
eventKillWords[k] = KillWords{ allKillWords[k] = KillWords{
Global: v.Global, Global: v.Global,
Assigned: now, Assigned: now,
Assignee: toAssign[0], Assignee: toAssign[0],
@ -426,66 +424,95 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
toAssign = toAssign[1:] toAssign = toAssign[1:]
} }
event.KillWords = eventKillWords event.AllKillWords = allKillWords
return true return true
}() { }() {
} }
globalsInUse := map[string]any{} for k, v := range event.AllKillWords {
publicsInUse := map[string]any{}
privatesInUse := map[string]any{}
for _, v := range event.KillWords {
globalsInUse[v.Global.Word] = nil
for _, public := range v.Assignment.Public {
publicsInUse[public.Word] = nil
}
for _, private := range v.Assignment.Private {
privatesInUse[private.Word] = nil
}
}
randWord := func(words string, taken map[string]any) string {
wordsList := strings.Fields(words)
for {
got := wordsList[rand.Intn(len(wordsList))]
if _, ok := taken[got]; !ok {
taken[got] = nil
return got
}
}
}
randGlobal := func() string {
return randWord(wordsHoliday, globalsInUse)
}
randPublic := func() string {
return randWord(wordsHoliday, publicsInUse)
}
randPrivate := func() string {
return randWord(wordsHoliday, privatesInUse)
}
// TODO generate .Global=...us major cities?, .Assignments.Public=...?, .Assignments.Private=holiday
for k, v := range event.KillWords {
if v.Global.Word == "" { if v.Global.Word == "" {
v.Global = KillWord{Word: randGlobal(), Points: -1} v.Global = KillWord{Word: event.AllKillWords.unusedGlobal(), Points: -1}
event.AllKillWords[k] = v
} }
if len(v.Assignment.Public) == 0 { if len(v.Assignment.Public) == 0 {
v.Assignment.Public = []KillWord{ v.Assignment.Public = []KillWord{}
KillWord{Word: randPublic(), Points: 50}, for i := 0; i < 2; i++ {
KillWord{Word: randPublic(), Points: 50}, v.Assignment.Public = append(v.Assignment.Public, KillWord{Word: event.AllKillWords.unusedPublic(), Points: 50})
event.AllKillWords[k] = v
} }
} }
if len(v.Assignment.Private) == 0 { if len(v.Assignment.Private) == 0 {
v.Assignment.Private = []KillWord{ v.Assignment.Private = []KillWord{}
KillWord{Word: randPrivate(), Points: 100}, for i := 0; i < 2; i++ {
v.Assignment.Private = append(v.Assignment.Private, KillWord{Word: event.AllKillWords.unusedPrivate(), Points: 100})
event.AllKillWords[k] = v
} }
} }
event.KillWords[k] = v
} }
return games.createEvent(ctx, id, event) return games.createEvent(ctx, id, event)
} }
//go:embed holiday.txt
var wordsHoliday string
func (m AllKillWords) unusedGlobal() string {
pool := strings.Fields(wordsHoliday)
inUse := func() []string {
result := []string{}
for _, killWords := range m {
result = append(result, killWords.Global.Word)
}
return result
}
for {
picked := pool[rand.Intn(len(pool))]
if !slices.Contains(inUse(), picked) {
return picked
}
}
}
// TODO hard difficulty
func (m AllKillWords) unusedPrivate() string {
pool := strings.Fields(wordsHoliday)
inUse := func() []string {
result := []string{}
for _, killWords := range m {
for _, killWord := range killWords.Assignment.Private {
result = append(result, killWord.Word)
}
}
return result
}
for {
picked := pool[rand.Intn(len(pool))]
if !slices.Contains(inUse(), picked) {
return picked
}
}
}
// TODO medium difficulty
func (m AllKillWords) unusedPublic() string {
pool := strings.Fields(wordsHoliday)
inUse := func() []string {
result := []string{}
for _, killWords := range m {
for _, killWord := range killWords.Assignment.Public {
result = append(result, killWord.Word)
}
}
return result
}
for {
picked := pool[rand.Intn(len(pool))]
if !slices.Contains(inUse(), picked) {
return picked
}
}
}
func (games Games) CreateEventGameComplete(ctx context.Context, id string) error { func (games Games) CreateEventGameComplete(ctx context.Context, id string) error {
if err := games.db.Exec(ctx, ` if err := games.db.Exec(ctx, `
UPDATE games UPDATE games

View File

@ -174,7 +174,7 @@ func TestParseEvent(t *testing.T) {
Word: "word", Word: "word",
Points: 1, Points: 1,
}, },
KillWords: map[string]KillWords{ AllKillWords: map[string]KillWords{
"x": KillWords{ "x": KillWords{
Global: KillWord{ Global: KillWord{
Word: "a", Word: "a",