Git Product home page Git Product logo

boardgame's Introduction

boardgame is a work-in-progress package that aspires to make it easy to define multi-player boardgames that can be easily hosted in a high-quality web app with minimal configuration.

You formally define the rules and logic of your boardgame in Go by defining a state object and a series of moves that can be made. You also define a simple Polymer-based web component that renders a given game state client-side.

boardgame is under active development as a hobby project and different components of it vary in their completeness and polish.

Getting started

A comprehensive getting started guide, including a walkthrough of all of the important concepts in a real-world example, is in the tutorial.

Demo

Demo showing automatic card and token animations

Design Goals

  • Don't Repeat Yourself Write your normative logic that defines your game in Go a single time.
  • Minimize Code Writing your game should feel like just transcribing the rules into a formal model, not like a challenging coding exercise.
  • Batteries Included Common operations, like "deal cards from the draw stack to each player's hand until each player has 3 cards" should require barely any logic to accomplish.
  • Minimize Boilerplate Structs with powerful defaults to anonymously embed in your structs, and easy-to-use code generation tools where required
  • Clean Layering If you don't like the default behavior, override just a small portion to make it do what you want
  • Flexible Powerful enough to model any real-world board or card game
  • Make Cheaters' Lives Hard Don't rely on security by obscurity to protect secret game state: sanitize properties before transmitting to the client
  • Identify Errors ASAP If you've configured something incorrectly, ideally it's found either by the type checker or at the moment the program boots up, not later when someone's playing a game. The library is designed to minimize interface{}, allowing you to rely on the type system as much as possible, and many common configuration errors will be detected and reported when you call NewGameManager.
  • Fast Minimal reliance on features like reflection at runtime
  • Minimize Javascript Most client-side views are 10's of lines of templates and databinding, sometimes without any javascript at all
  • Rich animations and UI Common operations like cards moving between stacks should make use of flexible, fast animations computed automatically
  • Robust tooling A swiss-army-knife utility called boardgame-util makes it easy to generate boilerplate code, generate starter projects, run development servers, make sure the database is structured well, and more.

Status

The library is currently relativley full-featured. Here are a few of the known gaps (and the issues that track their status):

  • Support of Multiple Browsers (Issue #394) Currently the web-app only fully works in Chrome, with support for animations in Safari, and with limited testing in other browsers
  • More Contorl over Animations (Issue #396) Currently moves that are applied one after another don't pause to allow animations to play
  • Examples with a board None of the example games in the main repo use a board, which means that tools aimed at board-based-games aren't fleshed out
  • Smooth Upgrading (Issue #184) If you change the shape of the state objects in your game, there's currently no way to handle older versions of the game stored in your database.

Many more small things are still rough or not implemented. Please file issues or comment on existing issues in the tracker for things you're missing!

boardgame's People

Contributors

andygeorge avatar jkomoros avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

boardgame's Issues

Add a way for moves to get fields set during Apply()

Like precisely which card was actually drawn--the information necessary to actually have enough information to apply the move clientside.

Will need to keep this separate somehow from information necessary to PROPOSE a move. Maybe with struct tags (ick!) or with a Complete() method that returns true when all of the required fields to propose a move are complete. Or a sub-struct that has state after its been set?

Add a IsGameFinished method

Likely on delegate. This is a method that will check to see if based on the state, the game is over. And if so, who won.

Notion of PlayerMoves and MetaMoves in Game

PlayerMoves is the set of all moves that Players can ever propose. MetaMoves is all other moves--things like FixUps. This makes it easier for e.g. cli to enumerate only the moves that the user likely wants to apply, while still allowing them to propose the other moves if they really want to.

Question: is every MetaMove a FixUp move? Do FixUp moves make sense to apply IFF their Legal() returns true for a given state?

Originally captured in #45

Handle long state strings

If it's too long to fit, figure out how wide the longest string printed so far is, give a few spaces of padding, draw a | line, and then render the rest. Repeat.

Associate Moves with a Game

We want a way for Game or CLI to be able to enumerate moves, ideally with a description, and create a new one.

One way is to have all Moves have a Copy(). So we keep a list of instainiated base moves of all of the types, and when seeing which ones are legal, we go through and Copy() them. Then they can all have a Description() and Name() field, and InitalizeWithState(payload) on them.

Another approach is to have game just have a list of functions that take a state payload and return an initialized move or nil if the game state doesn't permit one to exist. Moves could still have Description() and Name(), and then we'd only be able to list ones that were at least vaguely plausible at that state in the game.

The latter seems cleaner, although there are definitely some instances when I want to enumerate all of the moves in the game, even if I can't do anything with them right now.

So maybe it's Move.Copy()InitForState(state) error. Where if it returns error that means it's not even conceivable right now (let alone legal).

... Is there a distinct concept of "Conceivable at this game state" and "Legal at this game state"? The former is only useful to the extent the move is not yet filled in with all of its fields yet, but otherwise is basically the same. Conceivable seems like it could be an albatross, because it's basically a bespoke version of Legal(), which will be finicky logic.

OK, so it's a list of instantiated Moves(). We can enumerate them for Name() And Description(). If we find one we like, we call Copy().DefaultsForState(state), which always does the best it can to set the properties it can default reasonably. (like TargetPlayerIndex == CurrentPlayer)

Necessary to fix #26

Consider a code-gen approach

Write now we have some interfaces that do things and at various point library users need to cast back and forth and do some weird implementations. Which things are structs and which things are interfaces is seemingly random, which makes everything seem pretty messy.

Another approach would be to do a code-gen approach with marked-up structs, like in https://github.com/go-reform/reform . This is very hard to get working and test, and seems like it could be very finicky. But it's worth considering an option.

Rename State.Payload

The first thing is actually more the StateWrapper, and the inner thing is actually the State.

Create a DefaultDelegate

That just has no-ops for all methods. That way you can easily embed it in your struct and just override the methods you want.

A PlayerIndex property type for States

A top-level expected type. That would allow us to understand the intent, and verify that it's never out of bounds (except for maybe -1 if it's no one's turn)

Add SizedStack

Currently called FixedLengthStack in the explainer.

A normal stack, except that the length is always the same, and -1s are included in spots that aren't filled.

Consider if PropertyReader is necessary

It's not actually used anywhere. And if it were, we'd likely just use reflection (which would require the fields to be public... or would it? Looks like you might be able to read).

It's theoretically useful in the Logic Engine to be able to read property values, but maybe we just do a State.ReadProperty(...name string) interface{}, which can just use reflection.

It's a lot of (weird) overhead to have until we actually need it...

At the worst we can probably remove it and then add it back in if really necessary.

An ASCII Image buffer

That's basically just a two dimensional array of termbox.SetCell calls.

Would have to be in a separate package so that everyone could include it

Would have NewTermboxBuffer(width, height), a Size(), and SetCell.

Then a Render(x, y) which would render into TermBox.

This would allow more dynamic rendering in CLI render mode.

Introduce the notion of Modes in cli

That install the various key bindings when the mode is entered. This will help rationalize the keybinding logic, which currently is very ad hoc...

Necessary to fix #26 (without going crazy, at least)

Move.DefaultsForState(Payload)

Sets the defaults for a move based on the current state. For example, it might set TargetPlayerIndex = state.game.currenPlayerIndex

Because win state is not in State, hard to write logic around

For example, if you want to do a Renderer func, you can't print if the game is won or not, because the state object doesn't know. And legal methods on a move can't know if the game is already over.

It's probably OK to have it be special--renderer funcs can't show it, and legal can't know it, but the cli can render winning state itself, and ApplyMove will always do a check for the game being won anyway.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.