battleword

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 26, 2022 License: MIT Imports: 14 Imported by: 4

README

Battleword

Wordle is cool right now

What is this

Battleword is a competition to see who can come up with the fastest/most accurate/shoutiest wordle solver.

Players host an api, then the battleword engine will make a POST request to their api with the state of a wordle (starting empty).

The player's api should then respond to the state of the game in the body of the post with their best guess. As soon as the battleword engine hears back from them, it will send the results of their guess in a new request. It will do that until the player's api guesses correctly, or they reach the guess limit.

Quickstart

  1. Download the latest release for your OS and unpack
  2. Run solvo (double click) - this starts solvo the solver. He will listen for game states from engine.
  3. Run engine - this starts sending game states to solvo. With every guess solvo makes, engine will send a new request to solvo with the results of his previous guess. Solvo will ignore those results and choose a completely random word to send next. Your solver should do better than solvo.

Setup

To test your own guesser against the engine, create an api that implements the schema below. Once you've done that, run the engine against the api location of your solver like so:

./engine --apis http://localhost:8081

You can specify multiple solvers to compete against each other:

./engine --apis http://localhost:8081,http://localhost:8080

NB these commands are executed in a command line of your choice. Exact syntax may change based on your OS.

API

This is what all solvers need to implement.

/guess

The engine will hit your api here with the previous results of a game. You are expected to respond with your best guess. Each guess_results object also comes with the start and finish time, plus an ID that correlates to the header guessID that gets sent with each request. I've omitted from this JSON for brevity. Solvo prints out the full body when you run him.

Request:
{
    "game_id": "3bead1b6-cd41-4bd0-9ec0-9b451319efba",
    "guess_results": [
        {
            "guess": "tense",
            "result": [ 1, 0, 0, 0, 0 ]
        },
        {
            "guess": "finer",
            "result": [ 0, 1, 0, 0, 1 ]
        },
        {
            "guess": "unset",
            "result": [ 0, 0, 0, 0, 2 ]
        },
        {
            "guess": "cable",
            "result": [ 0, 0, 0, 0, 0 ]
        },
        {
            "guess": "deity",
            "result": [ 2, 0, 1, 1, 0 ]
        }
    ],
    "guess_durations_ns": [ 1002925700, 1001538400, 1000738000, 1000947200, 1000960600 ]
}
Response:
{
	"guess": "rumba",
	"shout": "why is everybody shouting"
}

Shouts server no purpose except to intimidate your opponents.

/ping

In order to get the definition of your character, the engine will ping you. This is also run at the start of each match up to 10 times in order to wake up your server if you're hosting it in serverless land where everything is slightly less reliable.

concurrent_connection_limit specifies how many concurrent requests you are happy with. It will also ensure that only concurrent_connection_limit + 2 games are ever active at once for each player so you don't get a scenario where you have to make all 100 first guesses before being sent the second guess. If you are a big dog, you can crank this as high as you like.

colour is spelt colour because this is a civilised repo. It is used as the colour for your part of the statistics in the UI. It has to be of the format #FFFFFF (not case sensitive though).

Request:

GET request - no payload

Response:
{
	"name": "solvo",
	"description": "the magnificent",
    "concurrent_connection_limit": 10,
    "colour": "#7e0391"
}

There will be more things here in the future. stay posted.

/results

Once all players are finished, the engine will send you the results of everyone in the match. No response is required, except maybe to message your friends to brag. player_id represents your ID, look for the corresponding player in the players array to see how you went. As with the request, all objects come with an ID, start, and end time that has been omitted for brevity where unnecessary. Check Solvo for the exact body.

Request:
{
    "player_id": "9fda863c-f303-47da-a8f0-35b0b84b1abe",
    "results": {
        "match_id": "777f785b-d2f9-4467-990e-e2f90efe3b52",
        "players": [
            {
                "player_id": "9fda863c-f303-47da-a8f0-35b0b84b1abe",
                "definition": {
                    "name": "solvo",
                    "description": "the magnificent"
                },
                "games_played": [
                    {
                        "game_id": "3bead1b6-cd41-4bd0-9ec0-9b451319efba",
                        "guess_results": [
                            {
                                "guess": "tense",
                                "result": [ 1, 0, 0, 0, 0 ]
                            },
                            {
                                "guess": "finer",
                                "result": [ 0, 1, 0, 0, 1 ]
                            },
                            {
                                "guess": "unset",
                                "result": [ 0, 0, 0, 0, 2 ]
                            },
                            {
                                "guess": "cable",
                                "result": [ 0, 0, 0, 0, 0 ]
                            },
                            {
                                "guess": "deity",
                                "result": [ 2, 0, 1, 1, 0 ]
                            },
                            {
                                "guess": "deter",
                                "result": [ 2, 0, 1, 0, 1 ]
                            }
                        ],
                        "guess_durations_ns": [ 1002925700, 1001538400, 1000738000, 1000947200, 1000960600, 1001443500 ]
                    }
                ],
            },
            {
                "player_id": "b6f3c0ed-c885-4253-8d23-725def324c55",
                "definition": {
                    "name": "schwordler",
                    "description": "the brave"
                },
                "games_played": [
                    {
                        "game_id": "3bead1b6-cd41-4bd0-9ec0-9b451319efba",
                        "guess_results": [
                            {
                                "guess": "crane",
                                "result": [ 0, 2, 0, 0, 0 ]
                            },
                            {
                                "guess": "droit",
                                "result": [ 2, 2, 2, 2, 2 ]
                            }
                        ],
                        "correct": true,
                        "guess_durations_ns": [ 2135600, 1794700 ]
                    }
                ],
            }
        ],
        "games": [ { "game_id": "3bead1b6-cd41-4bd0-9ec0-9b451319efba", "answer": "droit" } ],
        "rounds_per_game": 6,
        "letters_per_word": 5
    }
}
Releasing

