Add tabletop components 486-500 and ten game icons

Fifteen pieces of a games night: Dice, DiceTray, PlayingCard, CardHand,
Deck, Chessboard, GoBoard, MahjongTile, Domino, Roulette, CoinFlip,
BingoCard, TicTacToe, ScoreTrack and Meeple. Component number 500 is
a meeple, which seems right.

Dice tumble, coins turn and wheels spin on a cue, a frame at a time,
and land at once under Reduce Motion. Hands lift the card you point
at and play the one drawn on top; pieces and stones pick the lighter
of Lit and Ink for White, so they read in every palette; the computer
plays a fair O; FREE is a star in every language.

New 12x12 icons: Spade, Club, Diamond, Meeple, King, Queen, Rook,
Bishop, Knight and Pawn.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-12 14:03:58 -04:00
1 parent 7800003418
commit 81003b21ee
32 files changed
+2781 -1

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
// Package tabletop is dice, cards, boards and tokens.
package tabletop
import (
"fmt"
"strconv"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/icon"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
// Suit is a playing card's suit.
type Suit int
const (
Spades Suit = iota
Hearts
Diamonds
Clubs
)
var suits = [...]struct {
msg string
sp *pixel.Sprite
}{{"spades", icon.Spade}, {"hearts", icon.Heart}, {"diamonds", icon.Diamond}, {"clubs", icon.Club}}
// Card's Rank runs from ace, 1, to king, 13.
type Card struct {
Rank int
Suit Suit
}
// check fails on a rank or suit no deck has.
func (cd Card) check(name string) {
if cd.Rank < 1 || cd.Rank > 13 || cd.Suit < Spades || cd.Suit > Clubs {
panic(fmt.Sprintf("tabletop: %s card %+v", name, cd))
}
}
// ink is a card's color: hearts and diamonds are red.
func (cd Card) ink() pixel.Slot {
if cd.Suit == Hearts || cd.Suit == Diamonds {
return pixel.Bad
}
return pixel.Ink
}
// index is the printed rank: A, 2–10, J, Q, K.
func (cd Card) index() string {
return [...]string{"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}[cd.Rank-1]
}
// name reads a card out, as ACE OF SPADES.
func (cd Card) name(k pixel.Kit) string {
rank := strconv.Itoa(cd.Rank)
switch cd.Rank {
case 1:
rank = k.Msg("ace")
case 11, 12, 13:
rank = k.Msg([...]string{"jack", "queen", "king"}[cd.Rank-11])
}
return fmt.Sprintf(k.Msg("card_name"), rank, k.Msg(suits[cd.Suit].msg))
}
const cardW, cardH = 36, 50
// drawCard paints a card at x, y: face or back.
func drawCard(g pixel.Canvas, x, y int, cd Card, back bool) {
g.Frame(x, y, cardW, cardH, pixel.Flat, pixel.Lit)
if back {
g.Rect(x+3, y+3, cardW-6, cardH-6, pixel.Accent)
for j := 0; j < cardH-10; j += 4 {
for i := j / 4 % 2 * 2; i < cardW-10; i += 4 {
g.Rect(x+5+i, y+5+j, 2, 2, pixel.AccentLit)
}
}
return
}
ink, idx := cd.ink(), cd.index()
g.Micro(x+3, y+3, idx, ink, 1)
g.Micro(x+cardW-3-pixel.MicroWidth(idx), y+cardH-8, idx, ink, 1)
// Every card shows its suit in a corner.
g.Sprite(x+cardW-14, y+2, suits[cd.Suit].sp, 0, ink, 1)
// Court cards show their piece, the rest a big pip.
sp := suits[cd.Suit].sp
if cd.Rank > 10 {
sp = [...]*pixel.Sprite{icon.Knight, icon.Queen, icon.King}[cd.Rank-11]
}
g.Sprite(x+(cardW-24)/2, y+(cardH-24)/2+2, sp, 0, ink, 2)
}
// pips places 0–6 pips on a face of side s.
func pips(g pixel.Canvas, x, y, s, n int, ink pixel.Slot) {
if n < 0 || n > 6 {
panic(fmt.Sprintf("tabletop: %d pips", n))
}
spots := [...][][2]int{{}, {{1, 1}}, {{0, 0}, {2, 2}}, {{0, 0}, {1, 1}, {2, 2}}, {{0, 0}, {2, 0}, {0, 2}, {2, 2}},
{{0, 0}, {2, 0}, {1, 1}, {0, 2}, {2, 2}}, {{0, 0}, {2, 0}, {0, 1}, {2, 1}, {0, 2}, {2, 2}}}[n]
d := max(2, s/7)
for _, p := range spots {
g.Rect(x+s*(p[0]+1)/4-d/2, y+s*(p[1]+1)/4-d/2, d, d, ink)
}
}
// shades are Lit and Ink, lighter first: White looks white.
func shades(k pixel.Kit) (light, dark pixel.Slot) {
lum := func(s pixel.Slot) int {
c := k.C(s)
return 299*int(c.R) + 587*int(c.G) + 114*int(c.B)
}
if lum(pixel.Lit) >= lum(pixel.Ink) {
return pixel.Lit, pixel.Ink
}
return pixel.Ink, pixel.Lit
}
// players color tokens, one slot a player.
var players = []pixel.Slot{pixel.Bad, pixel.Info, pixel.Good, pixel.Warn, pixel.Magic, pixel.Ink}