Skip to content

Commit

Permalink
Add Sparks game to fix #12.
Browse files Browse the repository at this point in the history
  • Loading branch information
donkirkby committed May 2, 2023
1 parent 5ccc302 commit 0dc25c7
Show file tree
Hide file tree
Showing 20 changed files with 30,625 additions and 16,453 deletions.
2 changes: 2 additions & 0 deletions docs/_data/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
link: /rules/spaiji.html
- name: Spargo / Margo
link: /rules/spargo.html
- name: Sparks
link: /rules/sparks.html
- name: Spire
link: /rules/spire.html
- name: Spline
Expand Down
Binary file added docs/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Andrés. The complete set of game rules are available on the
generous permission of the designers. There are more games in a [BGG list].
* Spaiji was designed by Néstor Romeral Andrés.
* Spargo and Margo were designed by Cameron Browne.
* Sparks was designed by [Dieter Stein].
* Spire was designed by Dieter Stein, and took second place in the Shibumi
Challenge.
* Spline was designed by Néstor Romeral Andrés.
Expand All @@ -55,6 +56,7 @@ Challenge.

[nestorgames web site]: https://nestorgames.com/shibumibook_detail.html
[BGG list]: https://boardgamegeek.com/boardgamefamily/13434/series-shibumi/linkeditems/boardgamefamily?pageid=1&sort=usersrated
[Dieter Stein]: https://spielstein.com/

### Image Credits
The marble and board graphics were designed by Cameron Browne, and are used with
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/spargo.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The board starts empty.

### Play
Players take turns adding a ball of their colour to a playable
point. The ball must have freedom (i.e. it must be visibly connected
point. The ball must have freedom (i.e., it must be visibly connected
to at least one empty board hole by a chain of visibly touching
friendly balls) following the move.

Expand Down
64 changes: 64 additions & 0 deletions docs/rules/sparks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: Sparks Rules

---

* designed by Dieter Stein
* 2 players

### Objective
Place your ball on top of the fire.

### Start
The board (a “fireplace”) starts filled with white and black balls in an alternating pattern. The red balls (called “sparks”) are kept ready to hand.

![Start]

### Play
Two players, White and Black, are taking turns by putting a **spark** from the
supply **and** a ball **of their own colour** from the board (the *coal ball*)
into the hand.

Coal can only be taken if it isn't **pinned**. (It is **free**, or it supports
at most **one** ball on the level above.)

If the coal ball was **free**, the player fills the emptied space with the spark
and plays the coal on any other place.

If the coal ball was **not free**, a supported ball will just drop into place:

* If a **spark** dropped, the player **returns** the spark in the hand to the
supply and plays only the coal ball on any place.
* If a white or black **coal ball** dropped, the player plays both balls in the
hand on any place and in any desired order.

In this example, white takes spark **x** from the supply, removes coal **a**,
puts **x** there, and plays **a**.

![Move 1a]
![Move 1b]

The next player, Black, takes another spark **y**, removes coal **b** which
makes coal **a** drop. Black has two balls now (**b** and **y**) and plays them.

![Move 2a]
![Move 2b]

### End
The player who places a ball of their own colour on top of the pyramid (the
fire cone) wins the game.

### Strategy

There are at least 14 moves. With each turn the pyramid normally grows by one
ball. Only if a spark is dropped, the number of balls is not increased. No
dropping sparks would be a win for Black. Yet there will be spark drops in
every game and players sometimes can force or avoid them. So controlling the
occurrence of spark drops is essential: White wins by an odd, Black by an even
number of spark drops.

[Start]: sparks_start.png "Start position"
[Move 1a]: sparks_move1a.png "Before move 1"
[Move 1b]: sparks_move1b.png "After move 1"
[Move 2a]: sparks_move2a.png "Before move 2"
[Move 2b]: sparks_move2b.png "After move 2"
Binary file added docs/rules/sparks_move1a.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/rules/sparks_move1b.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/rules/sparks_move2a.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/rules/sparks_move2b.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/rules/sparks_start.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions docs/rules/spook.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ title: Spook Rules
### Objective
Get all of your balls caught by Spooky the ghost.

### Play
### Start
The board starts empty.

### Play
The game is played in two phases.

#### A visit to the haunted castle
Two players, Red and Black, take turns placing one ball of their colour either
on an empty board hole or on a 2 × 2 platform. Starting with Red the pyramid is
Expand Down Expand Up @@ -41,6 +44,6 @@ Only if no move is available then:

As usual, pinned balls (supporting more than one ball) may not be removed.

### End of the game
### End
The player who has no more balls of his colour on the board in the getaway phase
wins the game.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
'sandbox=shibumi.sandbox.display:SandboxDisplay',
'spaiji=shibumi.spaiji.display:SpaijiDisplay',
'spargo=shibumi.spargo.display:SpargoDisplay',
'sparks=shibumi.sparks.display:SparksDisplay',
'spire=shibumi.spire.display:SpireDisplay',
'spook=shibumi.spook.display:SpookDisplay',
'sploof=shibumi.sploof.display:SploofDisplay',
Expand Down
125 changes: 124 additions & 1 deletion shibumi/diagram_writer.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
from pathlib import Path
from textwrap import dedent

