use an OR in a spot where it will help some tiny amount, set up doc
This commit is contained in:
parent
4e74d926b0
commit
08e0b11db9
9 changed files with 13632 additions and 5 deletions
387
design/othello.typ
Normal file
387
design/othello.typ
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
#let position(..rows) = {
|
||||
rows.pos()
|
||||
}
|
||||
|
||||
#let othello(pos, labels: true, cell-size: 30pt) = {
|
||||
let rows = pos
|
||||
|
||||
// Colors
|
||||
let board-color = rgb("#2d8659")
|
||||
let line-color = rgb("#1a5c3a")
|
||||
let white-piece = rgb("#f0f0f0")
|
||||
let black-piece = rgb("#1a1a1a")
|
||||
let label-color = rgb("#000000")
|
||||
let flip-color = rgb("#d32f2f")
|
||||
let mask-color = rgb("#000000").transparentize(60%)
|
||||
|
||||
// Calculate total size
|
||||
let board-size = cell-size * 8
|
||||
let label-offset = if labels { 15pt } else { 0pt }
|
||||
let total-size = board-size + label-offset * 2
|
||||
let piece-radius = cell-size * 0.4
|
||||
let move-radius = cell-size * 0.25
|
||||
|
||||
box(
|
||||
width: total-size,
|
||||
height: total-size,
|
||||
{
|
||||
place(
|
||||
dx: label-offset,
|
||||
dy: label-offset,
|
||||
// Draw board background
|
||||
rect(
|
||||
width: board-size,
|
||||
height: board-size,
|
||||
fill: board-color,
|
||||
stroke: line-color + 2pt
|
||||
)
|
||||
)
|
||||
|
||||
// Draw grid lines
|
||||
for i in range(1, 8) {
|
||||
let offset = cell-size * i
|
||||
// Vertical lines
|
||||
place(
|
||||
dx: label-offset + offset,
|
||||
dy: label-offset,
|
||||
line(
|
||||
start: (0pt, 0pt),
|
||||
end: (0pt, board-size),
|
||||
stroke: line-color + 1pt
|
||||
)
|
||||
)
|
||||
// Horizontal lines
|
||||
place(
|
||||
dx: label-offset,
|
||||
dy: label-offset + offset,
|
||||
line(
|
||||
start: (0pt, 0pt),
|
||||
end: (board-size, 0pt),
|
||||
stroke: line-color + 1pt
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Draw pieces and markers
|
||||
for (row-idx, row) in rows.enumerate() {
|
||||
for (col-idx, cell) in row.clusters().enumerate() {
|
||||
// Regular pieces
|
||||
if cell == "B" or cell == "W" {
|
||||
let x = label-offset + col-idx * cell-size + cell-size / 2 - piece-radius
|
||||
let y = label-offset + row-idx * cell-size + cell-size / 2 - piece-radius
|
||||
let piece-color = if cell == "B" { black-piece } else { white-piece }
|
||||
let piece-stroke = if cell == "W" { line-color + 0.5pt } else { none }
|
||||
|
||||
place(
|
||||
dx: x,
|
||||
dy: y,
|
||||
circle(
|
||||
radius: piece-radius,
|
||||
fill: piece-color,
|
||||
stroke: piece-stroke
|
||||
)
|
||||
)
|
||||
}
|
||||
// Pieces to be flipped
|
||||
else if cell == "b" or cell == "w" {
|
||||
let x = label-offset + col-idx * cell-size + cell-size / 2 - piece-radius
|
||||
let y = label-offset + row-idx * cell-size + cell-size / 2 - piece-radius
|
||||
let piece-color = if cell == "b" { black-piece } else { white-piece }
|
||||
|
||||
place(
|
||||
dx: x,
|
||||
dy: y,
|
||||
circle(
|
||||
radius: piece-radius,
|
||||
fill: piece-color,
|
||||
stroke: flip-color + 2pt
|
||||
)
|
||||
)
|
||||
}
|
||||
// Available moves
|
||||
else if cell == "0" or cell == "1" {
|
||||
let x = label-offset + col-idx * cell-size + cell-size / 2 - move-radius
|
||||
let y = label-offset + row-idx * cell-size + cell-size / 2 - move-radius
|
||||
let move-color = if cell == "0" {
|
||||
black-piece.transparentize(50%)
|
||||
} else {
|
||||
white-piece.transparentize(50%)
|
||||
}
|
||||
|
||||
place(
|
||||
dx: x,
|
||||
dy: y,
|
||||
circle(
|
||||
radius: move-radius,
|
||||
fill: move-color,
|
||||
stroke: none
|
||||
)
|
||||
)
|
||||
}
|
||||
// Masked squares
|
||||
else if cell == "X" {
|
||||
let x = label-offset + col-idx * cell-size
|
||||
let y = label-offset + row-idx * cell-size
|
||||
|
||||
place(
|
||||
dx: x,
|
||||
dy: y,
|
||||
rect(
|
||||
width: cell-size,
|
||||
height: cell-size,
|
||||
fill: mask-color,
|
||||
stroke: none
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw labels
|
||||
if labels {
|
||||
let files = ("a", "b", "c", "d", "e", "f", "g", "h")
|
||||
let ranks = ("8", "7", "6", "5", "4", "3", "2", "1").rev()
|
||||
|
||||
// File labels (bottom)
|
||||
for (i, file) in files.enumerate() {
|
||||
let x = label-offset + i * cell-size + cell-size / 2
|
||||
place(
|
||||
dx: x,
|
||||
dy: board-size + label-offset + 3pt,
|
||||
align(center, text(size: 10pt, fill: label-color, weight: "bold", file))
|
||||
)
|
||||
}
|
||||
|
||||
// Rank labels (left)
|
||||
for (i, rank) in ranks.enumerate() {
|
||||
let y = label-offset + i * cell-size + cell-size / 2
|
||||
place(
|
||||
dx: 3pt,
|
||||
dy: y,
|
||||
align(horizon, text(size: 10pt, fill: label-color, weight: "bold", rank))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#let othello-legend(cell-size: 20pt) = {
|
||||
let board-color = rgb("#2d8659")
|
||||
let line-color = rgb("#1a5c3a")
|
||||
let white-piece = rgb("#f0f0f0")
|
||||
let black-piece = rgb("#1a1a1a")
|
||||
let flip-color = rgb("#d32f2f")
|
||||
let mask-color = rgb("#000000").transparentize(60%)
|
||||
let piece-radius = cell-size * 0.4
|
||||
let move-radius = cell-size * 0.25
|
||||
|
||||
let legend-item(symbol, description) = {
|
||||
grid(
|
||||
columns: (cell-size + 10pt, 1fr),
|
||||
align: (center + horizon, left + horizon),
|
||||
gutter: 10pt,
|
||||
// Symbol cell
|
||||
box(
|
||||
width: cell-size,
|
||||
height: cell-size,
|
||||
{
|
||||
place(
|
||||
rect(
|
||||
width: cell-size,
|
||||
height: cell-size,
|
||||
fill: board-color,
|
||||
stroke: line-color + 1pt
|
||||
)
|
||||
)
|
||||
symbol
|
||||
}
|
||||
),
|
||||
// Description
|
||||
text(size: 10pt, description)
|
||||
)
|
||||
}
|
||||
|
||||
stack(
|
||||
dir: ttb,
|
||||
spacing: 6pt,
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
dx: cell-size / 2 - piece-radius,
|
||||
dy: cell-size / 2 - piece-radius,
|
||||
circle(radius: piece-radius, fill: black-piece)
|
||||
),
|
||||
[Black disc]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
dx: cell-size / 2 - piece-radius,
|
||||
dy: cell-size / 2 - piece-radius,
|
||||
circle(radius: piece-radius, fill: white-piece, stroke: line-color + 0.5pt)
|
||||
),
|
||||
[White disc]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
dx: cell-size / 2 - piece-radius,
|
||||
dy: cell-size / 2 - piece-radius,
|
||||
circle(radius: piece-radius, fill: black-piece, stroke: flip-color + 2pt)
|
||||
),
|
||||
[Black disc to be flipped]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
dx: cell-size / 2 - piece-radius,
|
||||
dy: cell-size / 2 - piece-radius,
|
||||
circle(radius: piece-radius, fill: white-piece, stroke: flip-color + 2pt)
|
||||
),
|
||||
[White disc to be flipped]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
dx: cell-size / 2 - move-radius,
|
||||
dy: cell-size / 2 - move-radius,
|
||||
circle(radius: move-radius, fill: black-piece.transparentize(50%))
|
||||
),
|
||||
[Available move for black]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
dx: cell-size / 2 - move-radius,
|
||||
dy: cell-size / 2 - move-radius,
|
||||
circle(radius: move-radius, fill: white-piece.transparentize(50%))
|
||||
),
|
||||
[Available move for white]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
place(
|
||||
rect(width: cell-size, height: cell-size, fill: mask-color)
|
||||
),
|
||||
[Masked square]
|
||||
),
|
||||
|
||||
legend-item(
|
||||
[],
|
||||
[Empty square]
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#let shift-indicator(values, cell-size: 30pt) = {
|
||||
assert(values.len() == 9, message: "shift-indicator requires exactly 9 values")
|
||||
|
||||
let board-color = rgb("#2d8659")
|
||||
let line-color = rgb("#1a5c3a")
|
||||
let white-piece = rgb("#f0f0f0")
|
||||
let black-piece = rgb("#1a1a1a")
|
||||
|
||||
let grid-size = cell-size * 3
|
||||
let piece-radius = cell-size * 0.4
|
||||
|
||||
box(
|
||||
width: grid-size,
|
||||
height: grid-size,
|
||||
{
|
||||
// Draw background
|
||||
place(
|
||||
rect(
|
||||
width: grid-size,
|
||||
height: grid-size,
|
||||
fill: board-color,
|
||||
stroke: line-color + 2pt
|
||||
)
|
||||
)
|
||||
|
||||
// Draw grid lines
|
||||
for i in range(1, 3) {
|
||||
let offset = cell-size * i
|
||||
// Vertical lines
|
||||
place(
|
||||
dx: offset,
|
||||
line(
|
||||
start: (0pt, 0pt),
|
||||
end: (0pt, grid-size),
|
||||
stroke: line-color + 1pt
|
||||
)
|
||||
)
|
||||
// Horizontal lines
|
||||
place(
|
||||
dy: offset,
|
||||
line(
|
||||
start: (0pt, 0pt),
|
||||
end: (grid-size, 0pt),
|
||||
stroke: line-color + 1pt
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Draw cells
|
||||
for row in range(3) {
|
||||
for col in range(3) {
|
||||
let idx = row * 3 + col
|
||||
let value = values.at(idx)
|
||||
let x = col * cell-size
|
||||
let y = row * cell-size
|
||||
|
||||
if value == 0 {
|
||||
// Half-white, half-black disc
|
||||
let center-x = x + cell-size / 2
|
||||
let center-y = y + cell-size / 2
|
||||
|
||||
// Draw full black circle
|
||||
place(
|
||||
dx: center-x - piece-radius,
|
||||
dy: center-y - piece-radius,
|
||||
circle(radius: piece-radius, fill: black-piece, stroke: none)
|
||||
)
|
||||
|
||||
// Draw white half-circle using clipping
|
||||
place(
|
||||
dx: center-x,
|
||||
dy: center-y - piece-radius,
|
||||
box(
|
||||
width: piece-radius,
|
||||
height: piece-radius * 2,
|
||||
clip: true,
|
||||
place(
|
||||
dx: -piece-radius,
|
||||
circle(radius: piece-radius, fill: white-piece, stroke: none)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Draw circle outline
|
||||
place(
|
||||
dx: center-x - piece-radius,
|
||||
dy: center-y - piece-radius,
|
||||
circle(radius: piece-radius, fill: none, stroke: line-color + 0.5pt)
|
||||
)
|
||||
} else {
|
||||
// Arrow and number
|
||||
let arrow = if value > 0 { "«" } else { "»" }
|
||||
let num = str(calc.abs(value))
|
||||
place(
|
||||
dx: x,
|
||||
dy: y,
|
||||
box(
|
||||
width: cell-size,
|
||||
height: cell-size,
|
||||
align(
|
||||
center + horizon,
|
||||
text(fill: white, weight: "bold", size: 10pt, arrow + " " + num)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue