Packages

A library providing a representation of Riichi Mahjong

Current section

Files

Jump to
ritchie README.md
Raw

README.md

# ritchie

[![Package Version](https://img.shields.io/hexpm/v/ritchie)](https://hex.pm/packages/ritchie)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://ritchie.hexdocs.pm/)

A complete **R**iichi **M**ahjong representation in Gleam. Heavily inspired by [`summivox`'s Rust riichi library](https://github.com/summivox/riichi-rs). Notable _differences_ include:
- The hand decomposition parser is entirely hand-rolled, it doesn't use lookup tables (that would be weird and hard with Gleam's restrictions)
- A separate `game` module is provided that tracks state across game rounds
- Possible actions/reactions can be listed at any point during the game, which makes it significantly easier to build upon
  (the logic is already there, after all)

```sh
gleam add ritchie
```
```gleam
import ritchie/game
import ritchie/elements/tile
import ritchie/elements/wall
import ritchie/model/action
import ritchie/model/discard

pub fn main() -> Nil {
    // Initialize a new game with standard rules, starting at 25000 points per player.
    let g = game.new_default()
    // Start a new round with a given wall (a full sorted wall, in our case)
    let assert Ok(g) = game.start_round(g, wall.make_sorted_wall(#(1, 1, 1)))
    
    // Reflect on `game.current_state` (which has the current draw, hands, melds, discards, and so on),
    // and then construct an `action` from the player whose turn it is.
    let ac = action.ActionDiscard(discard.Discard(
        tile: tile.t("3m"), // for example
        called_by: 2,
        declares_riichi: False,
        is_tsumogiri: True,
    ))
    // Register the action with the game. The game checks if the action is valid, and caches it to be
    // applied the next time you call `game.step`.
    let assert Ok(g) = game.register_action(g, ac)
    // Now, you could also construct a reaction (see `ritchie/model/reaction`), or even multiple, and
    // apply them in the same way using `game.register_reaction`. When you are done...
    // Process the next game step (action + reaction(s)), to produce the next state.
    case game.step(g) {
        Ok(game.GameStepOutcome(g, step, None)) -> {
            // Congrats, the next turn has started!
        }
        Ok(game.GameStepOutcome(g, step, Some(_))) -> {
            // Oh, the round has ended! This could potentially also
            // mean that the game is over.
        }
    }
}
```

Further documentation can be found at <https://ritchie.hexdocs.pm/>.

## Todo

Major and minor things that need doing:

- [ ] Shuffle wall. `game.start_round` currently expects a pre-shuffled wall
- [ ] More types should be opaque, especially the ones that the player uses.
      There should instead be constructors for most things
- [ ] Player bankruptcy should be handled
- [ ] Renhou is not detected
- [ ] Probably JSON serialization
- [ ] Properly implement `yaku_extra` and `yaku_block` in the ruleset

## License

Licensed under the LGPL-3.0.