Any time you add a new tag, a release is automatically built and deployed to github. goreleaser is awesome.

Documentation

Index

Constants

View Source
const (
	LetterResultBlack = iota
	LetterResultYellow
	LetterResultGreen
)
View Source
const (
	GuessIDHeader = "guessID"
)

Variables

View Source
var (
	CommonWords = []string{}/* 2309 elements not displayed */

	AllWords = []string{}/* 10638 elements not displayed */

)

Functions

func GetRandomWord

func GetRandomWord(words []string) string

func GetResult

func GetResult(guess, answer string) []int

func ValidDefinition added in v0.12.0

func ValidDefinition(definition PlayerDefinition) (bool, error)

func ValidGuess

func ValidGuess(guess, answer string) bool

TODO: get word list up in here

Types

type Game added in v0.3.0

type Game struct {
	ID     string `json:"game_id,omitempty"`
	Answer string `json:"answer,omitempty"`
	// contains filtered or unexported fields
}

func InitGame added in v0.3.0

func InitGame(commonWords []string, numLetters, numRounds int) Game

type Guess

type Guess struct {
	Guess string `json:"guess,omitempty"`

	// For the lols:
	Shout string `json:"shout,omitempty"`
}

type GuessResult added in v0.7.0

type GuessResult struct {
	ID string `json:"guess_id,omitempty"`

	Start  time.Time `json:"start,omitempty"`
	Finish time.Time `json:"finish,omitempty"`

	Guess  string `json:"guess,omitempty"`
	Result []int  `json:"result,omitempty"`
}

type Match added in v0.3.0

type Match struct {
	// contains filtered or unexported fields
}

func InitMatch added in v0.3.0

func InitMatch(log logrus.FieldLogger, allWords, commonWords []string, playerURIs []string, numLetters, numRounds, numGames int) (*Match, error)

InitMatch generates all the games for the match and populates player information and other match level metadata

func (*Match) Broadcast added in v0.3.2

func (m *Match) Broadcast()

Broadcast takes the results of the match and sends it to all players

func (*Match) Snapshot added in v0.8.0

func (m *Match) Snapshot() MatchSnapshot

func (*Match) Start added in v0.3.0

func (m *Match) Start(ctx context.Context)

Start kicks off all the games as goroutines and waits for them to complete

type MatchSnapshot added in v0.8.0

type MatchSnapshot struct {
	UUID string `json:"match_id,omitempty"`

	Start time.Time `json:"start,omitempty"`
	End   time.Time `json:"end,omitempty"`

	Players []Player `json:"players,omitempty"`
	Games   []Game   `json:"games,omitempty"`

	RoundsPerGame  int `json:"rounds_per_game,omitempty"`
	LettersPerWord int `json:"letters_per_word,omitempty"`
}

MatchSnapshot is what clients can use to get the current state of the game, and what gets sent to the contestants at the end of matches

type Player

type Player struct {
	ID          string            `json:"player_id,omitempty"`
	Definition  PlayerDefinition  `json:"definition,omitempty"`
	GamesPlayed []PlayerGameState `json:"games_played,omitempty"`

	Finish time.Time `json:"finish,omitempty"`
	// contains filtered or unexported fields
}

func InitPlayer

func InitPlayer(mu *sync.Mutex, log logrus.FieldLogger, uri string) (*Player, error)

func (*Player) BroadcastMatch added in v0.3.2

func (p *Player) BroadcastMatch(m MatchSnapshot) error

func (*Player) PlayMatch added in v0.8.0

func (p *Player) PlayMatch(ctx context.Context, games []Game)

type PlayerConnection added in v0.3.0

type PlayerConnection struct {
	// contains filtered or unexported fields
}

This is all secret or not json readable types

type PlayerDefinition added in v0.3.0

type PlayerDefinition struct {
	Name                string `json:"name,omitempty"`
	Description         string `json:"description,omitempty"`
	ConcurrentConnLimit int    `json:"concurrent_connection_limit,omitempty"`
	Colour              string `json:"colour,omitempty"`
}

func GetDefinition added in v0.4.0

func GetDefinition(uri string) (PlayerDefinition, error)

type PlayerGameState added in v0.3.0

type PlayerGameState struct {
	GameID string `json:"game_id,omitempty"`

	Start  time.Time `json:"start,omitempty"`
	Finish time.Time `json:"finish,omitempty"`

	GuessResults []GuessResult `json:"guess_results,omitempty"`

	Correct bool   `json:"correct,omitempty"`
	Error   string `json:"error,omitempty"`

	GuessDurationsNS []int64 `json:"guess_durations_ns,omitempty"`
	// contains filtered or unexported fields
}

func GetNextState added in v0.8.0

func PlayGame added in v0.8.0

type PlayerMatchResults added in v0.5.0

type PlayerMatchResults struct {
	PlayerID string        `json:"player_id,omitempty"`
	Results  MatchSnapshot `json:"results,omitempty"`
}

this struct includes the player's id to give them certainty about who they were

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL