Compare commits

...

3 Commits

Author SHA1 Message Date
Bel LaPointe
617785ad51 f u wannabe cors 2024-12-18 19:45:45 -07:00
Bel LaPointe
d2fa707628 tests pass but LOTS of todos 2024-12-16 17:29:27 -07:00
bel
421331eb71 i have a plan but also realize event state computation CANNOT create events because itll evalulate many times 2024-12-15 22:28:26 -07:00
2 changed files with 105 additions and 17 deletions

View File

@@ -11,6 +11,7 @@ import (
"slices"
"strings"
"time"
"unicode"
"github.com/google/uuid"
)
@@ -172,7 +173,10 @@ type (
ID string
Started bool
Completed time.Time
Players map[string]PlayerState
Players map[string]PlayerState
Trial Trial
}
PlayerState struct {
@@ -210,6 +214,12 @@ type (
Points int
}
Trial struct {
Prosecutor string
Defendant string
Word string
}
EventType int
EventPlayerJoin struct {
@@ -243,12 +253,19 @@ type (
Type EventType
Timestamp time.Time
Prosecutor string
Killer string
Defendant string
Word string
}
EventCodenameTrial struct {
Type EventType
Timestamp time.Time
Guilty bool
}
EventNotification struct {
Type EventType
Timestamp time.Time
Recipient string
Message string
}
AllKillWords map[string]KillWords
)
@@ -261,6 +278,7 @@ const (
GameReset
CodenameAccusal
CodenameTrial
Notification
)
type Event interface{ event() }
@@ -272,6 +290,7 @@ func (EventAssignmentRotation) event() {}
func (EventGameReset) event() {}
func (EventCodenameAccusal) event() {}
func (EventCodenameTrial) event() {}
func (EventNotification) event() {}
func EventWithTime(event Event, t time.Time) Event {
switch e := event.(type) {
@@ -296,6 +315,9 @@ func EventWithTime(event Event, t time.Time) Event {
case EventCodenameTrial:
e.Timestamp = t
event = e
case EventNotification:
e.Timestamp = t
event = e
}
return event
}
@@ -358,6 +380,10 @@ func parseEvent(b []byte, timestamp time.Time) (Event, error) {
var v EventCodenameTrial
err := json.Unmarshal(b, &v)
return EventWithTime(v, timestamp), err
case Notification:
var v EventNotification
err := json.Unmarshal(b, &v)
return EventWithTime(v, timestamp), err
}
return nil, fmt.Errorf("unknown event type %d: %s", peek.Type, b)
}
@@ -370,8 +396,6 @@ func (games Games) GameState(ctx context.Context, id string) (GameState, error)
return result, err
}
var stateBeforeAccusal *GameState
for _, event := range events {
switch e := event.(type) {
case EventPlayerJoin:
@@ -406,19 +430,45 @@ func (games Games) GameState(ctx context.Context, id string) (GameState, error)
result.Players[k] = player
}
case EventCodenameAccusal:
if stateBeforeAccusal == nil {
stateBeforeAccusal = &result
result = *stateBeforeAccusal
if actual := result.Players[e.Defendant].KillWords.Codename; !actual.Consumed {
result.Trial.Prosecutor = e.Prosecutor
result.Trial.Defendant = e.Defendant
result.Trial.Word = e.Word
return GameState{}, fmt.Errorf("not impl: accusal: %+v", e)
if !basicallyTheSame(actual.KillWord.Word, e.Word) {
} else if err := games.CreateEventCodenameTrial(ctx, id, true); err != nil { // TODO cannot be in State loop
return GameState{}, err
}
}
case EventCodenameTrial:
if stateBeforeAccusal != nil {
result = *stateBeforeAccusal
stateBeforeAccusal = nil
if result.Trial == (Trial{}) {
} else if e.Guilty {
if err := games.CreateEventNotification(ctx, id, fmt.Sprintf(`%s revealed %s is %s and collected %s's bounty.`, result.Trial.Prosecutor, result.Trial.Defendant, result.Trial.Word, result.Trial.Defendant)); err != nil { // TODO not in this loop
return GameState{}, err
}
return GameState{}, fmt.Errorf("not impl: trial: guilty: %+v", e)
} else {
v := result.Players[result.Trial.Prosecutor]
v.KillWords.Codename.Consumed = true
v.Kills = append(v.Kills, Kill{
Timestamp: e.Timestamp,
Victim: result.Trial.Defendant,
KillWord: KillWord{
Word: result.Trial.Word,
Points: -200,
},
})
result.Players[result.Trial.Prosecutor] = v
return GameState{}, fmt.Errorf("not impl: trial: %+v", e)
v = result.Players[result.Trial.Defendant]
v.KillWords.Codename.KillWord.Word = "" // TODO
return GameState{}, fmt.Errorf("creating state CANNOT create events because it will eval every loop")
if err := games.CreateEventNotification(ctx, id, fmt.Sprintf(`%s accused the innocent %s of being %s. %s will get a new codename.`, result.Trial.Prosecutor, result.Trial.Defendant, result.Trial.Word, result.Trial.Defendant)); err != nil {
return GameState{}, err
}
}
result.Trial = Trial{}
case EventGameReset:
return games.GameState(ctx, e.ID)
default:
@@ -429,6 +479,20 @@ func (games Games) GameState(ctx context.Context, id string) (GameState, error)
return result, err
}
func basicallyTheSame(a, b string) bool {
simplify := func(s string) string {
s = strings.TrimSpace(strings.ToLower(s))
s2 := ""
for _, c := range s {
if unicode.IsLetter(c) {
s2 = fmt.Sprintf("%s%c", s2, c)
}
}
return s2
}
return simplify(a) == simplify(b)
}
func (games Games) CreateGame(ctx context.Context, name string) (string, error) {
var exists string
if err := games.db.Query(ctx,
@@ -490,10 +554,7 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
},
}
prevAllKillWords := make(AllKillWords)
for k, v := range state.Players {
prevAllKillWords[k] = v.KillWords
}
prevAllKillWords := state.AllKillWords()
event.AllKillWords = prevAllKillWords.ShuffleAssignees(killer, victim, word)
event.AllKillWords = event.AllKillWords.FillKillWords()
@@ -501,6 +562,14 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
return games.createEvent(ctx, id, event)
}
func (state GameState) AllKillWords() AllKillWords {
m := make(AllKillWords)
for k, v := range state.Players {
m[k] = v.KillWords
}
return m
}
func (games Games) CreateEventGameReset(ctx context.Context, gid string) error {
state, err := games.GameState(ctx, gid)
if err != nil {
@@ -742,6 +811,23 @@ func (games Games) CreateEventGameComplete(ctx context.Context, id string) error
return games.createEvent(ctx, id, EventGameComplete{Type: GameComplete})
}
func (games Games) CreateEventCodenameAccusal(ctx context.Context, gid, prosecutor, defendant, codename string) error {
return fmt.Errorf("not impl: x accused y")
return fmt.Errorf("not impl: x caught by y")
}
func (games Games) CreateEventCodenameTrial(ctx context.Context, gid string, guilty bool) error {
return fmt.Errorf("not impl: x found guilty/notguilty")
}
func (games Games) CreateEventNotification(ctx context.Context, gid, msg string) error {
return games.CreateEventNotificationTo(ctx, gid, "", msg)
}
func (games Games) CreateEventNotificationTo(ctx context.Context, gid, uid, msg string) error {
return fmt.Errorf("not impl: simple")
}
func (games Games) createEvent(ctx context.Context, id string, v any) error {
payload, err := json.Marshal(v)
if err != nil {

View File

@@ -146,7 +146,9 @@ func (s *S) Session(ctx context.Context) Session {
func (s *S) serveWS(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context()
c, err := websocket.Accept(w, r, nil)
c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
InsecureSkipVerify: true,
})
if err != nil {
return err
}