from PySide6.QtGui import QPainter, QColor

from shibumi.sandbox.game import SandboxState
from shibumi.shibumi_display import ShibumiDisplay
from shibumi.shibumi_game_state import ShibumiGameState
from shibumi.spaiji.display import SpaijiDisplay
from shibumi.spaiji.game import SpaijiState
from shibumi.spline.display import SplineDisplay
from shibumi.spline.game import SplineState
from shibumi.sploof.display import SploofDisplay
from shibumi.sploof.state import SploofState
from zero_play.diagram_writer import DiagramWriter
from zero_play.game_display import center_text_item


class ShibumiDiagramWriter(DiagramWriter):
def __init__(self, state_text: str):
state = SandboxState(state_text)
display = ShibumiDisplay(state)
display.resize(300, 224)
display.ui.game_display.grab() # Force layout.
super().__init__(display)

def add_text(self, text: str, row: int, column: int, level: int = 0):
display = self.display
assert isinstance(display, ShibumiDisplay)
text_item = display.scene().addSimpleText(text)
label = display.column_labels[6]
piece_item = display.item_levels[level][row][column]
font = label.font()
font.setPixelSize(round(piece_item.pixmap().height() * 0.75))
text_item.setFont(font)
game_state = display.current_state
assert isinstance(game_state, ShibumiGameState)
if game_state.get_levels()[level][row][column] == game_state.BLACK:
text_item.setBrush(QColor('white'))
x = piece_item.x() + piece_item.pixmap().width() // 2
y = piece_item.y() + round(piece_item.pixmap().height() * 0.45)
center_text_item(text_item, x, y)


class SpaijiLossDiagram(DiagramWriter):
Expand Down Expand Up @@ -72,6 +103,93 @@ def __init__(self):
board[3, 0, 0] = state.BLACK


class SparksStartDiagram(ShibumiDiagramWriter):
def __init__(self):
super().__init__(dedent('''\
A C E G
7 W B W B 7
5 B W B W 5
3 W B W B 3
1 B W B W 1
A C E G
'''))


class SparksMove1aDiagram(ShibumiDiagramWriter):
def __init__(self):
super().__init__(dedent('''\
A C E G
7 W B W B 7
5 B W B W 5
3 W B W B 3
1 B W B W 1
A C E G
'''))
self.add_text('a', 1, 2)


class SparksMove1bDiagram(ShibumiDiagramWriter):
def __init__(self):
super().__init__(dedent('''\
A C E G
7 W B W B 7
5 B W B W 5
3 W B R B 3
1 B W B W 1
A C E G
B D F
6 W . .
4 . . .
2 . . .
B D F
'''))
self.add_text('x', 1, 2)
self.add_text('a', 2, 0, 1)


class SparksMove2aDiagram(SparksMove1bDiagram):
def __init__(self):
super().__init__()
self.add_text('b', 2, 0)


class SparksMove2bDiagram(ShibumiDiagramWriter):
def __init__(self):
super().__init__(dedent('''\
A C E G
7 W B W B 7
5 W W B W 5
3 W B R B 3
1 B W B W 1
A C E G
B D F
6 . . R
4 . . B
2 . . .
B D F
'''))
self.add_text('x', 1, 2)
self.add_text('a', 2, 0)
self.add_text('y', 2, 2, 1)
self.add_text('b', 1, 2, 1)


class SplineDiagram(DiagramWriter):
def __init__(self):
display = SplineDisplay()
Expand Down Expand Up @@ -267,6 +385,11 @@ def main():
rules_path = Path(__file__).parent.parent / "docs" / "rules"
SpaijiLossDiagram().write(rules_path / "spaiji_loss.png")
SpaijiWinDiagram().write(rules_path / "spaiji_win.png")
SparksStartDiagram().write(rules_path / "sparks_start.png")
SparksMove1aDiagram().write(rules_path / "sparks_move1a.png")
SparksMove1bDiagram().write(rules_path / "sparks_move1b.png")
SparksMove2aDiagram().write(rules_path / "sparks_move2a.png")
SparksMove2bDiagram().write(rules_path / "sparks_move2b.png")
SplineDiagram().write(rules_path / "spline.png")
SplineDiagram2().write(rules_path / "spline2.png")
SploofStartDiagram().write(rules_path / "sploof_start.png")
Expand All @@ -278,4 +401,4 @@ def main():
if __name__ == '__main__':
main()
elif __name__ == '__live_coding__':
SpaijiWinDiagram().demo()
SparksMove2bDiagram().demo()
Loading

0 comments on commit 0dc25c7

Please sign in to comment.