Chore: refactor; mark words [WIP]
This commit is contained in:
@ -10,10 +10,16 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div id="card-{{.Word}}" class="bg-stone-400 border border-gray-500 p-4 rounded-lg min-w-[100px] text-center text-white cursor-pointer"
|
<div id="card-{{.Word}}" class="bg-stone-400 border border-gray-500 rounded-lg min-w-[100px] cursor-pointer flex flex-col h-full">
|
||||||
|
<div class="flex-grow text-center p-4 flex items-center justify-center text-white"
|
||||||
style="text-shadow: 0 2px 4px rgba(0,0,0,0.8);"
|
style="text-shadow: 0 2px 4px rgba(0,0,0,0.8);"
|
||||||
hx-get="/word/show-color?word={{.Word}}" hx-trigger="click" hx-swap="outerHTML transition:true swap:.05s">
|
hx-get="/word/show-color?word={{.Word}}" hx-trigger="click" hx-swap="outerHTML transition:true swap:.05s">
|
||||||
{{.Word}}
|
{{.Word}}
|
||||||
|
</div>
|
||||||
|
<div class="h-6 bg-stone-600 rounded-b flex items-center justify-center text-white text-sm cursor-pointer"
|
||||||
|
onclick="this.innerHTML = 'X';">
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"gralias/broker"
|
"gralias/broker"
|
||||||
"gralias/llmapi"
|
"gralias/llmapi"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
"gralias/utils"
|
|
||||||
"gralias/wordloader"
|
"gralias/wordloader"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -173,22 +172,22 @@ func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) {
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func leaveRole(fi *models.FullInfo) {
|
// // DEPRECATED
|
||||||
fi.Room.RedTeam.Guessers = utils.RemoveFromSlice(fi.State.Username, fi.Room.RedTeam.Guessers)
|
// func leaveRole(fi *models.FullInfo) {
|
||||||
fi.Room.BlueTeam.Guessers = utils.RemoveFromSlice(fi.State.Username, fi.Room.BlueTeam.Guessers)
|
// fi.Room.RedTeam.Guessers = utils.RemoveFromSlice(fi.State.Username, fi.Room.RedTeam.Guessers)
|
||||||
if fi.Room.RedTeam.Mime == fi.State.Username {
|
// fi.Room.BlueTeam.Guessers = utils.RemoveFromSlice(fi.State.Username, fi.Room.BlueTeam.Guessers)
|
||||||
fi.Room.RedTeam.Mime = ""
|
// if fi.Room.RedTeam.Mime == fi.State.Username {
|
||||||
}
|
// fi.Room.RedTeam.Mime = ""
|
||||||
if fi.Room.BlueTeam.Mime == fi.State.Username {
|
// }
|
||||||
fi.Room.BlueTeam.Mime = ""
|
// if fi.Room.BlueTeam.Mime == fi.State.Username {
|
||||||
}
|
// fi.Room.BlueTeam.Mime = ""
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
func joinTeam(ctx context.Context, role, team string) (*models.FullInfo, error) {
|
func joinTeam(ctx context.Context, role, team string) (*models.FullInfo, error) {
|
||||||
// get username
|
// get username
|
||||||
fi, _ := getFullInfoByCtx(ctx)
|
fi, _ := getFullInfoByCtx(ctx)
|
||||||
// leave gueesers if present
|
fi.Room.RemovePlayer(fi.State.Username)
|
||||||
leaveRole(fi)
|
|
||||||
// get room
|
// get room
|
||||||
if role == "mime" {
|
if role == "mime" {
|
||||||
if team == "blue" {
|
if team == "blue" {
|
||||||
@ -367,3 +366,31 @@ func recoverPlayer(pm map[string]string) error {
|
|||||||
}
|
}
|
||||||
return saveState(pm["Username"], us)
|
return saveState(pm["Username"], us)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateMove checks if it is players turn
|
||||||
|
func validateMove(fi *models.FullInfo, ur models.UserRole) error {
|
||||||
|
if fi.State.Role != ur {
|
||||||
|
err := fmt.Errorf("need to be %s to make that action", ur)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// whos move it is?
|
||||||
|
if fi.State.Team != models.UserTeam(fi.Room.TeamTurn) {
|
||||||
|
err := errors.New("not your team's move")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch ur {
|
||||||
|
case models.UserRoleGuesser:
|
||||||
|
if !fi.Room.MimeDone {
|
||||||
|
err := errors.New("wait for the mime to give a clue")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case models.UserRoleMime:
|
||||||
|
if fi.Room.MimeDone {
|
||||||
|
err := errors.New("clue was already given")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("uknown user role: %s", ur)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"gralias/llmapi"
|
"gralias/llmapi"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleShowCreateForm(w http.ResponseWriter, r *http.Request) {
|
func HandleShowCreateForm(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -46,21 +46,10 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
|||||||
abortWithError(w, err.Error())
|
abortWithError(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if fi.State.Role != "guesser" {
|
if err := validateMove(fi, models.UserRoleGuesser); err != nil {
|
||||||
err = errors.New("need to be guesser to open the card")
|
|
||||||
abortWithError(w, err.Error())
|
abortWithError(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// whos move it is?
|
|
||||||
if fi.State.Team != models.UserTeam(fi.Room.TeamTurn) {
|
|
||||||
err = errors.New("not your team's move")
|
|
||||||
abortWithError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !fi.Room.MimeDone {
|
|
||||||
abortWithError(w, "wait for the clue")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
color, exists := fi.Room.WCMap[word]
|
color, exists := fi.Room.WCMap[word]
|
||||||
log.Debug("got show-color request", "word", word, "color", color)
|
log.Debug("got show-color request", "word", word, "color", color)
|
||||||
if !exists {
|
if !exists {
|
||||||
@ -159,6 +148,135 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleMarkCard(w http.ResponseWriter, r *http.Request) {
|
||||||
|
word := r.URL.Query().Get("word")
|
||||||
|
ctx := r.Context()
|
||||||
|
tmpl, err := template.ParseGlob("components/*.html")
|
||||||
|
if err != nil {
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fi, err := getFullInfoByCtx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := validateMove(fi, models.UserRoleGuesser); err != nil {
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
color, exists := fi.Room.WCMap[word]
|
||||||
|
log.Debug("got show-color request", "word", word, "color", color)
|
||||||
|
if !exists {
|
||||||
|
abortWithError(w, "word is not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// check if card already was revealed
|
||||||
|
for i, card := range fi.Room.Cards {
|
||||||
|
if !strings.EqualFold(card.Word, word) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if card.Revealed {
|
||||||
|
abortWithError(w, "cannot mark already revealed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fi.Room.Cards[i].Mark = append(card.Mark, models.CardMark{
|
||||||
|
Username: fi.State.Username,
|
||||||
|
Active: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
cardword := models.WordCard{
|
||||||
|
Word: word,
|
||||||
|
Color: color,
|
||||||
|
Revealed: false,
|
||||||
|
}
|
||||||
|
fi.Room.RevealSpecificWord(word)
|
||||||
|
fi.Room.UpdateCounter()
|
||||||
|
action := models.Action{
|
||||||
|
Actor: fi.State.Username,
|
||||||
|
ActorColor: string(fi.State.Team),
|
||||||
|
WordColor: string(color),
|
||||||
|
Action: models.ActionTypeGuess,
|
||||||
|
Word: word,
|
||||||
|
}
|
||||||
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
|
// if opened card is of color of opp team, change turn
|
||||||
|
oppositeColor := fi.Room.GetOppositeTeamColor()
|
||||||
|
fi.Room.OpenedThisTurn++
|
||||||
|
if fi.Room.ThisTurnLimit > 0 {
|
||||||
|
if fi.Room.ThisTurnLimit >= fi.Room.OpenedThisTurn {
|
||||||
|
// end turn
|
||||||
|
fi.Room.TeamTurn = oppositeColor
|
||||||
|
fi.Room.MimeDone = false
|
||||||
|
fi.Room.OpenedThisTurn = 0
|
||||||
|
fi.Room.ThisTurnLimit = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch string(color) {
|
||||||
|
case "black":
|
||||||
|
// game over
|
||||||
|
fi.Room.IsRunning = false
|
||||||
|
fi.Room.IsOver = true
|
||||||
|
fi.Room.TeamWon = oppositeColor
|
||||||
|
action := models.Action{
|
||||||
|
Actor: fi.State.Username,
|
||||||
|
ActorColor: string(fi.State.Team),
|
||||||
|
WordColor: models.WordColorBlack,
|
||||||
|
Action: models.ActionTypeGameOver,
|
||||||
|
}
|
||||||
|
fi.Room.OpenedThisTurn = 0
|
||||||
|
fi.Room.ThisTurnLimit = 0
|
||||||
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
|
case "white", string(oppositeColor):
|
||||||
|
// end turn
|
||||||
|
fi.Room.TeamTurn = oppositeColor
|
||||||
|
fi.Room.MimeDone = false
|
||||||
|
fi.Room.OpenedThisTurn = 0
|
||||||
|
fi.Room.ThisTurnLimit = 0
|
||||||
|
// check if no cards left => game over
|
||||||
|
if fi.Room.BlueCounter == 0 {
|
||||||
|
// blue won
|
||||||
|
fi.Room.IsRunning = false
|
||||||
|
fi.Room.IsOver = true
|
||||||
|
fi.Room.TeamWon = "blue"
|
||||||
|
action := models.Action{
|
||||||
|
Actor: fi.State.Username,
|
||||||
|
ActorColor: string(fi.State.Team),
|
||||||
|
WordColor: models.WordColorBlue,
|
||||||
|
Action: models.ActionTypeGameOver,
|
||||||
|
}
|
||||||
|
fi.Room.OpenedThisTurn = 0
|
||||||
|
fi.Room.ThisTurnLimit = 0
|
||||||
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
|
}
|
||||||
|
if fi.Room.RedCounter == 0 {
|
||||||
|
// red won
|
||||||
|
fi.Room.IsRunning = false
|
||||||
|
fi.Room.IsOver = true
|
||||||
|
fi.Room.TeamWon = "red"
|
||||||
|
action := models.Action{
|
||||||
|
Actor: fi.State.Username,
|
||||||
|
ActorColor: string(fi.State.Team),
|
||||||
|
WordColor: models.WordColorRed,
|
||||||
|
Action: models.ActionTypeGameOver,
|
||||||
|
}
|
||||||
|
fi.Room.OpenedThisTurn = 0
|
||||||
|
fi.Room.ThisTurnLimit = 0
|
||||||
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := saveFullInfo(fi); err != nil {
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// get mime bot for opp team and notify it
|
||||||
|
notifyBotIfNeeded(fi)
|
||||||
|
notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "")
|
||||||
|
if err := tmpl.ExecuteTemplate(w, "cardword", cardword); err != nil {
|
||||||
|
log.Error("failed to execute cardword template", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func HandleActionHistory(w http.ResponseWriter, r *http.Request) {
|
func HandleActionHistory(w http.ResponseWriter, r *http.Request) {
|
||||||
fi, err := getFullInfoByCtx(r.Context())
|
fi, err := getFullInfoByCtx(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -232,6 +232,8 @@ func RemoveBot(botName string, room *models.Room) error {
|
|||||||
delete(room.BotMap, botName)
|
delete(room.BotMap, botName)
|
||||||
delete(DoneChanMap, botName)
|
delete(DoneChanMap, botName)
|
||||||
delete(SignalChanMap, botName)
|
delete(SignalChanMap, botName)
|
||||||
|
// remove role from room
|
||||||
|
room.RemovePlayer(botName)
|
||||||
return saveRoom(room)
|
return saveRoom(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
main.go
1
main.go
@ -48,6 +48,7 @@ func ListenToRequests(port string) *http.Server {
|
|||||||
mux.HandleFunc("POST /check/name", handlers.HandleNameCheck)
|
mux.HandleFunc("POST /check/name", handlers.HandleNameCheck)
|
||||||
mux.HandleFunc("GET /add-bot", handlers.HandleAddBot)
|
mux.HandleFunc("GET /add-bot", handlers.HandleAddBot)
|
||||||
mux.HandleFunc("GET /remove-bot", handlers.HandleRemoveBot)
|
mux.HandleFunc("GET /remove-bot", handlers.HandleRemoveBot)
|
||||||
|
mux.HandleFunc("GET /mark-card", handlers.HandleMarkCard)
|
||||||
// special
|
// special
|
||||||
mux.HandleFunc("GET /renotify-bot", handlers.HandleRenotifyBot)
|
mux.HandleFunc("GET /renotify-bot", handlers.HandleRenotifyBot)
|
||||||
// sse
|
// sse
|
||||||
|
@ -63,6 +63,11 @@ type BotPlayer struct {
|
|||||||
Team UserTeam
|
Team UserTeam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CardMark struct {
|
||||||
|
Username string
|
||||||
|
Active bool
|
||||||
|
}
|
||||||
|
|
||||||
type Room struct {
|
type Room struct {
|
||||||
ID string `json:"id" db:"id"`
|
ID string `json:"id" db:"id"`
|
||||||
CreatedAt time.Time `json:"created_at" db:"created_at"` // limit?
|
CreatedAt time.Time `json:"created_at" db:"created_at"` // limit?
|
||||||
@ -89,11 +94,24 @@ type Room struct {
|
|||||||
RoundTime int32 `json:"round_time"`
|
RoundTime int32 `json:"round_time"`
|
||||||
IsOver bool
|
IsOver bool
|
||||||
TeamWon UserTeam // blue | red
|
TeamWon UserTeam // blue | red
|
||||||
|
//
|
||||||
|
Mark CardMark // card is marked
|
||||||
// needed for debug
|
// needed for debug
|
||||||
LogJournal []string
|
LogJournal []string
|
||||||
LastActionTS time.Time
|
LastActionTS time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Room) RemovePlayer(username string) {
|
||||||
|
r.RedTeam.Guessers = utils.RemoveFromSlice(username, r.RedTeam.Guessers)
|
||||||
|
r.BlueTeam.Guessers = utils.RemoveFromSlice(username, r.BlueTeam.Guessers)
|
||||||
|
if r.RedTeam.Mime == username {
|
||||||
|
r.RedTeam.Mime = ""
|
||||||
|
}
|
||||||
|
if r.BlueTeam.Mime == username {
|
||||||
|
r.BlueTeam.Mime = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FindBotByTeamRole returns bot name if found; otherwise empty string
|
// FindBotByTeamRole returns bot name if found; otherwise empty string
|
||||||
func (r *Room) FindBotByTeamRole(team, role string) string {
|
func (r *Room) FindBotByTeamRole(team, role string) string {
|
||||||
for bn, b := range r.BotMap {
|
for bn, b := range r.BotMap {
|
||||||
@ -252,6 +270,7 @@ type WordCard struct {
|
|||||||
Word string `json:"word"`
|
Word string `json:"word"`
|
||||||
Color WordColor `json:"color"`
|
Color WordColor `json:"color"`
|
||||||
Revealed bool `json:"revealed"`
|
Revealed bool `json:"revealed"`
|
||||||
|
Mark []CardMark `json:"marks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GameSettings struct {
|
type GameSettings struct {
|
||||||
|
2
todos.md
2
todos.md
@ -45,3 +45,5 @@
|
|||||||
- guesser bot no request after game restart;
|
- guesser bot no request after game restart;
|
||||||
- if mime joins another role, he stays as mime (before game start);
|
- if mime joins another role, he stays as mime (before game start);
|
||||||
- guesser llm makes up words, likely the prompt should be more clear;
|
- guesser llm makes up words, likely the prompt should be more clear;
|
||||||
|
- remove bot does not remove for player roles in the room; +
|
||||||
|
- remove join as mime button if there is a mime already on that team;
|
||||||
|
Reference in New Issue
Block a user