// Package scoreboard keeps players and their scores, enforces the rules, and // saves everything to a JSON file. It knows nothing about the web. package scoreboard import "errors" const MaxNameLength = 30 const MaxChange = 1000 const MaxScore = 1000000 // ErrUnknownPlayer means that no player has the name asked for. var ErrUnknownPlayer = errors.New("There is no player with that name.") // ErrNotSaved means that the file could not be written. It is the server's // problem and not the visitor's, and the board stays as it was. var ErrNotSaved = errors.New("could not save") // Player is one row of the board. The fields are exported because encoding/json // and html/template can only see exported fields. type Player struct { Name string Score int } // Board holds the players. Make one with Open. Its methods may be called by many // requests at the same time. Rules that must stay true: names are unique and not // empty, and every score is from 0 to MaxScore. type Board struct { // TODO: add a sync.Mutex, the file name, and a slice of players. } // Open loads the board from a file. A file that does not exist yet gives an // empty board. A file that cannot be read or understood is an error. func Open(filename string) (*Board, error) { // TODO: read the file, and treat os.ErrNotExist as an empty board. return &Board{}, nil } // TODO: add byScore here: the highest score first, and equal scores in order of // name. It is a named function, for slices.SortFunc. // Players returns a sorted copy of the players. func (b *Board) Players() []Player { // TODO: lock, copy the slice, sort the copy with byScore, and return it. return []Player{} } // AddPlayer adds a player with a score of 0. func (b *Board) AddPlayer(name string) error { // TODO: trim and check the name, lock, refuse a duplicate, and save. return errors.New("TODO: AddPlayer is not written yet.") } // AddPoints changes a player's score by points, which may be negative. func (b *Board) AddPoints(name string, points int) error { // TODO: check points, lock, find the player or return ErrUnknownPlayer, // refuse a score outside the rules, and save. return errors.New("TODO: AddPoints is not written yet.") } // TODO: add a helper that saves a slice, and returns an error containing // ErrNotSaved if that fails, and a helper that writes the JSON file.