Other games to play
-
-
-
-
Fler spel att spela
-
-
-
-
-
-
-
-
-
-
-
-
settings...
theme
西
å—
æ±
北
æ±ã€€å— 西 北
This is a fully functional implementation of the game of mahjong,
with competitive computer players, made for two reasons. The first
being that I like mahjong and I wanted to be able to play it on
a computer without having to install any software for that, and
the second being that it's a great example by which to explain how
to go about writing software that isn't trivial. We've all seen
tutorials for writing a "todo app", or "a single web page", but
those aren't things you'd actually want to write if you were to
make something: they're simple toy exercises to show off "how
easily you can make something". The problem is that tutorials
like this gloss over the fact that actually making something rather
than doing a simple exercise isn't easy. Writing software is hard.
And because it's hard, being told that it's easy also makes it
really easy to forget to plan for hardship: once you find something
you actually want to do, you soon discover that just
following the same methodology of that easy, toy implementation
makes you run into all kinds of obstacles, and if you're not
careful, or you don't have someone to help you get on track,
that thing you wanted to make just grinds to a halt before it
gets abandoned altogether. Tutorials don't teach you how to
plan for work you know is going to take more than a few days
to get done, so what if there was a tutorial that did? A
tutorial that covered the space between toy problems
and product programming as a day job? That's where this comes in.
And not just because of the amount of code involved, it's also
because you need to understand how much you can break up the work,
when to recognise you're going too many different things, and
when to abandon something that just doens't seem to want to work
so that you can try a different approach. Programming is hard,
you're going to fail at some point, and it would be super
nice if there was a tutorial that didn't just tell you want to do,
but also told you what failure looks like, so you can spot it,
and maybe even avoid it.
The game you can play, above, took about two months to write in
my spare time, and I'm going to assume you'll be doing the same,
because you probably already have a job, or you're attending school,
and you don't have the luxury of spending 16 hours a day on personal
projects. So: if you want to learn to program something non-trivial,
and you understand that this means you'll probably be working on it
for a couple of weeks, or even a month or two: this might just be
the tutorial for you.
Of course, if you just came here to play mahjong, then
as an added bonus, you can! Keep reading for an explanation of
how mahjong works, and specifically which rule set and scoring
system this particular implementation of mahjong supports.
Mahjong is a four player tile game where players compete to form a
winning "hand" of 14 tiles, arranged (in general) as four triplets
(either consecutive tiles within the same suit, or genuine triplets with
the same tile three times), and a pair (one tile, twice).
The traditional game uses 144 tiles, consisting of three numbered suits,
seven types of "honour" tile split into "winds" and "dragons", and two
sets of bonus tiles. Specifically:
-
Four sets of the numerical tiles 1 through 9 with "dots" ornamentation (traditionally called ç’, "coin"):
-
Four sets of the numerical tiles 1 through 9 with "bamboo"/"sticks" ornamentation (traditionally called ç´¢, "coin string"):
-
Four sets of the numerical tiles 1 through 9 with "Chinese character" ornamentation (traditionally called è¬, "10,000"):
-
Four sets of the four cardinal "wind" directions:
-
Four sets of "dragon" tiles:
With eight bonus tiles (not part of play - they are set aside
immediately when drawn, with a new tile drawn to replace it):
-
The four seasons (spring, summer, fall, winter, or 春, å¤, 秋, 冬)
-
The four seasonal flowers (orchid, plum blossom, bamboo,
chrysanthenum, or è˜, 梅, 竹, èŠ)
Core game play is about as simple as it gets: everyone starts with 13
tiles, and players take turns in which they draw a tile from the set of
undealt tiles, check to see if they can form a winning pattern, and if
not, discard one of their tiles so they're back at 13, after which it
is the next player's turn.
The "actual game" part, rather than "random chance" aspect comes in the
form of "claims", where players may claim a tile as it is being
discarded if they can use that tile to form certain sets. In this case,
it immediately becomes their turn, irrespective of whose turn it
"should" have been, and rather than drawing a tile from the undealt
tiles, they take the discarded tile as their 14th tile.
-
if a player has two identical tiles in their hand, they may claim a
third tile when another player discards it. This is called a "pung".
-
if a player has three identical tiles in their hand, they may claim
the fourth tile when another player discards it. This is called a
"kong".
-
if a player is waiting for a specific tile to win, they may claim that
winning tile when another player discards it regardless of what the
tile is needed for and whether that would be a legal claim if the
player were not winning on it.
If none of the above claims are made, then the player whose turn it is
next is allowed to pick up the discard tile rather than drawing a tile
from the undealt tiles, in order to form a set consisting of three
consecutive numbers within the same suit, called a "chow". Note that
these sets are typically worth no points, and will typically even
negatively impact the hand score by ruling out scores based on true-set
hand patterns.
In the case when a tile has claims by multiple players, a winning claims
trump any other claims, and a real claim trumps a player wishing to form
a set of consecutive tiles.
When honouring a claim, the receiving player must
reveal all tiles in the set they formed, and put those tiles aside,
face-up. These tiles are considered "locked", and can no longer be used
for anything, with a single exception:
If a player has a locked, true set of three tiles already on the table,
and they draw (not claim) the fourth tile, they are allowed to add that
tile to their locked set of three, forming a locked set of four. If a
player elects to do this, they receive a new tile from the undealt set
of tiles to compensate for the "loss" of a tile. If a player forgets to
do this, they they will not have enough tiles left to form a winning
hand, and may even be penalized for playing a hand with the wrong number
of tiles.
A player is not required to declare sets if they do not need to
claim a tile for them. If a player has a set of three or four tiles in
their hand, due to having started the game with them, or having drawn
tiles over a number of turns to end up with them in hand, they are under
no obligation to reveal that fact. Winning with unrevealed tiles
typically incurs a bonus.
Note that there are special considerations when a player has four of the
same tile in their hand. They may declare this and lock the four tiles
as a set that is no longer in their hand, receiving an extra tile to
prevent them from having too few tiles to form a winning hand (revealing
the tiles depending on the exact rules being played. Some rules do not
require this kind of set to be revealed, meaning other players will not
know which tile has become unavailable, and so may try to win on a tile
that cannot ever appear during that round of play). They may also elect
to keep all four tiles in their hand so that three of the tiles can be
used as one set, and the fourth tile can be used to form a numerical
set. Note that because a winning hand has to consist of four sets and a
pair, a player who wishes to count all four tiles as a single set will
have to declare that set, or they will not have enough tiles
with which to form the necessary number of sets and pair.
Scoring of hands is entirely dependent on the style of mahjong played,
but can be split into two ways to count points:
-
points and doublings, in which players gain points for
individual sets, and score doublings for particular combinations of
sets. Typically this scoring system has an "upper limit", limiting how
many points players can score per hand.
-
faan, in which player's hands are assigned a "hand score"
based on specific sets and patterns of sets, and this hand score is
then translated into a player score based on a rule-dependent mapping.
Typically this scoring system has both an upper limit, to fix how many
points players can score per hand, as well as a "lower limit", in
which getting a higher hand score does not alter the resulting player
score for several steps. E.g. a hand worth 5 or 6 faan may both score
as 5 faan, with a hand worth 7 faan assigned a higher score.
Additionally, rules typically use one of two "score settling" methods:
-
Winner takes all, in which the winner is paid their player score by
the other players. In this system, winning is more important than
forming high scoring hand patterns.
-
Everyone pays everyone, in which the winning player is paid their
score by the other players, and the other players all pay each other
based on the difference in scoring. In this system, forming high
scoring hand patterns is more important than just winning.
The game on this page can be played using two different rulesets:
Chinese Classical rules, and Cantonese rules.
- scoring is based on points and doubles
- players start with 2000 points
- the losers settle their scores after paying the winner
- East is paid double their winnings, and double-pays any losses
- the deal does not pass to the next player if East wins.
Points are awarded to any player for the following (open/concealed):
- each bonus tile: 4
- pair of dragons: 2
- pair of own winds: 2
- pair of wind of the round: 2
- pung of simples (numbers 2 through 8): 2/4
- pung of terminals (numbers 1 and 9): 4/8
- pung of winds: 4/8
- pung of dragons: 4/8
- kong of simples: 8/16
- kong of terminals: 16/32
- kong of winds: 16/32
- kong of dragonss: 16/32
The following points are awarded to the winner only:
- self-drawn win: 2
- winning on a non-scoring pair: 2
- winning on a scoring pair: 4
The following doubles are awarded to any player:
- having your own flower and season: 1
- having all flowers: +1
- having all seasons: +1
- pung/kong of own wind: 1
- pung/kong of wind of the round: 1
- pung/kong of dragons: 1
The following doubles are awarded to the winner only:
- chow hand (four chows and a non-scoring pair): 1
- one suit and honour (numbered tiles all from the same suit) : 1
- one suit (only number tiles, all the same suit): 3
- all pung hand: 1
- fully concealed (and self drawn) hand: 1
- (self-drawn) win on the last tile from the wall: 1
- claimed win on the last discard: 1
- winning by robbing a kong: 1
The following limit hands (scoring a flat 1000 points) exist:
- fully concealed pung hand
- all terminals: pungs and pairs of only 1 and 9 tiles
- all honours: pungs and pairs of winds and dragons
- all kong: four kongs and a pair
- three great scholars: pung/kong of each dragon
- little four winds: pung/kong of three winds, pair of last wind
- big four winds: pung/kong of all winds
- thirteen orphans: a 1 and 9 of each suit, one of each wind and dragon, and a pairing tile
- nine gates: 1,1,1, 2,3,4,5,6,7,8, 9,9,9, all of the same suit, all concealed, and a pairing tile
The player winds rotate counter-clockwise, so that (E,S,W,N) become
(S,W,N,E), and the wind of the round rotates clockwise, starting at
East, then South, then West, then North.
- scoring is based on points ("faan") and tiered limits ("laak"), which are mapped to a real score
- limit hands score at laak 2 (see table below)
- players start with 500 points
- only the winner scores points
- winners are paid double by all players on a self-drawn win, otherwise only the discarding player pays double
Points are awarded for for the following:
- pung/kong of own wind: 1
- pung/kong of wind of the round: 1
- pung/kong of dragons: 1
- having no flowers or seasons: 1
- having your own flower: 1
- having your own season: 1
- having all flowers: 1 extra point
- having all seasons: 1 extra point
- self-drawn win: 1
- chow hand (four chows and a non-scoring pair): 1
- one suit and honour (numbered tiles all from the same suit) : 3
- one suit (only number tiles, all the same suit): 6
- all honours hand: 5
- all pung hand: 3
- fully concealed hand: 1
- winning by robbing a kong: 1
The following limit hands exist:
- all terminals: pungs and pairs of only 1 and 9 tiles
- all honours: pungs and pairs of only winds and dragons
- three great scholars: pung/kong of each dragon
- little four winds: pung/kong of three winds, pair of last wind
- big four winds: pung/kong of all winds
- thirteen orphans: a 1 and 9 of each suit, one of each wind and dragon, and a pairing tile
- nine gates: 1,1,1, 2,3,4,5,6,7,8, 9,9,9, all of the same suit, all concealed, and a pairing tile
The conversion table for turning faan into a hand score is:
faan |
hand score |
0 |
0.5 |
1 |
1 |
2 |
2 |
3 |
4 |
4 |
8 |
5-6 (laak 1) |
16 |
7+ (laak 2) |
32 |
Because of the payment rules explained above, a hand score leads to
a total winnings of either 4x the points when winning off of a discard
(discarding player pays double, the other two players pay the base
score), or 6x the points when declaring a self-drawn win (all other
players pay double).
This game can be played with either a mouse or keyboard (or combination of the two).
The interface may also give you hints while playing:
- When playing with suggestions turned on (these are on by default) any tile that you
can claim will be highlighted in green when someone else plays it.
- When playing with bot recommendations turned on (these are on by default) any tile
that it recommends you claim will be highlighted in pink when someone else plays it.
- When playing with bot recommendations turned on, recommended discards will be highlighted
with a single black bar at the top of the tile.
- Regardless of suggestion settings, the tile you drew during your turn will be highlighted
using a green bar at the bottom of the tile, and your currently selected tile will have a
full green border.
Mouse controls
After receiving a new tile either from the wall or from claiming a set:
- click any tile in your tilebank to discard that tile.
- long-click to bring up the dialog to declare a kong or win.
While looking at discards from other players:
- ignore this discard: click anywhere on the discard "table", except for the discarded tile.
- claim discard: click the discarded tile.
While in a modal dialog, click any button to select that option.
Keyboard controls
After receiving a new tile, and after claiming a set:
- cycle left through your tiles: left cursor key or "a" key
- cycle right through your tiles: right cursor key or "d" key
- jump to first discardable tile: home key
- jump to last discardable tile: end key
- discard highlighted tile: space, enter, up cursor key, or "w" key
- declare a fully concealed, or melded kong with the currently highlighted tile: down cursor key or "s" key
- declare a self-drawn win after dismissing the claim dialog: down cursor key or "s" key
While looking at discards from other players:
- ignore this discard: left or right cursor key, or "a" or "d" key
- claim discard: space, enter, up cursor key, or "w" key
While in a modal dialog:
- move focus up one button: down cursor key, or "s" key
- move focus up one button: up cursor key, or "w" key
- select this button's option: space or enter.