-
Notifications
You must be signed in to change notification settings - Fork 1
/
docs.json
1 lines (1 loc) · 35.5 KB
/
docs.json
1
[{"name":"BoardGameFramework","comment":" Types and functions help create remote multiplayer board games\nusing the related framework. See\n[the detailed documentation and example\ncode](https://github.com/niksilver/board-game-framework/tree/master/docs)\nfor a proper introduction.\n\n# Game IDs\nPlayers with the same game ID (on the same server) are playing the same game.\n@docs GameId, gameId, fromGameId, idGenerator\n\n# Server connection\n@docs Server, wsServer, wssServer, withPort, withGameId, Address, toUrlString\n\n# Basic actions: open, send, close\n@docs open, send, close\n\n# Receiving messages\nWe receive envelopes: either messages from other clients, or messages from\nthe server about leavers and joiners, or messages about connectivity.\nAny game messages sent out are encoded into JSON, so we need to say\nhow to decode our application's JSON messages into some suitable Elm type.\n@docs ClientId, Envelope, Connectivity, decode, decoder\n","unions":[{"name":"Address","comment":" The address of a game which we can connect to.\n","args":[],"cases":[]},{"name":"Connectivity","comment":" The current connectivity state, received when it changes.\n\n`Connecting` can also be interpretted as \"reconnecting\", because\nif the connection is lost then the underlying JavaScript will try to\nreconnect.\n\n`Disconnected` will only be received if the client explicitly\nasks for the connection to be closed; otherwise if a disconnection\nis detected the JavaScript will be trying to reconnect.\n\nBoth `Connecting` and `Disconnected` mean there isn't a server connection,\nbut `Disconnected` means that the underlying JavaScript isn't attempting to\nchange that.\n","args":[],"cases":[["Connected",[]],["Connecting",[]],["Disconnected",[]]]},{"name":"Envelope","comment":" A message from the server, or the JavaScript connection layer.\nIt may contain a message specific to our application, which we say\nis of type `a`.\nSee [the concepts document](https://github.com/niksilver/board-game-framework/blob/master/docs/concepts.md)\nfor many more details of envelopes.\n\nThe envelopes are:\n* A welcome when our client joins;\n* A receipt containing any message we sent;\n* A message sent by another client peer;\n* Notice of another client joining;\n* Notice of another client leaving;\n* Change of status with the server connection;\n* An error reported by the JavaScript library.\n\nThe field names have consistent types and meaning:\n* `me`: our client's own client ID.\n* `others`: the IDs of all other clients currently in the game.\n* `from`: the ID of the client (not us) who sent the message.\n* `to`: the IDs of the clients to whom a message was sent, including us.\n* `joiner`: the ID of a client who has just joined.\n* `leaver`: the ID of a client who has just left.\n* `num`: the ID of the envelope. After a Welcome envelope, nums will\n be consecutive.\n* `time`: when the envelope was sent, in milliseconds since the epoch.\n* `body`: the application-specific message sent by the client.\n","args":["a"],"cases":[["Welcome",["{ me : BoardGameFramework.ClientId, others : List.List BoardGameFramework.ClientId, num : Basics.Int, time : Basics.Int }"]],["Receipt",["{ me : BoardGameFramework.ClientId, others : List.List BoardGameFramework.ClientId, num : Basics.Int, time : Basics.Int, body : a }"]],["Peer",["{ from : BoardGameFramework.ClientId, to : List.List BoardGameFramework.ClientId, num : Basics.Int, time : Basics.Int, body : a }"]],["Joiner",["{ joiner : BoardGameFramework.ClientId, to : List.List BoardGameFramework.ClientId, num : Basics.Int, time : Basics.Int }"]],["Leaver",["{ leaver : BoardGameFramework.ClientId, to : List.List BoardGameFramework.ClientId, num : Basics.Int, time : Basics.Int }"]],["Connection",["BoardGameFramework.Connectivity"]],["Error",["String.String"]]]},{"name":"GameId","comment":" A game ID represents a game that multiple players can join.\nIt's a string intended to be shared among intended players.\n","args":[],"cases":[]},{"name":"Server","comment":" A board game server.\n","args":[],"cases":[]}],"aliases":[{"name":"ClientId","comment":" The unique ID of any client.\n","args":[],"type":"String.String"}],"values":[{"name":"close","comment":" Close the connection to the game server.\nNot strictly necessary in most cases,\nbecause opening a new connection will automatically close an existing one.\n\n import BoardGameFramework as BGF\n\n port outgoing : Enc.Value -> Cmd msg\n\n -- Close our connection\n BGF.close outgoing\n","type":"(Json.Encode.Value -> Platform.Cmd.Cmd msg) -> Platform.Cmd.Cmd msg"},{"name":"decode","comment":" Decode an incoming envelope.\nWhen an envelope is sent it is encoded as JSON, so it needs to be\ndecoded when it's received. Our framework\ncan handle most of that, but it needs help when the envelope contains\na message from a client peer (a body), because that's specific to our\napplication.\n\nThe body is said to be of some type `a`,\nso we need to provide a JSON that produces an `a`.\n\nIf the decoding of the envelope is successful we will get an\n`Ok (Envelope a)`. If there is a problem we will get an `Err Error`.\n\nIn this example we expect our envelope body to be a JSON object\ncontaining an `id` field and a `name` field, both of which are strings.\n\n import Dict exposing (Dict)\n import Json.Decode as Dec\n import Json.Encode as Enc\n import BoardGameFramework as BGF\n\n -- Raw JSON envelopes come into this port\n port incoming : (Enc.Value -> msg) -> Sub msg\n\n type alias Body =\n { id : BGF.ClientId\n , name : String\n }\n\n type alias MyEnvelope = BGF.Envelope Body\n\n -- A JSON decoder which transforms our JSON object into a Body.\n bodyDecoder : Dec.Decoder Body\n bodyDecoder =\n Dec.map2\n Body\n (Dec.field \"id\" Dec.string)\n (Dec.field \"name\" Dec.string)\n\n type Msg =\n ...\n | Received (Result BGF.Error MyEnvelope)\n | ...\n\n -- Turn some envelope into a Msg which we can handle in our\n -- usual update function.\n receive : Enc.Value -> Msg\n receive v =\n BGF.decode bodyDecoder v\n |> Received\n\n -- We'll use this in our usual main function to subscribe to\n -- incoming envelopes and process them.\n subscriptions : Model -> Sub Msg\n subscriptions model =\n incoming receive\n\nSo after subscribing to what comes into our port, the sequence is:\nan envelope gets decoded as a `Result BGF.Error MyEnvelope; this\ngets wrapped into an application-specific `Received` type; we will\nhandle that in our usual `update` function.\n","type":"Json.Decode.Decoder a -> Json.Encode.Value -> Result.Result Json.Decode.Error (BoardGameFramework.Envelope a)"},{"name":"decoder","comment":" Create a JSON decoder for `Envelope a`, given a decoder for `a`.\nSee [`decode`](#decode) for examples.\n","type":"Json.Decode.Decoder a -> Json.Decode.Decoder (BoardGameFramework.Envelope a)"},{"name":"fromGameId","comment":" Extract the game ID as a string.\n","type":"BoardGameFramework.GameId -> String.String"},{"name":"gameId","comment":" Turn a string into a game ID.\nA good game ID will have a good chance of being unique and wil be easy\nto communicate, especially in URLs.\nThis test passes if it's five to thirty characters long (inclusive)\nand consists of just alphanumerics, dots, dashes, and forward slashes.\n\n gameId \"pancake-road\" == Ok ...\n gameId \"backgammon/pancake-road\" == Ok ...\n gameId \"#345#\" == Err \"Bad characters\"\n gameId \"road\" == Err \"Too short\"\n","type":"String.String -> Result.Result String.String BoardGameFramework.GameId"},{"name":"idGenerator","comment":" A random name generator for game IDs, which will be of the form\n\"_word_-_word_\".\n\nTo create a `Cmd` that generates a random name, we can use code like this:\n\n import Random\n import BoardGameFramework as BGF\n\n -- Make sure our Msg can handle a generated game id\n Msg =\n ...\n | GeneratedGameId BGF.GameId\n | ...\n\n -- Our update function\n update : Msg -> Model -> (Model, Cmd)\n update msg model =\n case msg of\n ... ->\n -- Generate a game ID\n ( updatedModel\n , Random.generate GeneratedGameId BGF.idGenerator\n )\n\n GeneratedGameId gameId ->\n -- Use the generated game ID\n","type":"Random.Generator BoardGameFramework.GameId"},{"name":"open","comment":" Open a connection to server, with a given game ID, via an Elm port.\n\n import BoardGameFramework as BGF\n\n port outgoing : Enc.Value -> Cmd msg\n\n server = BGF.wssServer \"bgf.pigsaw.org\"\n gameIdResult = BGF.gameId \"notice-handle\"\n\n -- Open a connection to wss://bgf.pigsaw.org/g/notice-handle\n case gameIdResult of\n Ok gameId ->\n BGF.open outgoing server gameId\n Err _ ->\n -- Won't get here\n","type":"(Json.Encode.Value -> Platform.Cmd.Cmd msg) -> BoardGameFramework.Server -> BoardGameFramework.GameId -> Platform.Cmd.Cmd msg"},{"name":"send","comment":" Send a message to the other clients.\n\nIn this example we'll send a `Body` message to other clients, which\nrequires us defining a JSON encoder for it.\n\n import BoardGameFramework as BGF\n\n type alias Body =\n { id : BGF.ClientId\n , name : String\n }\n\n bodyEncoder : Body -> Enc.Value\n bodyEncoder body =\n Enc.object\n [ (\"id\" , Enc.string body.id)\n , (\"name\" , Enc.string body.name)\n ]\n\n port outgoing : Enc.Value -> Cmd msg\n\n body =\n { id = \"123.456\"\n , name = \"Tango\"\n }\n\n -- Send body to the other clients (and we'll get a receipt).\n BGF.send outgoing bodyEncoder body\n","type":"(Json.Encode.Value -> Platform.Cmd.Cmd msg) -> (a -> Json.Encode.Value) -> a -> Platform.Cmd.Cmd msg"},{"name":"toUrlString","comment":" Turn an `Address` into a URL, expressed as a string.\nThis is useful for debugging, or otherwise seeing what's going on under\nthe hood.\n","type":"BoardGameFramework.Address -> String.String"},{"name":"withGameId","comment":" Create the address of an actual game we can connect to.\n\n gid1 = gameId \"voter-when\"\n gid2 = gameId \"poor-modern\"\n\n wsServer \"localhost\"\n |> withPort 8080\n |> withGameId gid1 -- We can join ws://localhost:8080/g/voter-when\n |> withGameId gid2 -- Changes to ws://localhost:8080/g/poor-modern\n","type":"BoardGameFramework.GameId -> BoardGameFramework.Server -> BoardGameFramework.Address"},{"name":"withPort","comment":" Explicitly set the port of a server, if we don't want to connect to\nthe default port. The default port is 80 for insecure connections and\n443 for secure connections.\n\n wsServer \"localhost\" |> withPort 8080 -- ws://localhost:8080\n","type":"Basics.Int -> BoardGameFramework.Server -> BoardGameFramework.Server"},{"name":"wsServer","comment":" Create a `Server` that uses a websocket connection (not a secure\nwebsocket connection). For example\n\n wsServer \"bgf.pigsaw.org\"\n\nwill allow us to make connections of the form `ws://bgf.pigsaw.org/...`.\n","type":"String.String -> BoardGameFramework.Server"},{"name":"wssServer","comment":" Create a `Server` that uses a secure websocket connection.\nA call of the form\n\n wssServer \"bgf.pigsaw.org\"\n\nwill allow us to make connections of the form `wss://bgf.pigsaw.org/...`.\n","type":"String.String -> BoardGameFramework.Server"}],"binops":[]},{"name":"BoardGameFramework.Clients","comment":" Functions for managing a list of clients (which may be players,\nobservers, or something else).\n\nEach client is simply a record with an `id` field of type `ClientId`,\nplus other fields as desired.\nThe client list will never contain more than one\nelement with the same `ClientId`.\n\nThe type `ClientId` is just an alias for `String`, and comes from the base\n[`BoardGameFramework`](../BoardGameFramework) module.\n\n# Basic types\n@docs Client, Clients\n\n# Build\n@docs empty, singleton, insert, update, remove\n\n# Query\n@docs isEmpty, member, get, length, filterLength\n\n# Lists and dicts\n@docs ids, toList, mapToList, toDict, fromList\n\n# Transform\n@docs map, fold, filter, partition\n\n# Combine\n@docs union, intersect, diff\n\n# JSON\n@docs encode, decoder\n","unions":[{"name":"Clients","comment":" A list of clients.\n","args":["e"],"cases":[]}],"aliases":[{"name":"Client","comment":" A player, observer, or similar.\n","args":["e"],"type":"{ e | id : BoardGameFramework.ClientId }"}],"values":[{"name":"decoder","comment":" A decoder for a client list. You need to provide a decoder for\na single `Client`, including its `id` field.\nRecall that the `id` field is a `ClientId`, which is just an alias for\n`String`.\n\nIf a `Client` has a `name` field and a Boolean `player` field,\nthen this is how we make a decoder for it:\n\n import Json.Decode as Dec\n\n singleClientDecoder =\n Dec.map3\n (\\id name player -> { id = id, name = name, player = player })\n (Dec.field \"id\" Dec.string)\n (Dec.field \"name\" Dec.string)\n (Dec.field \"player\" Dec.bool)\n\n clientsDecoder =\n decoder singleClientDecoder\n\n","type":"Json.Decode.Decoder (BoardGameFramework.Clients.Client e) -> Json.Decode.Decoder (BoardGameFramework.Clients.Clients e)"},{"name":"diff","comment":" Find clients from the first list whose `id` isn't in the second list.\n","type":"BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"},{"name":"empty","comment":" An empty client list.\n","type":"BoardGameFramework.Clients.Clients e"},{"name":"encode","comment":" Encode a client list. You need to provide encoders for each field\n(but not the `id` field - that's taken care of).\n\nIf we have a client list `cs` with a `name` field and a Boolean\n`player` field, then this is how we encode it:\n\n import Json.Encode as Enc\n\n encodeClients : Clients e -> Enc.Value\n encodeClients =\n encode\n [ (\"name\", .name >> Enc.string)\n , (\"player\", .player >> Enc.bool)\n ]\n\n encodedClients : Enc.Value\n encodedClients =\n encodeClients cs\n","type":"List.List ( String.String, BoardGameFramework.Clients.Client e -> Json.Encode.Value ) -> BoardGameFramework.Clients.Clients e -> Json.Encode.Value"},{"name":"filter","comment":" Keep only those clients that pass a test.\n\nHere's how we might get all those in `TeamA`:\n\n filter (\\c -> c.team == TeamA) clients\n","type":"(BoardGameFramework.Clients.Client e -> Basics.Bool) -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"},{"name":"filterLength","comment":" The number of clients that pass a test.\n\nHere's how we might count all those in `TeamA`:\n\n filterLength (\\c -> c.team == TeamA) clients\n","type":"(BoardGameFramework.Clients.Client e -> Basics.Bool) -> BoardGameFramework.Clients.Clients e -> Basics.Int"},{"name":"fold","comment":" Fold over all the clients. Order of processing is not guaranteed.\n\nHere's how to add up everyone's score:\n\n fold (\\c n -> c.score + n) 0 clients\n","type":"(BoardGameFramework.Clients.Client e -> a -> a) -> a -> BoardGameFramework.Clients.Clients e -> a"},{"name":"fromList","comment":" Turn a `List` of clients into a `Clients e`.\nIf the `List` has more than one element with the same `id` then only\none of those will end up in the output, and which one is not predictable.\n","type":"List.List (BoardGameFramework.Clients.Client e) -> BoardGameFramework.Clients.Clients e"},{"name":"get","comment":" Get a client by its ID.\n","type":"BoardGameFramework.ClientId -> BoardGameFramework.Clients.Clients e -> Maybe.Maybe (BoardGameFramework.Clients.Client e)"},{"name":"ids","comment":" Get a list of all the client IDs.\n","type":"BoardGameFramework.Clients.Clients e -> List.List BoardGameFramework.ClientId"},{"name":"insert","comment":" Insert a client, or replace an existing one.\n","type":"BoardGameFramework.Clients.Client e -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"},{"name":"intersect","comment":" Find clients with `id`s that are in both client lists.\nThe client from the first list will be preserved.\n","type":"BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"},{"name":"isEmpty","comment":" Is the client list empty?\n","type":"BoardGameFramework.Clients.Clients e -> Basics.Bool"},{"name":"length","comment":" The number of clients in the list.\n","type":"BoardGameFramework.Clients.Clients e -> Basics.Int"},{"name":"map","comment":" Apply a function to all clients.\n\nThe function could change an `id`.\nThat would almost certainly be a bad idea, but\nif it happened then the resulting client list would still have one\nelement per `id`.\n\nHere's how we might reset everyone's score to zero:\n\n map (\\c -> { c | score = 0}) clients\n","type":"(BoardGameFramework.Clients.Client e -> BoardGameFramework.Clients.Client f) -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients f"},{"name":"mapToList","comment":" Extract a list from all the clients.\n\nIf all our clients have a `name` field, then here's how to get a list\nof all client names:\n\n mapToList .name clients\n","type":"(BoardGameFramework.Clients.Client e -> a) -> BoardGameFramework.Clients.Clients e -> List.List a"},{"name":"member","comment":" See if a client with a given ID is in the client list.\n","type":"BoardGameFramework.ClientId -> BoardGameFramework.Clients.Clients e -> Basics.Bool"},{"name":"partition","comment":" Split the client list into two: those who pass a test (first\nelement of the pair), and those who don't.\n\nIf `player` is a Boolean field distinguishing a participant from an\nobserver, then here's how we might split the two:\n\n partition .player clients\n","type":"(BoardGameFramework.Clients.Client e -> Basics.Bool) -> BoardGameFramework.Clients.Clients e -> ( BoardGameFramework.Clients.Clients e, BoardGameFramework.Clients.Clients e )"},{"name":"remove","comment":" Remove a client from the client list.\n","type":"BoardGameFramework.ClientId -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"},{"name":"singleton","comment":" A client list with one client.\n","type":"BoardGameFramework.Clients.Client e -> BoardGameFramework.Clients.Clients e"},{"name":"toDict","comment":" Get all the clients as a `Dict` mapping from client ID.\n","type":"BoardGameFramework.Clients.Clients e -> Dict.Dict BoardGameFramework.ClientId (BoardGameFramework.Clients.Client e)"},{"name":"toList","comment":" Get all the clients as a list.\n","type":"BoardGameFramework.Clients.Clients e -> List.List (BoardGameFramework.Clients.Client e)"},{"name":"union","comment":" Combine two client lists. If a client with the same `id` appears\nin both lists, then the one from the first list will survive.\n","type":"BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"},{"name":"update","comment":" Update a specific client using a mapping function.\n\nIt's possible for the mapping function to produce a value with\na different `id` from the one given. This would almost certainly be\nan error. But if you did it, then the client with the `id` given will\nbe removed, and the value produced by the mapping function will be\ninserted.\n","type":"BoardGameFramework.ClientId -> (Maybe.Maybe (BoardGameFramework.Clients.Client e) -> Maybe.Maybe (BoardGameFramework.Clients.Client e)) -> BoardGameFramework.Clients.Clients e -> BoardGameFramework.Clients.Clients e"}],"binops":[]},{"name":"BoardGameFramework.Lobby","comment":" The lobby is the first screen of any game, and allows the user to select\nthe game ID. It will also randomly generate a game ID on first loading.\nBut the game ID can also be selected by changing the URL,\nso this module also handles changes through that route.\n\nIf a player needs to provide further information before entering a\ngame (perhaps a name, a team, a role, etc) then that should\nbe captured on a subsequent screen.\n\nThe [`update`](#update) function updates the lobby, including the player\ntyping a game ID and the player successfully leaving the lobby with\na valid game ID.\nTherefore it will also return a `Maybe s`,\nwhich is the initial state of whatever follows the lobby - for example,\nthe initial state of the game.\nThis will be `Nothing` if the player is still in the lobby, and `Just s`\nwhen they successfully leave.\nThe `init` field of the lobby's [`Config`](#Config) defines\nhow to create this initial state `s`.\n\nSee the [simple lobby example](https://github.com/niksilver/board-game-framework/tree/master/examples/lobby-simple)\nfor how this all fits together in practice.\n\n# Defining\n@docs Lobby, Config, Msg, lobby\n\n# Messages\n@docs urlRequested, urlChanged, newDraft, confirm\n\n# Updating\n@docs update\n\n# Querying\n@docs url, urlString, draft, okDraft\n\n# Viewing\n@docs view\n","unions":[{"name":"Lobby","comment":" The lobby is the gateway to the main game.\n","args":["msg","s"],"cases":[]},{"name":"Msg","comment":" A message to update the model of the lobby. We will capture this\nin our main application and pass it into [`update`](#update).\nFor example:\n\n import BoardGameFramework as BGF\n import BoardGameFramework.Lobby as Lobby\n\n type Msg =\n ToLobby Lobby.Msg\n | ...\n\n lobbyConfig : Lobby.Config Msg BGF.GameId\n lobbyConfig =\n { init = ...\n , openCmd = ...\n , msgWrapper = ToLobby\n }\n\n update : Msg -> Model -> (Model, Cmd Msg)\n update msg model =\n case msg of\n ToLobby subMsg ->\n let\n (lobby, maybeNext, cmd) = Lobby.update subMsg model.lobby\n in\n ...\n","args":[],"cases":[]}],"aliases":[{"name":"Config","comment":" How the lobby interoperates with the main app. We need:\n* A way to generate an initial game state (or whatever follows the\n lobby), given a game ID;\n* A function to generate the [`open`](../BoardGameFramework#open)\n command to the server, given a game ID;\n* How to wrap a lobby `msg` into an application-specific message (which\n we can catch at the top level of our application and then pass into the\n lobby).\n","args":["msg","s"],"type":"{ init : BoardGameFramework.GameId -> s, openCmd : BoardGameFramework.GameId -> Platform.Cmd.Cmd msg, msgWrapper : BoardGameFramework.Lobby.Msg -> msg }"}],"values":[{"name":"confirm","comment":" Confirm that we should try to use the draft gameID as the actual game ID -\nfor example, when the user has clicked a Go button after typing in a game\nID. There is no need to check if the game ID is valid.\n\nYou don't need to use this if you're using\nthis module's [`view`](#view) function, but do look at the source of\nthat function if you want to see how it's used.\n","type":"(BoardGameFramework.Lobby.Msg -> msg) -> msg"},{"name":"draft","comment":" Get the (possibly incomplete) game ID that the player is entering\ninto the lobby UI.\nThis isn't necessary if you're using the\n[`view`](#view) function.\n","type":"BoardGameFramework.Lobby.Lobby msg s -> String.String"},{"name":"lobby","comment":" Create a lobby which handles game ID and URL changes.\n","type":"BoardGameFramework.Lobby.Config msg s -> Url.Url -> Browser.Navigation.Key -> ( BoardGameFramework.Lobby.Lobby msg s, Maybe.Maybe s, Platform.Cmd.Cmd msg )"},{"name":"newDraft","comment":" Tell the lobby that the draft game ID has changed - for example, when\nthe user types another character into the lobby's text box, asking which\ngame they'd like to join.\n\nYou don't need to use this if you're using\nthis module's [`view`](#view) function, but do look at the source of\nthat function if you want to see how it's used.\n","type":"(BoardGameFramework.Lobby.Msg -> msg) -> String.String -> msg"},{"name":"okDraft","comment":" See if the (possibly incomplete) game ID is a valid game ID.\nUseful for knowing if we should enable or disable a Go button in the UI,\nbut it isn't necessary if you're using the\n[`view`](#view) function.\n","type":"BoardGameFramework.Lobby.Lobby msg s -> Basics.Bool"},{"name":"update","comment":" Handle any message for the lobby. Returns the new lobby, maybe a\nnew playing state (if a new game ID has been confirmed or a new game link\nhas been clicked on)\nand any commands that need to be\nissued (such as opening a connection to a new game).\n\nThe example below is the `update` function of some main app.\nWe defined our `Lobby` with a `msgWrapper` of\n`ToLobby`, and our model maintains the game-in-progress state as\nits `playing` field.\n\n update : Msg -> Model -> (Model, Cmd Msg)\n update msg model =\n case msg of\n ToLobby lMsg ->\n let\n (lobby, maybePlaying, cmd) = Lobby.update lMsg model.lobby\n in\n ( { model\n | lobby = lobby\n , playing = maybePlaying\n }\n , cmd\n )\n\n ... ->\n","type":"BoardGameFramework.Lobby.Msg -> BoardGameFramework.Lobby.Lobby msg s -> ( BoardGameFramework.Lobby.Lobby msg s, Maybe.Maybe s, Platform.Cmd.Cmd msg )"},{"name":"url","comment":" Get the URL, which the `Lobby` is holding. This may be the URL of\nthe game lobby or the actual game.\n","type":"BoardGameFramework.Lobby.Lobby msg s -> Url.Url"},{"name":"urlChanged","comment":" Default handler for when the URL has changed in the browser.\nThis is called before any page rendering.\nSee [`urlRequested`](#urlRequested) for an example of this being used.\n","type":"(BoardGameFramework.Lobby.Msg -> msg) -> Url.Url -> msg"},{"name":"urlRequested","comment":" Default handler for links being clicked. External links are loaded,\ninternal links are ignored.\n\n import BoardGameFramework as BGF\n import BoardGameFramework.Lobby as Lobby\n\n type Msg =\n ToLobby Lobby.Msg\n | ...\n\n main : Program BGF.ClientId Model Msg\n main =\n Browser.application\n { init = init\n , update = update\n , subscriptions = subscriptions\n , onUrlRequest = Lobby.urlRequested ToLobby\n , onUrlChange = Lobby.urlChanged ToLobby\n , view = view\n }\n","type":"(BoardGameFramework.Lobby.Msg -> msg) -> Browser.UrlRequest -> msg"},{"name":"urlString","comment":" Get the URL as a string.\n","type":"BoardGameFramework.Lobby.Lobby msg s -> String.String"},{"name":"view","comment":" View the lobby form.\n\nYou need to provide the label text (for outside the text box),\nthe placeholder text (for within the text box), and the button text.\nFor styling, the whole is in an HTML `div` of class `bgf-label`.\n","type":"{ label : String.String, placeholder : String.String, button : String.String } -> BoardGameFramework.Lobby.Lobby msg s -> Html.Html msg"}],"binops":[]},{"name":"BoardGameFramework.Sync","comment":" We will want to synchronise some values, such as the state of the\ngame, with our peers.\nWe will calculate an initial value (step 0) and as the game\nprogresses we will calculate later values (step 1, 2, etc).\nBut our peers will be doing the same thing, and sometimes there may\nbe a clash - such as two players on the same team selecting different\noptions at the same time. The way we solve that problem is to always\nsend a calculated (assumed) value to our peers via the server,\nand whichever value we receive first from the server (either ours as\na Receipt, or theirs as a Peer message) is the accepted one.\n\nSo the general procedure is:\ncreate an initial value as our [`zero`](#zero) step,\ncalculate each subsequent step as the game progresses,\nand always send any value we've calculated to the server.\nAt the same time we receive values from the server,\nand [`resolve`](#resolve) any received value with our current value.\n\n# Basics\n@docs Sync, zero, value\n\n# Modifying\n@docs assume, mapToNext, resolve\n\n# Encoding and decoding\n@docs encode, decoder\n\n# Utilities\n@docs envCompare\n","unions":[{"name":"Sync","comment":" Some value which can be synchronised, and resolved against other\nvalues.\n","args":["a"],"cases":[]}],"aliases":[],"values":[{"name":"assume","comment":" Assume a new value as the next step, but recognise that this is yet\nto be accepted.\n\nIn a hangman game, if the state is a string, and the next\nstate is found by revealing one of its letters\nusing some function `reveal : Int -> String -> String`,\nthen we might have\n\n import BoardGameFramework.Sync as Sync exposing (Sync)\n\n next : Int -> Sync String -> Sync String\n next i state =\n let\n state2 =\n Sync.value state\n |> reveal i\n in\n Sync.assume state2\n","type":"a -> BoardGameFramework.Sync.Sync a -> BoardGameFramework.Sync.Sync a"},{"name":"decoder","comment":" Decode a synced value received from another client\nYou need to supply an decoder for the value.\n","type":"Json.Decode.Decoder a -> Json.Decode.Decoder (BoardGameFramework.Sync.Sync a)"},{"name":"encode","comment":" Encode a synced value for sending to another client.\nYou need to supply an encoder for the value.\n\nIn a game of hangman, where we're trying to find a seven letter word,\nwe might create our encoder like this:\n\n\n import Json.Encode as Encode\n import BoardGameFramework.Sync as Sync\n\n word : Sync String\n word = Sync.zero \"-------\"\n\n wordEncoder : Sync String -> Enc.Value\n wordEncoder =\n Sync.encode Enc.string\n","type":"(a -> Json.Encode.Value) -> BoardGameFramework.Sync.Sync a -> Json.Encode.Value"},{"name":"envCompare","comment":" Compare the order of two envelopes. An earlier envelope is `LT`\na later envelope.\n\nA `Connection` envelope has no order information,\nso is considered as late as possible.\n\n env1 = ... -- First Welcome envelope received\n env2 = ... -- First Receipt received after sending something\n envX = ... -- Some connection envelope\n envCompare env1 env2 -- LT\n envCompare env2 env1 -- GT\n envCompare env1 env1 -- EQ\n envCompare envX env1 -- GT\n","type":"BoardGameFramework.Envelope b -> BoardGameFramework.Envelope b -> Basics.Order"},{"name":"mapToNext","comment":" Set the next value with a mapping function. This will be the next step.\nThe new value will not yet be accepted.\n\nIn a hangman game, if the state is a string, and the next\nstate is found by revealing one of its letters\nusing some function `reveal : Int -> String -> String`,\nthen we might have\n\n import BoardGameFramework.Sync as Sync exposing (Sync)\n\n next : Int -> Sync String -> Sync String\n next i state =\n state\n |> Sync.mapToNext (reveal i)\n","type":"(a -> a) -> BoardGameFramework.Sync.Sync a -> BoardGameFramework.Sync.Sync a"},{"name":"resolve","comment":" Resolve which of two values should be considered the correct one.\nThe function takes the envelope that contained the new value, the new value,\nand the current value.\n\n origSyncedValue\n |> Sync.resolve newEnv newSyncedValue\n\nThe result is whichever value is the later step; if they represent the\nsame step then the one from the earlier envelope is preferred; if that\nis still the same then the original value is returned.\n","type":"BoardGameFramework.Envelope b -> BoardGameFramework.Sync.Sync a -> BoardGameFramework.Sync.Sync a -> BoardGameFramework.Sync.Sync a"},{"name":"value","comment":" Get the value from a synchronisation point.\n","type":"BoardGameFramework.Sync.Sync a -> a"},{"name":"zero","comment":" Set an initial value with step `0`, which is known not to have come\nfrom the server.\n","type":"a -> BoardGameFramework.Sync.Sync a"}],"binops":[]},{"name":"BoardGameFramework.Wrap","comment":" Sometimes we don't want to send just one kind of value to\nour peers, but several. If so, then we need to wrap and label each\ntype of value so that it can be correctly identified at the other end.\nThis module helps with that.\n\nAll the examples in this module follow on from the basic setup below,\nin which we will\nsend two kinds of value: a card with a message (a `String`) and the size\nof various piles of chips (a `List Int`). This will be JSON-encoded\nthrough ports, and will be decoded as `Envelope`s.\n\n import Json.Encode as Enc\n import Json.Decode as Dec\n import BoardGameFramework as BGF\n import BoardGameFramework.Wrap as Wrap\n\n type Body =\n Card String\n | Chips (List Int)\n\n type Msg =\n Received (Result Dec.Error (BGF.Envelope Body))\n | ...\n\n port outgoing : Enc.Value -> Cmd msg\n port incoming : (Enc.Value -> msg) -> Sub msg\n\n# JSON\n@docs encode, decoder\n\n# Sending and receiving\n@docs send, receive\n","unions":[],"aliases":[],"values":[{"name":"decoder","comment":" Create a decoder for values which are wrapped with labels.\nWe don't need to use this if we're using the [`receive`](#receive)\nfunction.\n\nGiven a decoder for a card and a decoder for chips, we can create\na `Decoder Body`:\n\n cardDecoder : Dec.Decoder String\n cardDecoder =\n Dec.string\n\n chipsDecoder : Dec.Decoder (List Int)\n chipsDecoder =\n Dec.list Dec.int\n\n bodyDecoder : Dec.Decoder Body\n bodyDecoder =\n Wrap.decoder\n [ (\"card\", Dec.map Card cardDecoder)\n , (\"chips\", Dec.map Chips chipsDecoder)\n ]\n","type":"List.List ( String.String, Json.Decode.Decoder body ) -> Json.Decode.Decoder body"},{"name":"encode","comment":" Wrap a value with a label.\n\n encodeCard : String -> Enc.Value\n encodeCard text =\n Enc.string text\n |> Wrap.encode \"card\"\n\n encodeChips : List Int -> Enc.Value\n encodeChips chips =\n Enc.list Enc.int chips\n |> Wrap.encode \"chips\"\n","type":"String.String -> Json.Encode.Value -> Json.Encode.Value"},{"name":"receive","comment":" Take a JSON-encoded value (which has been wrapped up with a label)\nand turn it into a `msg`. By supplying the first two parameters\nwe get a function (JSON `Value` to `msg`) which can be given\nto the inbound port. Using this function means we don't have to use\n[`decode`](#decode).\n\nUsing our running example, we can subscribe to a `Msg` like this:\n\n port incoming : (Enc.Value -> msg) -> Sub msg\n\n subscriptions : Model -> Sub Msg\n subscriptions _ =\n incoming myReceive\n\n myReceive : Enc.Value -> Msg\n myReceive =\n Wrap.receive\n Received\n [ (\"card\", Dec.map Card cardDecoder)\n , (\"chips\", Dec.map Chips chipsDecoder)\n ]\n\nNow our usual `update` function can take `Received` envelopes of the\ncorrect type.\n\nNote that we don't need to use this `receive` function if\nwe're happy to create our own `Body` decoder:\n\n bodyDecoder : Dec.Decoder Body\n bodyDecoder =\n Wrap.decoder\n [ (\"card\", Dec.map Card cardDecoder)\n , (\"chips\", Dec.map Chips chipsDecoder)\n ]\n\n myReceive : Enc.Value -> Msg\n myReceive v =\n BGF.decode bodyDecoder v\n |> Received\n","type":"(Result.Result Json.Decode.Error (BoardGameFramework.Envelope body) -> msg) -> List.List ( String.String, Json.Decode.Decoder body ) -> Json.Encode.Value -> msg"},{"name":"send","comment":" Send one type of value by wrapping it up with a label, and thus\nmaking it an acceptable envelope body. Parameters are\n\n* The outbound port;\n* The label;\n* A function to encode the value;\n* The value itself.\n\nHere's how we can send a card value and some chips data through the\n`outgoing` port.\n\n sendCardCmd : String -> Cmd Msg\n sendCardCmd =\n Wrap.send outgoing \"card\" encodeCard\n\n\n sendChipsCmd : List Int -> Cmd Msg\n sendChipsCmd =\n Wrap.send outgoing \"chips\" encodeChips\n\n -- Use the functions to send some data\n\n sendCardCmd \"Tell us a secret\" -- Sends the card value to our peers\n sendChipsCmd [150, 0, 100] -- Sends the chips data to our peers\n","type":"(Json.Encode.Value -> Platform.Cmd.Cmd msg) -> String.String -> (body -> Json.Encode.Value) -> body -> Platform.Cmd.Cmd msg"}],"binops":[]}]