Cribbage Board
A two-player cribbage board with the classic 61-hole track for each player: 60 scoring holes in lanes that snake up and back (3 lanes of 20, or 2 lanes of 30), two start holes and a finish hole, grouped in fives with a gap so a score is read at a glance. A groove across the board marks the halfway skunk line, and the four pegs store standing in holes at the start end. The default 3-lane board is 188 x 96 x 8 mm with a 7 mm hole pitch (the 2-lane board is 253 mm long, so use a smaller pitch or print it diagonally). Pegs are 3 mm with a 6 mm round head and a 0.3 mm hole clearance; peg diameter, clearance, pitch and board thickness are parameters. The board prints flat, the pegs lie on a flat cut on their side; no supports.
# Cribbage Board - two 61-hole tracks laid out as a serpentine, with four pegs
#
# Each player has 60 scoring holes in lanes of 20 (or 30) that snake up and back,
# plus two start holes and a finish (61st) hole; the holes are grouped in fives with
# a small gap so a score is read at a glance. The hole positions are one list
# comprehension, drilled in one pass. Four pegs are stored standing in holes at the
# start end. The board prints flat, the pegs lie on their side; no supports.
@param 2..3 step:1 group:"Track" desc:"Lanes per player (3 lanes of 20 or 2 lanes of 30)"
$lanes = 3
@param 6..9 step:0.5 group:"Track" desc:"Hole pitch (mm)"
$pitch = 7
@param 2.8..3.6 step:0.1 group:"Pegs" desc:"Peg diameter (mm)"
$peg_d = 3.0
@param 0.2..0.5 step:0.05 group:"Pegs" desc:"Hole clearance over the peg diameter (mm)"
$peg_fit = 0.3
@param 6..10 step:0.5 group:"Board" desc:"Board thickness (mm)"
$thick = 8
@param choices:["board and pegs", "board", "peg"] group:"Output" desc:"What to build"
$part = "board and pegs"
$n = 60 / $lanes # holes per lane
assert $n == floor($n)
$ggap = 2 # extra space after every 5 holes
$row_len = ($n - 1) * $pitch + ($n / 5 - 1) * $ggap
$x0 = -$row_len / 2
$cgap = 6 # strip between the two players
$margin = 6
$hole_r = ($peg_d + $peg_fit) / 2
$hole_depth = $thick - 2
# --- hole positions -----------------------------------------------------
# lane r (0 = outermost) at y, going +X on even lanes and -X on odd ones
def lane_y($r, $s) = $s * ($cgap / 2 + ($lanes - 1 - $r + 0.5) * $pitch)
def idx($r, $k) = if $r % 2 == 0 then $k else $n - 1 - $k
def hole_x($r, $k) = $x0 + idx($r, $k) * $pitch + floor(idx($r, $k) / 5) * $ggap
def tx($j) = hole_x(floor(($j % 60) / $n), $j % $n) - $cx
def ty($j, $s) = lane_y(floor(($j % 60) / $n), $s)
$fin_x = if $lanes % 2 == 1 then $x0 + $row_len + $ggap + $pitch else $x0 - $ggap - $pitch
$xmin = $x0 - $ggap - 2 * $pitch
$xmax = if $lanes % 2 == 1 then $fin_x else $x0 + $row_len
$store_w = 12 # strip at the start end for the four stored pegs
$bx0 = $xmin - $margin - $store_w
$bx1 = $xmax + $margin
$L = $bx1 - $bx0
$Wd = 2 * ($cgap / 2 + $lanes * $pitch) + 2 * $margin
$cx = ($bx0 + $bx1) / 2
# points on a face are relative to the face centre, so every x carries -$cx
# 0..59 player 1, 60..119 player 2, then start, start, finish for each player
def ex_x($e) = (if $e % 3 == 0 then $x0 - $ggap - $pitch else if $e % 3 == 1 then $x0 - $ggap - 2 * $pitch else $fin_x) - $cx
def ex_y($e) = lane_y((if $e % 3 == 2 then $lanes - 1 else 0), (if $e < 3 then 1 else -1))
def pt($j) = if $j < 60 then (tx($j), ty($j, 1)) else if $j < 120 then (tx($j), ty($j, -1)) else (ex_x($j - 120), ex_y($j - 120))
$pts = [pt($j) for $j in range(126)]
assert len($pts) == 126
$store = [($bx0 + $store_w / 2 + 1 - $cx, (-1.5 + $i) * ($pitch + 1)) for $i in range(4)]
$blank = rect ($L - 8) ($Wd - 8) | offset 4 | extrude $thick # centred on the origin
$board = $blank | faces >Z | points $pts | hole $hole_r depth:$hole_depth
| faces >Z | points $store | hole $hole_r depth:$hole_depth
# a groove across the centre strip marks the halfway (skunk) line of the outer lane: hole 30 is at the far end of lane 0 of a 2-lane board, so only engrave it for 3 lanes
$skunk = box 1.2 ($Wd - 2 * $margin) 1.2 | translate (hole_x(0, 10) - ($pitch + $ggap) / 2 - $cx) 0 $thick
$board2 = if $lanes == 3 then ($board - $skunk) else $board
assert $board2.solids == 1
assert $board2.bbox.x ~ $L
assert $board2.bbox.y ~ $Wd
assert $board2.bbox.z ~ $thick
assert $board2.faces == $blank.faces + 130 * 2 + (if $lanes == 3 then 5 else 0)
print "board (mm)" [$L, $Wd, $thick]
# --- pegs: a shaft that enters the hole, a 45 deg shoulder and a round head ------
$peg_len = $hole_depth - 0.5
$head_d = 2 * $peg_d
$peg = (cylinder ($peg_d / 2) $peg_len | floor)
+ (cone ($peg_d / 2) ($head_d / 2) ($head_d / 2 - $peg_d / 2) | floor | translate 0 0 $peg_len)
+ (cylinder ($head_d / 2) 4 | floor | translate 0 0 ($peg_len + $head_d / 2 - $peg_d / 2))
+ (sphere ($head_d / 2) | translate 0 0 ($peg_len + $head_d / 2 - $peg_d / 2 + 4))
$peg_total = $peg_len + $head_d / 2 - $peg_d / 2 + 4 + $head_d / 2
assert $peg.solids == 1
assert $peg.bbox.z ~ $peg_total
assert $peg_total < $thick + 10
# lying on its side for printing (the head is round, so a flat is cut underneath)
$peg_flat = ($peg | rotate 0 90 0 | translate 0 0 ($head_d / 2)) - (box ($peg_total + 2) ($head_d + 2) 2 | translate 0 0 -0.4)
$pegs = union [$peg_flat | translate (-$peg_total / 2) ($Wd / 2 + 6 + $i * ($head_d + 3)) 0 for $i in range(4)]
assert $pegs.solids == 4
$all = union [$board2, $pegs]
if $part == "board" then $board2 else if $part == "peg" then $peg_flat else $all