Skip to content

Instantly share code, notes, and snippets.

@zamfofex
Last active January 21, 2023 07:11
Show Gist options
  • Save zamfofex/b9dc6375b3f4eb3798a536841ea7354d to your computer and use it in GitHub Desktop.
Save zamfofex/b9dc6375b3f4eb3798a536841ea7354d to your computer and use it in GitHub Desktop.
Dummyette on Discord
*
!/.gitignore
!/readme.md
!/map.json
!/notation.js
!/pieces.js
!/discord.js
!/main.js

Dummyette on Discord

Dummyette can now be used as a Discord bot! This is just a silly project I have decided to spend some time on.

Invite Dummyette to your Discord server!

usage

deno run -A --import-map=.../map.json .../main.js

This will create a directory in the CWD named channels which will contain the current game information for each channel so that the bot can continue games even across different executions.

Once running, moves can be given to (as messages) it in channels it partakes in UCI/SAN format.

The Discord bot token can be specified by the environment variable discord_token.

license

0BSD (zero‐clause BSD) © zamfofex

import {LiveController} from "dummyette/streams.js"
let opNames = ["dispatch", "heartbeat", "identify", "presence", "voice", "-", "resume", "reconect", "request-members", "invalid", "hello", "acknowledge"]
let ops = Object.assign({}, ...opNames.map((op, n) => ({[op]: n})))
let properties =
{
$os: "Linux",
$browser: "Dummyette",
$device: "wicord",
}
let v = "10"
let base = `https://discord.com/api/v${v}`
export let Discord = async token =>
{
token = String(token)
let sequence = 0
let headers = {authorization: token}
let jsonHeaders = {...headers, "content-type": "application/json"}
let socket = new WebSocket(`wss://gateway.discord.gg/?v=${v}&encoding=json`)
let send = (op, d) => socket.send(JSON.stringify({op: op, d}))
let {stream, tryPush} = LiveController()
let packets = stream.map(string => JSON.parse(string))
let events = packets.filter(({op}) => op === ops.dispatch)
socket.addEventListener("message", ({data}) => tryPush(data))
events.forEach(({s}) => sequence = s)
let {op, d: {heartbeat_interval}} = await packets.first
if (op !== ops.hello) return
setInterval(() => send(ops.heartbeat, sequence), heartbeat_interval)
send(ops.identify, {token, intents: (1<<9)|(1<<12)|(1<<15), properties})
let applicationID = await events.filter(({t}) => t === "READY").map(({d}) => d.application.id).first
let createMessage = ({id, channel_id, content, author: {id: authorID}}) =>
{
let reply = async (text, body = new FormData()) =>
{
text = String(text)
let json = JSON.stringify({content: text, allowed_mentions: {replied_user: false}, message_reference: {message_id: id}})
body.set("payload_json", json)
let response = await fetch(`${base}/channels/${channel_id}/messages`, {method: "POST", headers, body})
if (!response.ok) throw new Error("response not ok")
await response.text()
}
let author = {id: authorID}
Object.freeze(author)
let message = {id, author, text: content, reply, channelID: channel_id}
Object.freeze(message)
return message
}
let createInteraction = ({id, channel_id, token, data: {name, options}}) =>
{
let values = {}
for (let option of options ?? [])
values[option.name] = option.value
let reply = async (text, body = new FormData()) =>
{
text = String(text)
let json = JSON.stringify({type: 4, data: {content: text}})
body.set("payload_json", json)
let response = await fetch(`${base}/interactions/${id}/${token}/callback`, {method: "POST", headers, body})
if (!response.ok) throw new Error("response not ok")
await response.text()
let edit = async (text, body = new FormData()) =>
{
text = String(text)
let json = JSON.stringify({content: text})
body.set("payload_json", json)
let response = await fetch(`${base}/webhooks/${applicationID}/${token}/messages/@original`, {method: "PATCH", headers, body})
if (!response.ok) throw new Error("response not ok")
await response.text()
}
let result = {edit}
Object.freeze(result)
return result
}
return {name, values, reply, channelID: channel_id}
}
let messages = events
.filter(({t}) => t === "MESSAGE_CREATE")
.map(({d}) => createMessage(d))
let Command = async ({name, description, type = "chat", options = []} = {}) =>
{
name = String(name)
type = String(type)
if (description) description = String(description)
else description = undefined
if (type !== "chat") return
let json =
{
name,
type: 1,
description,
options: [],
}
for (let {name, description, type = "string", min, max, required = false, choices} of options)
{
name = String(name)
type = String(type)
min = Number(min)
max = Number(max)
required = Boolean(required)
if (description) description = String(description)
else description = undefined
let typeNumber
if (type === "string") typeNumber = 3
if (type === "integer") typeNumber = 4
if (type === "number") typeNumber = 10
if (typeNumber === undefined) return
let optionJSON =
{
name,
description,
type: typeNumber,
required,
}
if (type === "string")
optionJSON.min_length = min,
optionJSON.max_length = max
else
optionJSON.min_value = min,
optionJSON.max_value = max
if (choices)
{
optionJSON.choices = []
for (let choice of choices)
{
if (typeof choice === "object")
{
let {value, name = value} = choice
optionJSON.choices.push({name, value})
}
else
{
optionJSON.choices.push({name: choice, value: choice})
}
}
}
json.options.push(optionJSON)
}
let response = await fetch(`${base}/applications/${applicationID}/commands`, {method: "POST", headers: jsonHeaders, body: JSON.stringify(json)})
if (!response.ok) throw new Error("response not ok")
await response.text()
let interactions = events
.filter(({t, d}) => t === "INTERACTION_CREATE" && d.type === 2 && d.data?.name === name)
.map(({d}) => createInteraction(d))
return interactions
}
let discord = {messages, Command, id: applicationID}
Object.freeze(discord)
return discord
}
import {standardBoard, emptyBoard, Board960} from "dummyette/chess.js"
import {AsyncAnalyser} from "dummyette/dummyette.js"
import {toSAN, fromFEN} from "dummyette/notation.js"
import {Discord} from "./discord.js"
import {createCanvas} from "canvas"
import * as pieces from "./pieces.js"
import {parseMoveName} from "./notation.js"
import {LiveStream} from "dummyette/streams.js"
let perspective = 1.25
let roundedRect = (ctx, x, y, width, height, radius) =>
{
ctx.moveTo(x + radius, y)
ctx.arcTo(x + width, y, x + width, y + height, radius)
ctx.arcTo(x + width, y + height, x, y + height, radius)
ctx.arcTo(x, y + height, x, y, radius)
ctx.arcTo(x, y, x + width, y, radius)
}
let draw = (canvas, board, move, color = board.turn, knightTypes) =>
{
let {ceil, floor} = Math
if (!knightTypes) knightTypes = []
let w2 = canvas.width / board.width
let h2 = canvas.height / (board.height + perspective)
let width = canvas.width
let height = ceil(h2 * board.height)
let offset = canvas.height - height
let ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.save()
ctx.beginPath()
roundedRect(ctx, 0, offset, width, height, width / 32)
ctx.clip()
ctx.beginPath()
ctx.fillStyle = "#FAFAFA"
ctx.rect(0, offset, width, height)
ctx.fill()
for (let x = 0 ; x < 4 ; x++)
for (let y = 0 ; y < 4 ; y++)
{
let x0 = x * 2
let y0 = y * 2
let x1 = (x0 + 0) * w2
let x2 = (x0 + 1) * w2
let x3 = (x0 + 2) * w2
let y1 = (y0 + 0) * h2
let y2 = (y0 + 1) * h2
let y3 = (y0 + 2) * h2
let g1 = ctx.createLinearGradient(x1, y2 + offset, x2, y3 + offset)
g1.addColorStop(0, "#BDE4")
g1.addColorStop(1, "#BDE")
let g2 = ctx.createLinearGradient(x2, y1 + offset, x3, y2 + offset)
g2.addColorStop(0, "#BDE4")
g2.addColorStop(1, "#BDE")
ctx.beginPath()
ctx.fillStyle = g1
ctx.rect(floor(x1), floor(y2 + offset), ceil(w2), ceil(h2))
ctx.fillStyle = g2
ctx.rect(floor(x2), floor(y1 + offset), ceil(w2), ceil(h2))
ctx.fill()
}
ctx.restore()
if (move)
{
ctx.beginPath()
ctx.fillStyle = "#FBD"
for (let {x, y} of [move.from, move.to])
{
if (color === "black") x = 7 - x
else y = 7 - y
ctx.ellipse((x + 0.5) * w2, (y + 0.5) * h2 + offset, w2 / 2 * 0.75, h2 / 2 * 0.75, 0, 0, 7)
}
ctx.fill()
}
for (let x = 0 ; x < board.width ; x++)
for (let y = 0 ; y < board.height ; y++)
{
let x0 = x
let y0 = y
if (color === "white")
y0 = board.height - y0 - 1
else
x0 = board.width - x0 - 1
let piece = board.at(x0, y0)
if (!piece) continue
let fill = "#EEE"
let stroke = "#666"
if (piece.color === "black")
fill = "#777",
stroke = "#333"
let knightType
if (piece.type === "knight")
knightType = knightTypes[board.Position(x0, y0).name]
if (!knightType) knightType = []
ctx.translate((x + 0.5) * w2, (y + 1 - 0.25) * h2 + offset)
ctx.scale(w2 / 512, w2 / 512)
let flipped = false
if (color === "black") ctx.scale(-1, 1), flipped = !flipped
if (knightType.includes("flipped")) ctx.scale(-1, 1), flipped = !flipped
if (knightType.includes("pony")) ctx.scale(0.85, 0.85)
if (knightType.includes("unicorn")) pieces.horn(ctx, fill, stroke)
pieces[piece.type](ctx, fill, stroke, flipped)
if (knightType.includes("pegasus")) pieces.wings(ctx, fill, stroke)
ctx.setTransform(1, 0, 0, 1, 0, 0)
}
}
let pieceNames = {pawn: "p", knight: "n", bishop: "b", rook: "r", queen: "q", king: "k"}
let toFEN = board =>
{
let result = []
for (let y = board.height - 1 ; y >= 0 ; y--)
{
let rank = ""
let count = 0
for (let x = 0 ; x < board.width ; x++)
{
let piece = board.at(x, y)
if (!piece)
{
count++
continue
}
if (count !== 0)
rank += count
count = 0
let name = pieceNames[piece.type]
if (piece.color === "white") name = name.toUpperCase()
rank += name
}
if (count !== 0)
rank += count
result.push(rank)
}
let turn = "w"
if (board.turn !== "white") turn = "b"
let whiteKing = board.getKingPosition("white")
let blackKing = board.getKingPosition("black")
let castle = ""
if (board.get(whiteKing) === "initial")
{
for (let x = 0 ; x < board.width ; x++)
{
if (board.at(x, whiteKing.y)?.type === "rook" && board.get(x, whiteKing.y) === "initial")
castle += board.Position(x, whiteKing.y).file.toUpperCase()
}
}
if (board.get(blackKing) === "initial")
{
for (let x = 0 ; x < board.width ; x++)
{
if (board.at(x, blackKing.y)?.type === "rook" && board.get(x, blackKing.y) === "initial")
castle += board.Position(x, blackKing.y).file
}
}
if (!castle) castle = "-"
let ep = "-"
for (let x = 0 ; x < board.width ; x++)
for (let y = 0 ; y < board.height ; y++)
{
let piece = board.at(x, y)
if (piece?.type === "pawn" && board.get(x, y) === "passing")
{
let position
if (piece.color === "white") position = board.Position(x, y - 1)
else position = board.Position(x, y + 1)
ep = position.name
break
}
}
return `${result.join("/")} ${turn} ${castle} ${ep}`
}
let canvas = createCanvas(512, 512)
let analyser = AsyncAnalyser()
let search = (board, i = 4) =>
{
if (i === 0) return board.score
let result = -Infinity
for (let {play} of board.moves)
{
let score = -search(play(), i - 1)
if (score > result) result = score
}
return result
}
let evaluate = async board =>
{
if (board.width !== 8 || board.height !== 8)
return 0
let [{move, score}] = await analyser.evaluate(board)
return score
}
let analyse = board =>
{
if (board.width === 8 && board.height === 8)
return analyser.analyse(board)
let evaluations = board.moves.map(move => ({move, score: search(move.play())}))
evaluations.sort((a, b) => a.score - b.score)
return evaluations.map(({move}) => move)
}
await Deno.mkdir("channels", {recursive: true})
let discord = await Discord(Deno.env.get("discord_token"))
let defaultKnights =
{
b1: ["flipped"], b8: ["flipped"],
a2: ["flipped", "pony"],
b2: ["flipped", "pegasus"],
c2: ["flipped", "unicorn"],
d2: ["flipped", "pegasus", "unicorn"],
e2: ["pegasus", "unicorn"],
f2: ["unicorn"],
g2: ["pegasus"],
h2: ["pony"],
a7: ["flipped", "pony"],
b7: ["flipped", "pegasus"],
c7: ["flipped", "unicorn"],
d7: ["flipped", "pegasus", "unicorn"],
e7: ["pegasus", "unicorn"],
f7: ["unicorn"],
g7: ["pegasus"],
h7: ["pony"],
}
let resign = async (reply, channelID) =>
{
await reply("You resigned the game!")
try { await Deno.remove(`channels/${channelID}.txt`) }
catch (e) { if (!(e instanceof Deno.errors.NotFound)) throw e }
}
let playMove = (knightTypes, move) =>
{
if (move.captured)
delete knightTypes[move.captured.position.name]
if (move.from.name in knightTypes)
{
knightTypes[move.to.name] = knightTypes[move.from.name]
delete knightTypes[move.from.name]
}
return move.play()
}
let play = async (reply, channelID, color, board, knightTypes) =>
{
if (!color) color = "white"
if (color === "random")
{
if (Math.random() < 0.5)
color = "white"
else
color = "black"
}
let move
if (color !== board.turn)
{
let message = await reply("Starting game\u2026")
reply = message.edit
let moves = await analyse(board)
move = moves[0]
board = playMove(knightTypes, move)
}
draw(canvas, board, move, color, knightTypes)
let formData = new FormData()
formData.set("file[0]", new Blob([canvas.toBuffer()], {type: "image/png"}), "board.png")
if (move) await reply(toSAN(move), formData)
else await reply("", formData)
await Deno.writeTextFile(`channels/${channelID}.txt`, toFEN(board) + "\n" + JSON.stringify(knightTypes))
}
let chess960 = (reply, channelID, color, n) =>
{
let board
if (n === undefined) board = Board960()
else board = Board960(n)
play(reply, channelID, color, board, defaultKnights)
}
let offerDraw = async (reply, channelID) =>
{
let {board} = await getBoard(channelID)
let score = await evaluate(board)
if (score < -2)
{
await reply("Draw accepted!")
try { await Deno.remove(`channels/${channelID}.txt`) }
catch (e) { if (!(e instanceof Deno.errors.NotFound)) throw e }
}
else
{
await reply("I decline the draw, the game goes on!")
}
}
let interactions = LiveStream(
await discord.Command(
{
name: "chess960",
description: "Challenge me to a chess 960 game in this channel.",
options:
[
{
name: "which",
description: "Number of the chess 960 starting position. (Default: Random)",
type: "integer",
min: 0, max: 959,
},
{
name: "color",
description: "The color you are going to be playing as. (Default: White)",
type: "string",
choices: ["white", "black", "random"],
},
],
}),
await discord.Command(
{
name: "resign",
description: "Resign the ongoing game in this channel.",
}),
await discord.Command(
{
name: "draw",
description: "Offer me a draw.",
}),
await discord.Command(
{
name: "play",
description: "Challenge me to a chess game in this channel.",
options:
[
{
name: "color",
description: "The color you are going to be playing as. (Default: White)",
type: "string",
choices: ["white", "black", "random"],
},
{
name: "fen",
description: "The FEN of the position to play. (Default: Initial Position)",
type: "string",
min: 6,
},
],
}),
)
let getBoard = async channelID =>
{
let board
let knightTypes
try
{
let text = await Deno.readTextFile(`channels/${channelID}.txt`)
let [fen, knightTypeJSON] = text.split("\n")
board = fromFEN(fen)
if (knightTypeJSON) knightTypes = JSON.parse(knightTypeJSON)
else knightTypes = []
}
catch (e)
{
if (!(e instanceof Deno.errors.NotFound)) throw e
board = undefined
}
let result
if (board) result = {board, knightTypes}
else result = {board: standardBoard, knightTypes: defaultKnights}
return result
}
; (async () =>
{
for await (let {name, values, reply, channelID} of interactions)
{
if (name === "play")
{
let knightTypes = defaultKnights
let board = standardBoard
if (values.fen)
{
knightTypes = []
board = fromFEN(values.fen)
if (!board)
{
await reply("Your FEN is invalid.")
continue
}
if (board.width !== 8 || board.height !== 8)
{
await reply("The board must be 8×8 squares.")
continue
}
}
await play(reply, channelID, values.color, board, knightTypes)
}
if (name === "chess960") await chess960(reply, channelID, values.color, values.which)
if (name === "resign") await resign(reply, channelID)
if (name === "draw") await offerDraw(reply, channelID)
}
})()
for await (let message of discord.messages)
{
if (message.author.id === discord.id) continue
if (message.text === "!chess end")
{
await resign(message.reply, message.channelID)
continue
}
if (/!chess [0-9]{1,3}/.test(message.text))
{
let n = Number(message.text.slice("!chess ".length))
if (Number.isInteger(n) && n <= 960)
{
if (n === 960) n = undefined
await chess960(message.reply, message.channelID, "white", n)
continue
}
}
let messageText = message.text
let {board, knightTypes} = await getBoard(message.channelID)
let color = board.turn
let match = parseMoveName(messageText)
let possibilities
if (match)
{
possibilities = board.moves.filter(move => match(move))
if (possibilities.length !== 1) match = undefined
}
if (!match)
{
match = parseMoveName(messageText, true)
if (match) possibilities = board.moves.filter(move => match(move))
}
if (!match) continue
if (possibilities.length === 0)
{
await message.reply("Wait, that’s illegal!")
continue
}
if (possibilities.length > 1)
{
await message.reply("Which move did you mean?\n" + possibilities.map(move => `• ${toSAN(move)}`).join("\n"))
continue
}
let move = possibilities[0]
board = playMove(knightTypes, move)
let moves = await analyse(board)
let text = ""
if (moves.length !== 0)
{
move = moves[0]
board = playMove(knightTypes, move)
text = toSAN(move) + "\n"
}
if (board.moves.length === 0)
text += "Game over!",
await Deno.remove(`channels/${message.channelID}.txt`)
else
await Deno.writeTextFile(`channels/${message.channelID}.txt`, toFEN(board) + "\n" + JSON.stringify(knightTypes))
draw(canvas, board, move, color, knightTypes)
let formData = new FormData()
formData.set("file[0]", new Blob([canvas.toBuffer()], {type: "image/png"}), "board.png")
await message.reply(text, formData)
}
{
"imports":
{
"dummyette/": "https://raw.githubusercontent.com/zamfofex/dummyette/main/",
"canvas": "https://deno.land/x/canvas/mod.ts"
}
}
let pieces =
{
p: "pawn",
n: "knight",
b: "bishop",
r: "rook",
q: "queen",
k: "king",
B: "bishop",
"♙": "pawn",
"♘": "knight",
"♗": "bishop",
"♖": "rook",
"♕": "queen",
"♔": "king",
"♟︎": "pawn",
"♞": "knight",
"♝": "bishop",
"♜": "rook",
"♛": "queen",
"♚": "king",
}
let names = Object.keys(pieces)
let files = [..."abcdefgh"]
let ranks = [..."12345678"]
let tt = () => true
let ff = () => false
let and = (f, g) => (...args) => f(...args) && g(...args)
let or = (f, g) => (...args) => f(...args) || g(...args)
let not = f => (...args) => !f(...args)
let check = move => move.play().check
let checkmate = move => move.play().checkmate
let promotes = move => Boolean(move.promotion)
let promotesTo = type => move => move.play().at(move.to).type === type
let fileFrom = file => move => move.from.file === file
let rankFrom = rank => move => move.from.rank === rank
let fileTo = file => move => (move.rook?.from ?? move.to).file === file
let rankTo = rank => move => (move.rook?.from ?? move.to).rank === rank
let pieceFrom = type => move => move.before.at(move.from).type === type
let captures = move => Boolean(move.captured)
let shortCastle = move => move.rook && move.rook.from.x > move.from.x
let longCastle = move => move.rook && move.rook.from.x < move.from.x
let castle = or(shortCastle, longCastle)
let checkmark = ch =>
{
if (ch === "+") return check
if (ch === "#") return checkmate
}
let promotionTo = ch =>
{
if (names.includes(ch)) return and(promotes, promotesTo(pieces[ch]))
}
let promotion = ch =>
{
if (ch === "=") return promotes
}
let toRank = ch =>
{
if (ranks.includes(ch)) return rankTo(ch)
}
let toFile = ch =>
{
if (files.includes(ch)) return fileTo(ch)
}
let fromRank = ch =>
{
if (ranks.includes(ch)) return rankFrom(ch)
}
let fromFile = ch =>
{
if (files.includes(ch)) return fileFrom(ch)
}
let captureMark = ch =>
{
if (ch === "×" || ch === "x") return captures
}
let fromPiece = ch =>
{
if (names.includes(ch)) return pieceFrom(pieces[ch])
}
let parsers = [() => tt, checkmark, promotionTo, promotion, toRank, toFile, captureMark, fromRank, fromFile, fromPiece]
export let parseMoveName = (name, bishops) =>
{
name = String(name)
name = name.normalize("NFKD")
name = name.replace(/[^A-Za-z0-9\p{S}#]/ug, "")
let castles = name.match(/^([oO0]{1,3})([+#]?)$/)
if (castles)
{
let [{}, castling, check] = castles
let result = castle
if (castling.length === 2) result = shortCastle
if (castling.length === 3) result = longCastle
if (check) result = and(result, checkmark(check))
return result
}
name = [...name]
name.reverse()
let original = name
name = name.map(ch => ch.toLowerCase())
let traverse = (i, j, has) =>
{
if ((j === parsers.length) !== (i === name.length)) return
if (i === name.length)
{
if (!has.includes(toFile))
if (!has.includes(toRank))
return
if (!has.includes(fromFile))
if (!has.includes(fromRank))
if (!has.includes(fromPiece))
return pieceFrom("pawn")
return tt
}
let parse = parsers[j]
if (!has.includes(captureMark))
{
if (parse === fromRank)
if (!has.includes(toRank))
return
if (parse === fromFile)
if (!has.includes(toFile))
return
}
if (parse === promotion && !has.includes(promotionTo)) return
let ch = name[i]
if (bishops && ch === "b")
{
ch = original[i]
if (parse === fromPiece && ch === "b")
return
}
let f = parse(ch)
if (!f) return
has = [...has, parse]
let result = ff
for (let k = j + 1 ; k <= parsers.length ; k++)
{
let f = traverse(i + 1, k, has)
if (!f) continue
result = or(f, result)
}
if (result === ff) return
return and(result, f)
}
return traverse(-1, 0, [])
}
// piece set by FreeVector.com: https://www.freevector.com/chess-icons-vector-set-20658
let strokePawn = ctx =>
{
ctx.moveTo(114.1, -192.4)
ctx.bezierCurveTo(91.1, -215.9, 65.1, -242.4, 65.0, -308.0)
ctx.bezierCurveTo(73.2, -314.3, 85.5, -326.5, 89.8, -345.1)
ctx.bezierCurveTo(93.0, -359.0, 91.2, -373.9, 84.4, -389.6)
ctx.bezierCurveTo(84.4, -389.6, 84.4, -389.7, 84.4, -389.7)
ctx.bezierCurveTo(83.9, -390.8, 83.4, -391.9, 82.9, -393.0)
ctx.bezierCurveTo(82.8, -393.2, 82.7, -393.3, 82.7, -393.5)
ctx.bezierCurveTo(81.3, -396.4, 79.8, -399.3, 78.0, -402.2)
ctx.bezierCurveTo(77.6, -402.9, 77.2, -403.6, 76.8, -404.3)
ctx.bezierCurveTo(76.4, -404.9, 76.0, -405.6, 75.6, -406.2)
ctx.bezierCurveTo(75.1, -407.0, 74.5, -407.9, 74.0, -408.7)
ctx.bezierCurveTo(73.7, -409.2, 73.3, -409.7, 73.0, -410.3)
ctx.bezierCurveTo(72.9, -410.5, 72.8, -410.6, 72.7, -410.8)
ctx.bezierCurveTo(85.1, -427.4, 91.9, -447.7, 91.9, -468.6)
ctx.bezierCurveTo(91.9, -521.7, 48.7, -565.0, -4.5, -565.0)
ctx.bezierCurveTo(-57.7, -565.0, -100.9, -521.8, -100.9, -468.6)
ctx.bezierCurveTo(-100.9, -447.8, -94.1, -427.4, -81.7, -410.8)
ctx.bezierCurveTo(-81.8, -410.6, -81.9, -410.5, -82.0, -410.3)
ctx.bezierCurveTo(-82.3, -409.8, -82.6, -409.3, -83.0, -408.9)
ctx.bezierCurveTo(-83.6, -408.0, -84.2, -407.1, -84.7, -406.3)
ctx.bezierCurveTo(-85.1, -405.7, -85.5, -405.1, -85.8, -404.5)
ctx.bezierCurveTo(-86.2, -403.8, -86.7, -403.1, -87.1, -402.3)
ctx.bezierCurveTo(-88.8, -399.4, -90.3, -396.5, -91.7, -393.7)
ctx.bezierCurveTo(-91.8, -393.5, -91.9, -393.4, -92.0, -393.2)
ctx.bezierCurveTo(-92.5, -392.1, -93.0, -391.0, -93.5, -389.9)
ctx.bezierCurveTo(-93.5, -389.9, -93.5, -389.8, -93.6, -389.8)
ctx.bezierCurveTo(-100.4, -374.2, -102.2, -359.3, -99.0, -345.3)
ctx.bezierCurveTo(-92.4, -317.1, -67.6, -303.6, -66.6, -303.1)
ctx.bezierCurveTo(-66.2, -302.9, -65.8, -302.7, -65.3, -302.6)
ctx.bezierCurveTo(-66.8, -241.1, -92.0, -215.4, -114.3, -192.6)
ctx.bezierCurveTo(-128.7, -177.6, -142.4, -163.5, -144.7, -142.2)
ctx.bezierCurveTo(-148.6, -106.2, -130.6, -91.6, -122.3, -86.9)
ctx.lineTo(-122.3, -49.8)
ctx.bezierCurveTo(-122.3, -46.5, -119.6, -43.9, -116.4, -43.9)
ctx.lineTo(116.5, -43.9)
ctx.bezierCurveTo(119.8, -43.9, 122.4, -46.6, 122.4, -49.8)
ctx.lineTo(122.4, -86.9)
ctx.bezierCurveTo(130.6, -91.6, 148.7, -106.3, 144.8, -142.2)
ctx.bezierCurveTo(142.4, -163.5, 128.6, -177.6, 114.1, -192.4)
}
let fillPawn = ctx =>
{
ctx.moveTo(62.4, -416.8)
ctx.bezierCurveTo(73.8, -431.5, 80.0, -449.8, 80.0, -468.5)
ctx.bezierCurveTo(80.0, -515.1, 42.1, -553.0, -4.5, -553.0)
ctx.bezierCurveTo(-51.1, -553.0, -89.0, -515.1, -89.0, -468.5)
ctx.bezierCurveTo(-89.0, -449.8, -82.8, -431.6, -71.4, -416.8)
ctx.lineTo(62.4, -416.8)
ctx.moveTo(73.7, -384.6)
ctx.bezierCurveTo(73.7, -384.6, 73.7, -384.6, 73.7, -384.6)
ctx.bezierCurveTo(73.3, -385.4, 73.0, -386.2, 72.6, -387.0)
ctx.bezierCurveTo(72.5, -387.1, 72.5, -387.2, 72.4, -387.4)
ctx.bezierCurveTo(71.8, -388.7, 71.2, -390.0, 70.5, -391.3)
ctx.bezierCurveTo(70.3, -391.7, 70.1, -392.1, 69.8, -392.6)
ctx.bezierCurveTo(69.5, -393.2, 69.2, -393.7, 68.9, -394.3)
ctx.bezierCurveTo(68.5, -395.0, 68.1, -395.7, 67.7, -396.4)
ctx.bezierCurveTo(67.4, -396.9, 67.1, -397.4, 66.8, -398.0)
ctx.bezierCurveTo(66.3, -398.9, 65.7, -399.7, 65.2, -400.6)
ctx.bezierCurveTo(65.0, -401.0, 64.7, -401.3, 64.5, -401.7)
ctx.bezierCurveTo(63.8, -402.8, 63.0, -403.9, 62.2, -405.1)
ctx.lineTo(-71.2, -405.1)
ctx.bezierCurveTo(-72.0, -404.0, -72.7, -402.8, -73.5, -401.7)
ctx.bezierCurveTo(-73.7, -401.3, -74.0, -401.0, -74.2, -400.6)
ctx.bezierCurveTo(-74.8, -399.7, -75.3, -398.9, -75.8, -398.0)
ctx.bezierCurveTo(-76.1, -397.5, -76.4, -397.0, -76.7, -396.5)
ctx.bezierCurveTo(-77.1, -395.8, -77.5, -395.1, -77.9, -394.3)
ctx.bezierCurveTo(-78.2, -393.7, -78.5, -393.2, -78.8, -392.6)
ctx.bezierCurveTo(-79.0, -392.2, -79.2, -391.8, -79.5, -391.3)
ctx.bezierCurveTo(-80.2, -390.0, -80.8, -388.7, -81.4, -387.4)
ctx.bezierCurveTo(-81.5, -387.3, -81.5, -387.2, -81.6, -387.0)
ctx.bezierCurveTo(-82.0, -386.2, -82.3, -385.4, -82.7, -384.6)
ctx.bezierCurveTo(-82.7, -384.6, -82.7, -384.6, -82.7, -384.6)
ctx.bezierCurveTo(-85.5, -378.0, -87.3, -371.6, -88.1, -365.5)
ctx.lineTo(79.1, -365.5)
ctx.bezierCurveTo(78.3, -371.6, 76.5, -378.0, 73.7, -384.6)
ctx.moveTo(-59.1, -314.1)
ctx.lineTo(53.0, -314.1)
ctx.bezierCurveTo(57.5, -316.9, 73.8, -328.2, 78.3, -348.0)
ctx.bezierCurveTo(78.7, -349.9, 79.0, -351.7, 79.2, -353.6)
ctx.lineTo(-88.2, -353.6)
ctx.bezierCurveTo(-88.0, -351.7, -87.7, -349.8, -87.3, -348.0)
ctx.bezierCurveTo(-82.8, -328.2, -66.5, -316.9, -62.0, -314.1)
ctx.lineTo(-59.1, -314.1)
ctx.moveTo(105.6, -184.1)
ctx.bezierCurveTo(82.9, -207.3, 54.8, -235.9, 53.2, -302.2)
ctx.lineTo(-53.3, -302.2)
ctx.bezierCurveTo(-54.9, -236.0, -83.0, -207.3, -105.7, -184.1)
ctx.bezierCurveTo(-119.9, -169.6, -131.1, -158.1, -133.0, -140.9)
ctx.bezierCurveTo(-136.5, -108.7, -119.3, -98.4, -115.3, -96.4)
ctx.lineTo(115.1, -96.4)
ctx.bezierCurveTo(119.2, -98.4, 136.3, -108.7, 132.8, -140.9)
ctx.bezierCurveTo(131.0, -158.2, 119.8, -169.6, 105.6, -184.1)
ctx.moveTo(-110.5, -55.7)
ctx.lineTo(110.5, -55.7)
ctx.lineTo(110.5, -84.6)
ctx.lineTo(-110.5, -84.6)
}
let strokeRook = ctx =>
{
ctx.moveTo(145.1, -483.3)
ctx.lineTo(75.3, -483.3)
ctx.bezierCurveTo(72.5, -483.3, 70.0, -481.3, 69.5, -478.5)
ctx.lineTo(56.0, -410.8)
ctx.lineTo(45.1, -410.8)
ctx.lineTo(52.9, -476.7)
ctx.bezierCurveTo(53.1, -478.4, 52.6, -480.1, 51.4, -481.3)
ctx.bezierCurveTo(50.3, -482.6, 48.7, -483.3, 47.0, -483.3)
ctx.lineTo(-47.3, -483.3)
ctx.bezierCurveTo(-49.0, -483.3, -50.6, -482.6, -51.7, -481.3)
ctx.bezierCurveTo(-52.8, -480.0, -53.4, -478.3, -53.2, -476.7)
ctx.lineTo(-45.4, -410.8)
ctx.lineTo(-56.0, -410.8)
ctx.lineTo(-69.4, -478.6)
ctx.bezierCurveTo(-70.0, -481.4, -72.4, -483.4, -75.2, -483.4)
ctx.lineTo(-145.0, -483.4)
ctx.bezierCurveTo(-146.8, -483.4, -148.5, -482.6, -149.7, -481.1)
ctx.bezierCurveTo(-150.8, -479.7, -151.2, -477.8, -150.8, -476.0)
ctx.lineTo(-121.2, -358.1)
ctx.bezierCurveTo(-120.5, -355.5, -118.2, -353.6, -115.5, -353.6)
ctx.lineTo(-105.8, -353.6)
ctx.lineTo(-83.2, -305.6)
ctx.bezierCurveTo(-82.2, -303.5, -80.1, -302.2, -77.8, -302.2)
ctx.lineTo(-65.0, -302.2)
ctx.bezierCurveTo(-66.5, -240.9, -91.7, -215.2, -114.0, -192.4)
ctx.bezierCurveTo(-128.6, -177.5, -142.3, -163.5, -144.6, -142.2)
ctx.bezierCurveTo(-148.5, -106.2, -130.5, -91.6, -122.2, -86.9)
ctx.lineTo(-122.2, -49.8)
ctx.bezierCurveTo(-122.2, -46.5, -119.5, -43.9, -116.3, -43.9)
ctx.lineTo(116.6, -43.9)
ctx.bezierCurveTo(119.9, -43.9, 122.5, -46.6, 122.5, -49.8)
ctx.lineTo(122.5, -86.9)
ctx.bezierCurveTo(130.7, -91.6, 148.8, -106.3, 144.9, -142.2)
ctx.bezierCurveTo(142.6, -163.5, 128.8, -177.6, 114.3, -192.4)
ctx.bezierCurveTo(92.0, -215.2, 66.8, -240.9, 65.3, -302.2)
ctx.lineTo(78.1, -302.2)
ctx.bezierCurveTo(80.4, -302.2, 82.5, -303.5, 83.5, -305.6)
ctx.lineTo(106.1, -353.6)
ctx.lineTo(115.8, -353.6)
ctx.bezierCurveTo(118.5, -353.6, 120.9, -355.4, 121.5, -358.1)
ctx.lineTo(150.8, -476.0)
ctx.bezierCurveTo(151.2, -477.8, 150.8, -479.6, 149.7, -481.1)
ctx.bezierCurveTo(148.6, -482.5, 146.9, -483.3, 145.1, -483.3)
}
let fillRook = ctx =>
{
ctx.moveTo(66.7, -403.7)
ctx.bezierCurveTo(66.1, -400.9, 63.7, -398.9, 60.9, -398.9)
ctx.lineTo(38.5, -398.9)
ctx.bezierCurveTo(36.8, -398.9, 35.2, -399.6, 34.1, -400.9)
ctx.bezierCurveTo(33.0, -402.2, 32.4, -403.9, 32.6, -405.5)
ctx.lineTo(40.4, -471.4)
ctx.lineTo(-40.5, -471.4)
ctx.lineTo(-32.7, -405.5)
ctx.bezierCurveTo(-32.5, -403.8, -33.0, -402.1, -34.2, -400.9)
ctx.bezierCurveTo(-35.3, -399.6, -36.9, -398.9, -38.6, -398.9)
ctx.lineTo(-61.0, -398.9)
ctx.bezierCurveTo(-63.8, -398.9, -66.3, -400.9, -66.8, -403.7)
ctx.lineTo(-80.2, -471.5)
ctx.lineTo(-137.6, -471.5)
ctx.lineTo(-111.0, -365.4)
ctx.lineTo(-102.2, -365.4)
ctx.lineTo(102.0, -365.4)
ctx.lineTo(110.8, -365.4)
ctx.lineTo(137.4, -471.5)
ctx.lineTo(80.0, -471.5)
ctx.lineTo(66.7, -403.7)
ctx.moveTo(-74.2, -314.1)
ctx.lineTo(-59.1, -314.1)
ctx.lineTo(59.1, -314.1)
ctx.lineTo(74.2, -314.1)
ctx.lineTo(92.8, -353.6)
ctx.lineTo(-92.8, -353.6)
ctx.moveTo(-53.3, -302.2)
ctx.bezierCurveTo(-54.9, -236.0, -83.0, -207.3, -105.7, -184.1)
ctx.bezierCurveTo(-119.9, -169.6, -131.1, -158.1, -133.0, -140.9)
ctx.bezierCurveTo(-136.5, -108.7, -119.3, -98.4, -115.3, -96.4)
ctx.lineTo(115.1, -96.4)
ctx.bezierCurveTo(119.2, -98.4, 136.3, -108.7, 132.8, -140.9)
ctx.bezierCurveTo(130.9, -158.2, 119.7, -169.6, 105.5, -184.1)
ctx.bezierCurveTo(82.8, -207.3, 54.7, -235.9, 53.1, -302.2)
ctx.lineTo(-53.3, -302.2)
ctx.moveTo(-110.5, -55.7)
ctx.lineTo(110.5, -55.7)
ctx.lineTo(110.5, -84.6)
ctx.lineTo(-110.5, -84.6)
}
let strokeKnight = ctx =>
{
ctx.moveTo(183.9, -287.0)
ctx.bezierCurveTo(154.0, -301.4, 152.3, -317.7, 155.0, -364.6)
ctx.bezierCurveTo(155.2, -368.8, 155.6, -373.3, 155.9, -378.2)
ctx.bezierCurveTo(159.6, -430.2, 165.7, -517.1, 105.7, -563.5)
ctx.bezierCurveTo(39.2, -615.0, -34.4, -595.0, -43.2, -590.2)
ctx.bezierCurveTo(-50.1, -586.4, -52.7, -573.4, -56.7, -546.7)
ctx.bezierCurveTo(-58.0, -538.3, -59.4, -528.7, -60.6, -525.9)
ctx.bezierCurveTo(-63.3, -519.6, -81.0, -508.4, -97.3, -502.6)
ctx.bezierCurveTo(-129.5, -500.9, -155.2, -481.6, -166.1, -450.9)
ctx.bezierCurveTo(-172.9, -431.9, -171.9, -413.6, -163.9, -406.5)
ctx.bezierCurveTo(-162.8, -405.5, -161.4, -405.0, -160.0, -405.0)
ctx.lineTo(-127.2, -405.0)
ctx.bezierCurveTo(-124.7, -395.2, -118.3, -387.6, -109.2, -383.6)
ctx.bezierCurveTo(-97.0, -378.3, -82.1, -380.3, -70.4, -388.9)
ctx.bezierCurveTo(-61.2, -395.7, -50.6, -394.4, -43.5, -392.1)
ctx.bezierCurveTo(-69.1, -370.6, -150.3, -298.8, -155.1, -248.7)
ctx.bezierCurveTo(-159.3, -204.3, -139.2, -185.4, -127.5, -178.2)
ctx.bezierCurveTo(-136.9, -167.2, -143.3, -156.4, -144.8, -142.2)
ctx.bezierCurveTo(-148.7, -106.2, -130.7, -91.6, -122.4, -86.9)
ctx.lineTo(-122.4, -49.8)
ctx.bezierCurveTo(-122.4, -46.5, -119.7, -43.9, -116.5, -43.9)
ctx.lineTo(116.4, -43.9)
ctx.bezierCurveTo(119.7, -43.9, 122.3, -46.6, 122.3, -49.8)
ctx.lineTo(122.3, -86.9)
ctx.bezierCurveTo(130.5, -91.6, 148.6, -106.3, 144.7, -142.2)
ctx.bezierCurveTo(143.0, -157.7, 135.6, -169.2, 124.7, -181.2)
ctx.bezierCurveTo(131.5, -198.1, 127.8, -209.4, 124.2, -215.4)
ctx.lineTo(185.5, -277.6)
ctx.bezierCurveTo(186.8, -279.0, 187.4, -280.9, 187.1, -282.8)
ctx.bezierCurveTo(186.9, -284.6, 185.6, -286.2, 183.9, -287.0)
}
let fillKnight = ctx =>
{
ctx.moveTo(143.2, -365.3)
ctx.bezierCurveTo(143.4, -369.5, 143.8, -374.1, 144.1, -379.1)
ctx.bezierCurveTo(147.6, -428.7, 153.5, -511.7, 98.5, -554.2)
ctx.bezierCurveTo(38.6, -600.5, -28.3, -584.3, -37.2, -579.9)
ctx.bezierCurveTo(-40.3, -576.1, -43.3, -555.9, -45.0, -544.9)
ctx.bezierCurveTo(-45.6, -541.2, -46.0, -537.9, -46.5, -535.1)
ctx.bezierCurveTo(-17.4, -548.6, 10.7, -542.9, 24.0, -538.8)
ctx.bezierCurveTo(25.2, -549.4, 28.9, -557.7, 35.0, -563.4)
ctx.bezierCurveTo(44.0, -571.8, 54.9, -571.2, 55.4, -571.2)
ctx.bezierCurveTo(58.0, -571.0, 60.2, -569.2, 60.8, -566.6)
ctx.lineTo(74.8, -506.9)
ctx.bezierCurveTo(83.3, -500.1, 117.1, -470.0, 113.3, -417.9)
ctx.bezierCurveTo(111.2, -389.3, 100.6, -365.5, 91.2, -344.5)
ctx.bezierCurveTo(81.9, -323.7, 73.8, -305.8, 75.7, -287.7)
ctx.bezierCurveTo(78.7, -258.5, 105.7, -232.8, 116.0, -223.9)
ctx.lineTo(171.5, -280.2)
ctx.bezierCurveTo(140.9, -298.0, 140.7, -322.5, 143.2, -365.3)
ctx.moveTo(113.9, -186.0)
ctx.bezierCurveTo(120.5, -202.7, 113.5, -210.4, 112.6, -211.4)
ctx.bezierCurveTo(108.6, -214.5, 68.1, -246.7, 64.0, -286.5)
ctx.bezierCurveTo(61.8, -307.7, 70.9, -327.9, 80.5, -349.4)
ctx.bezierCurveTo(89.9, -370.5, 99.7, -392.2, 101.6, -418.8)
ctx.bezierCurveTo(105.3, -470.4, 66.6, -498.4, 66.2, -498.7)
ctx.bezierCurveTo(65.0, -499.5, 64.2, -500.8, 63.8, -502.2)
ctx.lineTo(50.5, -558.9)
ctx.bezierCurveTo(48.3, -558.3, 45.5, -557.1, 43.0, -554.7)
ctx.bezierCurveTo(38.0, -549.9, 35.4, -541.8, 35.4, -530.6)
ctx.bezierCurveTo(35.4, -528.6, 34.4, -526.7, 32.7, -525.6)
ctx.bezierCurveTo(31.0, -524.5, 28.9, -524.4, 27.0, -525.2)
ctx.bezierCurveTo(26.6, -525.4, -13.4, -543.0, -50.7, -519.5)
ctx.bezierCurveTo(-57.5, -507.6, -80.6, -496.0, -94.2, -491.2)
ctx.bezierCurveTo(-94.7, -491.0, -95.3, -490.9, -95.9, -490.9)
ctx.bezierCurveTo(-135.7, -489.2, -150.5, -459.7, -155.0, -447.0)
ctx.bezierCurveTo(-160.1, -432.7, -159.2, -421.3, -157.1, -416.9)
ctx.lineTo(-122.9, -416.9)
ctx.lineTo(-84.5, -424.2)
ctx.bezierCurveTo(-81.3, -424.8, -78.2, -422.7, -77.6, -419.5)
ctx.bezierCurveTo(-77.0, -416.3, -79.1, -413.2, -82.3, -412.6)
ctx.lineTo(-115.3, -406.3)
ctx.bezierCurveTo(-113.4, -400.9, -109.8, -396.8, -104.6, -394.5)
ctx.bezierCurveTo(-96.4, -390.9, -85.8, -392.5, -77.6, -398.5)
ctx.bezierCurveTo(-55.9, -414.5, -30.6, -399.6, -29.4, -398.8)
ctx.bezierCurveTo(-28.6, -398.3, 6.8, -377.9, 26.2, -397.9)
ctx.bezierCurveTo(28.5, -400.2, 32.2, -400.3, 34.6, -398.0)
ctx.bezierCurveTo(36.9, -395.7, 37.0, -392.0, 34.7, -389.6)
ctx.bezierCurveTo(25.6, -380.3, 14.6, -377.2, 3.9, -377.2)
ctx.bezierCurveTo(-11.1, -377.2, -25.3, -383.3, -31.8, -386.6)
ctx.bezierCurveTo(-49.5, -372.0, -138.9, -295.8, -143.5, -247.6)
ctx.bezierCurveTo(-148.0, -200.8, -121.7, -187.9, -117.0, -186.0)
ctx.lineTo(113.9, -186.0)
ctx.moveTo(-115.2, -174.1)
ctx.bezierCurveTo(-125.1, -163.2, -131.5, -153.6, -132.9, -140.9)
ctx.bezierCurveTo(-136.4, -108.8, -119.3, -98.4, -115.2, -96.4)
ctx.lineTo(115.2, -96.4)
ctx.bezierCurveTo(119.3, -98.4, 136.4, -108.7, 132.9, -140.9)
ctx.bezierCurveTo(131.5, -153.7, 125.1, -163.3, 115.2, -174.1)
ctx.lineTo(-115.2, -174.1)
ctx.moveTo(-110.5, -55.7)
ctx.lineTo(110.5, -55.7)
ctx.lineTo(110.5, -84.6)
ctx.lineTo(-110.5, -84.6)
}
let strokeBishop = ctx =>
{
ctx.moveTo(112.6, -212.0)
ctx.bezierCurveTo(87.4, -253.8, 56.2, -305.6, 54.4, -370.3)
ctx.lineTo(57.5, -370.3)
ctx.bezierCurveTo(58.3, -370.3, 59.2, -370.5, 59.9, -370.8)
ctx.bezierCurveTo(61.0, -371.3, 86.7, -383.0, 92.4, -408.1)
ctx.bezierCurveTo(94.9, -419.3, 92.9, -431.2, 86.6, -443.6)
ctx.bezierCurveTo(86.6, -443.6, 86.6, -443.6, 86.6, -443.7)
ctx.bezierCurveTo(85.3, -446.3, 83.7, -448.9, 82.0, -451.5)
ctx.bezierCurveTo(81.8, -451.9, 81.6, -452.2, 81.3, -452.6)
ctx.bezierCurveTo(80.9, -453.2, 80.5, -453.8, 80.1, -454.4)
ctx.bezierCurveTo(79.7, -455.0, 79.3, -455.5, 78.9, -456.1)
ctx.bezierCurveTo(78.5, -456.6, 78.2, -457.1, 77.8, -457.6)
ctx.bezierCurveTo(77.4, -458.1, 77.0, -458.7, 76.6, -459.2)
ctx.bezierCurveTo(85.8, -466.7, 102.1, -486.0, 102.1, -527.7)
ctx.bezierCurveTo(102.1, -546.2, 95.1, -565.4, 81.2, -584.6)
ctx.bezierCurveTo(79.3, -587.2, 75.7, -587.8, 73.0, -586.0)
ctx.lineTo(30.9, -556.7)
ctx.lineTo(61.3, -600.7)
ctx.bezierCurveTo(62.9, -603.1, 62.6, -606.3, 60.6, -608.3)
ctx.bezierCurveTo(52.9, -615.7, 45.9, -621.5, 41.1, -625.1)
ctx.bezierCurveTo(47.1, -633.6, 50.4, -643.7, 50.4, -654.1)
ctx.bezierCurveTo(50.4, -681.8, 27.9, -704.4, 0.1, -704.4)
ctx.bezierCurveTo(-27.6, -704.4, -50.2, -681.9, -50.2, -654.1)
ctx.bezierCurveTo(-50.2, -643.6, -46.9, -633.6, -40.9, -625.1)
ctx.bezierCurveTo(-58.3, -612.0, -102.0, -574.3, -102.0, -527.8)
ctx.bezierCurveTo(-102.0, -486.1, -85.7, -466.9, -76.5, -459.3)
ctx.bezierCurveTo(-76.9, -458.8, -77.3, -458.2, -77.7, -457.7)
ctx.bezierCurveTo(-78.1, -457.2, -78.5, -456.7, -78.8, -456.2)
ctx.bezierCurveTo(-79.2, -455.6, -79.6, -455.1, -80.0, -454.5)
ctx.bezierCurveTo(-80.4, -453.9, -80.8, -453.3, -81.2, -452.7)
ctx.bezierCurveTo(-81.4, -452.3, -81.7, -452.0, -81.9, -451.6)
ctx.bezierCurveTo(-83.6, -449.0, -85.1, -446.4, -86.5, -443.8)
ctx.bezierCurveTo(-86.5, -443.8, -86.5, -443.7, -86.5, -443.7)
ctx.bezierCurveTo(-92.8, -431.3, -94.8, -419.5, -92.3, -408.2)
ctx.bezierCurveTo(-86.7, -383.1, -60.9, -371.4, -59.8, -370.9)
ctx.bezierCurveTo(-59.0, -370.6, -58.2, -370.4, -57.4, -370.4)
ctx.lineTo(-54.3, -370.4)
ctx.bezierCurveTo(-56.1, -305.7, -87.3, -253.9, -112.5, -212.1)
ctx.bezierCurveTo(-128.6, -185.4, -142.5, -162.4, -144.6, -142.3)
ctx.bezierCurveTo(-148.5, -106.3, -130.5, -91.7, -122.2, -87.0)
ctx.lineTo(-122.2, -49.9)
ctx.bezierCurveTo(-122.2, -46.6, -119.5, -44.0, -116.3, -44.0)
ctx.lineTo(116.5, -44.0)
ctx.bezierCurveTo(119.8, -44.0, 122.4, -46.7, 122.4, -49.9)
ctx.lineTo(122.4, -87.0)
ctx.bezierCurveTo(130.6, -91.7, 148.7, -106.4, 144.8, -142.3)
ctx.bezierCurveTo(142.6, -162.3, 128.7, -185.3, 112.6, -212.0)
}
let fillBishop = ctx =>
{
ctx.moveTo(30.3, -630.2)
ctx.bezierCurveTo(35.6, -637.0, 38.5, -645.2, 38.5, -653.8)
ctx.bezierCurveTo(38.5, -675.0, 21.3, -692.2, 0.1, -692.2)
ctx.bezierCurveTo(-21.1, -692.2, -38.3, -675.0, -38.3, -653.8)
ctx.bezierCurveTo(-38.3, -645.2, -35.4, -636.9, -30.1, -630.2)
ctx.lineTo(30.3, -630.2)
ctx.moveTo(-66.3, -466.2)
ctx.lineTo(66.3, -466.2)
ctx.bezierCurveTo(71.1, -469.2, 90.2, -483.9, 90.2, -527.5)
ctx.bezierCurveTo(90.2, -542.0, 85.0, -557.2, 74.8, -572.6)
ctx.lineTo(10.7, -528.0)
ctx.bezierCurveTo(8.4, -526.4, 5.2, -526.6, 3.1, -528.7)
ctx.bezierCurveTo(1.1, -530.7, 0.8, -533.9, 2.4, -536.3)
ctx.lineTo(48.5, -603.0)
ctx.bezierCurveTo(40.0, -610.9, 32.7, -616.3, 29.7, -618.4)
ctx.lineTo(-29.9, -618.4)
ctx.bezierCurveTo(-38.7, -612.1, -90.3, -573.5, -90.3, -527.6)
ctx.bezierCurveTo(-90.1, -483.9, -70.9, -469.2, -66.3, -466.2)
ctx.moveTo(75.8, -438.8)
ctx.bezierCurveTo(75.8, -438.8, 75.8, -438.8, 75.8, -438.8)
ctx.bezierCurveTo(74.5, -441.3, 73.0, -443.8, 71.3, -446.3)
ctx.bezierCurveTo(71.2, -446.5, 71.0, -446.7, 70.9, -446.9)
ctx.bezierCurveTo(70.2, -447.9, 69.5, -448.9, 68.7, -449.9)
ctx.bezierCurveTo(68.5, -450.2, 68.3, -450.5, 68.1, -450.8)
ctx.bezierCurveTo(67.2, -452.0, 66.2, -453.2, 65.2, -454.4)
ctx.lineTo(-65.1, -454.4)
ctx.bezierCurveTo(-66.1, -453.2, -67.1, -452.0, -68.0, -450.8)
ctx.bezierCurveTo(-68.2, -450.5, -68.4, -450.2, -68.7, -449.9)
ctx.bezierCurveTo(-69.4, -448.9, -70.1, -447.9, -70.8, -447.0)
ctx.bezierCurveTo(-71.0, -446.8, -71.1, -446.5, -71.3, -446.3)
ctx.bezierCurveTo(-73.0, -443.8, -74.5, -441.3, -75.8, -438.9)
ctx.bezierCurveTo(-75.8, -438.9, -75.8, -438.8, -75.9, -438.8)
ctx.bezierCurveTo(-78.5, -433.8, -80.3, -428.9, -81.1, -424.2)
ctx.lineTo(80.8, -424.2)
ctx.bezierCurveTo(80.2, -428.9, 78.4, -433.7, 75.8, -438.8)
ctx.moveTo(48.4, -382.1)
ctx.lineTo(56.2, -382.1)
ctx.bezierCurveTo(60.6, -384.4, 77.2, -394.0, 80.9, -410.7)
ctx.bezierCurveTo(81.0, -411.2, 81.1, -411.8, 81.2, -412.3)
ctx.lineTo(-81.0, -412.3)
ctx.bezierCurveTo(-80.9, -411.7, -80.8, -411.2, -80.7, -410.6)
ctx.bezierCurveTo(-76.9, -393.8, -60.4, -384.3, -56.0, -382.1)
ctx.lineTo(-48.2, -382.1)
ctx.lineTo(48.4, -382.1)
ctx.moveTo(102.5, -205.9)
ctx.bezierCurveTo(76.5, -249.0, 44.4, -302.3, 42.6, -370.3)
ctx.lineTo(-42.4, -370.3)
ctx.bezierCurveTo(-44.2, -302.4, -76.3, -249.0, -102.3, -205.9)
ctx.bezierCurveTo(-117.7, -180.4, -130.9, -158.4, -132.8, -140.9)
ctx.bezierCurveTo(-136.3, -108.7, -119.1, -98.4, -115.1, -96.4)
ctx.lineTo(115.3, -96.4)
ctx.bezierCurveTo(119.4, -98.4, 136.5, -108.7, 133.0, -140.9)
ctx.bezierCurveTo(131.1, -158.4, 117.8, -180.4, 102.5, -205.9)
ctx.moveTo(-110.5, -55.7)
ctx.lineTo(110.5, -55.7)
ctx.lineTo(110.5, -84.6)
ctx.lineTo(-110.5, -84.6)
}
let strokeQueen = ctx =>
{
ctx.moveTo(112.6, -212.0)
ctx.bezierCurveTo(87.4, -253.8, 56.2, -305.6, 54.4, -370.3)
ctx.lineTo(57.5, -370.3)
ctx.bezierCurveTo(58.3, -370.3, 59.2, -370.5, 59.9, -370.8)
ctx.bezierCurveTo(61.0, -371.3, 84.7, -382.1, 91.6, -405.2)
ctx.lineTo(117.3, -405.2)
ctx.bezierCurveTo(118.9, -405.2, 120.4, -405.8, 121.5, -407.0)
ctx.bezierCurveTo(122.6, -408.1, 123.2, -409.7, 123.2, -411.2)
ctx.bezierCurveTo(122.9, -430.1, 113.6, -450.4, 95.5, -471.4)
ctx.bezierCurveTo(94.4, -472.7, 92.7, -473.5, 91.0, -473.5)
ctx.lineTo(75.8, -473.5)
ctx.bezierCurveTo(78.0, -491.7, 87.0, -545.3, 120.4, -575.7)
ctx.bezierCurveTo(121.9, -577.1, 122.6, -579.2, 122.2, -581.2)
ctx.bezierCurveTo(121.8, -583.2, 120.4, -584.9, 118.5, -585.6)
ctx.bezierCurveTo(118.0, -585.8, 106.5, -590.1, 91.9, -590.9)
ctx.bezierCurveTo(89.2, -604.4, 78.7, -640.6, 42.8, -656.2)
ctx.bezierCurveTo(43.0, -657.8, 43.1, -659.4, 43.1, -661.1)
ctx.bezierCurveTo(43.1, -684.9, 23.7, -704.3, -0.1, -704.3)
ctx.bezierCurveTo(-23.9, -704.3, -43.3, -684.9, -43.3, -661.1)
ctx.bezierCurveTo(-43.3, -659.5, -43.2, -657.8, -43.0, -656.2)
ctx.bezierCurveTo(-78.9, -640.6, -89.3, -604.4, -92.1, -590.9)
ctx.bezierCurveTo(-106.7, -590.1, -118.2, -585.8, -118.7, -585.6)
ctx.bezierCurveTo(-120.6, -584.9, -122.0, -583.2, -122.4, -581.2)
ctx.bezierCurveTo(-122.8, -579.2, -122.1, -577.1, -120.6, -575.7)
ctx.bezierCurveTo(-87.2, -545.3, -78.1, -491.7, -76.0, -473.5)
ctx.lineTo(-91.2, -473.5)
ctx.bezierCurveTo(-92.9, -473.5, -94.6, -472.8, -95.7, -471.4)
ctx.bezierCurveTo(-113.8, -450.4, -123.2, -430.1, -123.4, -411.2)
ctx.bezierCurveTo(-123.4, -409.6, -122.8, -408.1, -121.7, -407.0)
ctx.bezierCurveTo(-120.6, -405.9, -119.1, -405.2, -117.5, -405.2)
ctx.lineTo(-91.8, -405.2)
ctx.bezierCurveTo(-85.0, -382.1, -61.2, -371.3, -60.1, -370.8)
ctx.bezierCurveTo(-59.3, -370.5, -58.5, -370.3, -57.7, -370.3)
ctx.lineTo(-54.6, -370.3)
ctx.bezierCurveTo(-56.4, -305.6, -87.6, -253.8, -112.8, -212.0)
ctx.bezierCurveTo(-128.9, -185.3, -142.8, -162.3, -144.9, -142.2)
ctx.bezierCurveTo(-148.8, -106.2, -130.8, -91.6, -122.5, -86.9)
ctx.lineTo(-122.5, -49.8)
ctx.bezierCurveTo(-122.5, -46.5, -119.8, -43.9, -116.6, -43.9)
ctx.lineTo(116.3, -43.9)
ctx.bezierCurveTo(119.6, -43.9, 122.2, -46.6, 122.2, -49.8)
ctx.lineTo(122.2, -86.9)
ctx.bezierCurveTo(130.4, -91.6, 148.5, -106.3, 144.6, -142.2)
ctx.bezierCurveTo(142.6, -162.3, 128.7, -185.3, 112.6, -212.0)
}
let fillQueen = ctx =>
{
ctx.moveTo(0.0, -629.7)
ctx.bezierCurveTo(17.3, -629.7, 31.3, -643.7, 31.3, -661.0)
ctx.bezierCurveTo(31.3, -678.3, 17.3, -692.3, 0.0, -692.3)
ctx.bezierCurveTo(-17.3, -692.3, -31.3, -678.3, -31.3, -661.0)
ctx.bezierCurveTo(-31.3, -643.7, -17.2, -629.7, 0.0, -629.7)
ctx.moveTo(-44.7, -573.4)
ctx.bezierCurveTo(-36.7, -582.0, -20.2, -597.2, -0.6, -599.3)
ctx.bezierCurveTo(-0.2, -599.3, 0.3, -599.3, 0.7, -599.3)
ctx.bezierCurveTo(20.3, -597.2, 36.8, -582.0, 44.8, -573.4)
ctx.bezierCurveTo(53.3, -583.3, 65.2, -589.2, 79.9, -590.6)
ctx.bezierCurveTo(76.9, -603.2, 67.3, -631.5, 39.9, -644.4)
ctx.bezierCurveTo(33.4, -628.8, 18.0, -617.8, 0.1, -617.8)
ctx.bezierCurveTo(-17.8, -617.8, -33.2, -628.8, -39.7, -644.4)
ctx.bezierCurveTo(-67.2, -631.4, -76.7, -603.2, -79.7, -590.6)
ctx.bezierCurveTo(-65.1, -589.1, -53.2, -583.3, -44.7, -573.4)
ctx.moveTo(63.9, -473.4)
ctx.bezierCurveTo(65.7, -490.5, 73.7, -542.3, 105.2, -577.0)
ctx.bezierCurveTo(100.5, -578.1, 94.3, -579.0, 87.7, -579.1)
ctx.bezierCurveTo(87.7, -579.1, 87.7, -579.1, 87.7, -579.1)
ctx.bezierCurveTo(87.5, -579.1, 87.2, -579.1, 87.0, -579.1)
ctx.bezierCurveTo(86.9, -579.1, 86.7, -579.1, 86.6, -579.1)
ctx.bezierCurveTo(69.9, -579.0, 57.6, -572.8, 50.2, -560.8)
ctx.bezierCurveTo(49.2, -559.1, 47.4, -558.1, 45.4, -558.0)
ctx.bezierCurveTo(43.4, -557.9, 41.6, -558.8, 40.4, -560.3)
ctx.bezierCurveTo(40.2, -560.5, 21.7, -584.7, -0.0, -587.5)
ctx.bezierCurveTo(-21.6, -584.7, -40.2, -560.6, -40.4, -560.3)
ctx.bezierCurveTo(-41.6, -558.7, -43.5, -557.9, -45.4, -558.0)
ctx.bezierCurveTo(-47.4, -558.1, -49.1, -559.1, -50.2, -560.8)
ctx.bezierCurveTo(-57.6, -572.8, -69.9, -579.0, -86.6, -579.1)
ctx.bezierCurveTo(-86.7, -579.1, -86.9, -579.1, -87.0, -579.1)
ctx.bezierCurveTo(-87.2, -579.1, -87.5, -579.1, -87.7, -579.1)
ctx.bezierCurveTo(-87.7, -579.1, -87.7, -579.1, -87.7, -579.1)
ctx.bezierCurveTo(-94.3, -579.1, -100.5, -578.1, -105.2, -577.0)
ctx.bezierCurveTo(-73.7, -542.3, -65.7, -490.5, -63.9, -473.4)
ctx.lineTo(63.9, -473.4)
ctx.moveTo(110.9, -417.0)
ctx.bezierCurveTo(109.0, -430.8, 101.4, -445.8, 88.3, -461.5)
ctx.lineTo(69.3, -461.5)
ctx.lineTo(-69.2, -461.5)
ctx.lineTo(-88.2, -461.5)
ctx.bezierCurveTo(-101.4, -445.7, -109.0, -430.8, -110.8, -417.0)
ctx.lineTo(-86.8, -417.0)
ctx.lineTo(87.0, -417.0)
ctx.lineTo(110.9, -417.0)
ctx.moveTo(79.1, -405.2)
ctx.lineTo(-79.0, -405.2)
ctx.bezierCurveTo(-73.4, -391.8, -60.0, -384.1, -56.1, -382.1)
ctx.lineTo(56.2, -382.1)
ctx.bezierCurveTo(60.0, -384.1, 73.4, -391.8, 79.1, -405.2)
ctx.moveTo(102.5, -205.9)
ctx.bezierCurveTo(76.5, -249.0, 44.4, -302.3, 42.6, -370.3)
ctx.lineTo(-42.4, -370.3)
ctx.bezierCurveTo(-44.2, -302.4, -76.3, -249.0, -102.3, -205.9)
ctx.bezierCurveTo(-117.7, -180.4, -130.9, -158.4, -132.8, -140.9)
ctx.bezierCurveTo(-136.3, -108.7, -119.1, -98.4, -115.1, -96.4)
ctx.lineTo(115.3, -96.4)
ctx.bezierCurveTo(119.4, -98.4, 136.5, -108.7, 133.0, -140.9)
ctx.bezierCurveTo(131.1, -158.4, 117.8, -180.4, 102.5, -205.9)
ctx.moveTo(-110.5, -55.7)
ctx.lineTo(110.5, -55.7)
ctx.lineTo(110.5, -84.6)
ctx.lineTo(-110.5, -84.6)
}
let strokeKing = ctx =>
{
ctx.moveTo(112.6, -212.0)
ctx.bezierCurveTo(87.4, -253.8, 56.2, -305.6, 54.4, -370.3)
ctx.lineTo(57.5, -370.3)
ctx.bezierCurveTo(58.3, -370.3, 59.2, -370.5, 59.9, -370.8)
ctx.bezierCurveTo(61.0, -371.3, 84.7, -382.1, 91.6, -405.2)
ctx.lineTo(117.3, -405.2)
ctx.bezierCurveTo(118.9, -405.2, 120.4, -405.8, 121.5, -407.0)
ctx.bezierCurveTo(122.6, -408.1, 123.2, -409.7, 123.2, -411.2)
ctx.bezierCurveTo(122.9, -430.1, 113.6, -450.3, 95.5, -471.3)
ctx.bezierCurveTo(83.9, -486.2, 71.1, -503.6, 68.7, -508.5)
ctx.bezierCurveTo(68.9, -518.1, 86.6, -585.5, 103.5, -645.1)
ctx.bezierCurveTo(104.0, -646.9, 103.6, -648.8, 102.5, -650.3)
ctx.bezierCurveTo(101.4, -651.8, 99.6, -652.7, 97.8, -652.7)
ctx.lineTo(48.0, -652.7)
ctx.lineTo(36.9, -679.4)
ctx.lineTo(75.2, -663.4)
ctx.bezierCurveTo(77.0, -662.6, 79.1, -662.8, 80.8, -663.9)
ctx.bezierCurveTo(82.4, -665.0, 83.4, -666.8, 83.4, -668.8)
ctx.lineTo(83.4, -757.2)
ctx.bezierCurveTo(83.4, -759.2, 82.4, -761.0, 80.8, -762.1)
ctx.bezierCurveTo(79.2, -763.2, 77.1, -763.4, 75.2, -762.6)
ctx.lineTo(36.9, -746.6)
ctx.lineTo(49.5, -776.9)
ctx.bezierCurveTo(50.3, -778.7, 50.1, -780.8, 49.0, -782.5)
ctx.bezierCurveTo(47.9, -784.1, 46.1, -785.1, 44.1, -785.1)
ctx.lineTo(-44.3, -785.1)
ctx.bezierCurveTo(-46.3, -785.1, -48.1, -784.1, -49.2, -782.5)
ctx.bezierCurveTo(-50.3, -780.9, -50.5, -778.8, -49.7, -776.9)
ctx.lineTo(-37.7, -748.0)
ctx.lineTo(-74.4, -763.3)
ctx.bezierCurveTo(-76.2, -764.1, -78.3, -763.9, -80.0, -762.8)
ctx.bezierCurveTo(-81.6, -761.7, -82.6, -759.9, -82.6, -757.9)
ctx.lineTo(-82.6, -669.5)
ctx.bezierCurveTo(-82.6, -667.5, -81.6, -665.7, -80.0, -664.6)
ctx.bezierCurveTo(-78.4, -663.5, -76.3, -663.3, -74.4, -664.1)
ctx.lineTo(-37.0, -679.7)
ctx.lineTo(-48.3, -652.7)
ctx.lineTo(-98.1, -652.7)
ctx.bezierCurveTo(-100.0, -652.7, -101.7, -651.8, -102.8, -650.3)
ctx.bezierCurveTo(-103.9, -648.8, -104.3, -646.9, -103.8, -645.1)
ctx.bezierCurveTo(-86.9, -585.5, -69.1, -518.2, -69.0, -508.5)
ctx.bezierCurveTo(-71.3, -503.6, -84.1, -486.2, -95.8, -471.3)
ctx.bezierCurveTo(-113.9, -450.3, -123.2, -430.1, -123.5, -411.2)
ctx.bezierCurveTo(-123.5, -409.6, -122.9, -408.1, -121.8, -407.0)
ctx.bezierCurveTo(-120.7, -405.9, -119.2, -405.2, -117.6, -405.2)
ctx.lineTo(-91.9, -405.2)
ctx.bezierCurveTo(-85.1, -382.1, -61.3, -371.3, -60.2, -370.8)
ctx.bezierCurveTo(-59.4, -370.5, -58.6, -370.3, -57.8, -370.3)
ctx.lineTo(-54.7, -370.3)
ctx.bezierCurveTo(-56.5, -305.6, -87.7, -253.8, -112.9, -212.0)
ctx.bezierCurveTo(-129.0, -185.3, -142.9, -162.3, -145.0, -142.2)
ctx.bezierCurveTo(-148.9, -106.2, -130.9, -91.6, -122.6, -86.9)
ctx.lineTo(-122.6, -49.8)
ctx.bezierCurveTo(-122.6, -46.5, -119.9, -43.9, -116.7, -43.9)
ctx.lineTo(116.2, -43.9)
ctx.bezierCurveTo(119.5, -43.9, 122.1, -46.6, 122.1, -49.8)
ctx.lineTo(122.1, -86.9)
ctx.bezierCurveTo(130.3, -91.6, 148.4, -106.3, 144.5, -142.2)
ctx.bezierCurveTo(142.5, -162.3, 128.6, -185.3, 112.6, -212.0)
}
let fillKing = ctx =>
{
ctx.moveTo(-23.3, -695.3)
ctx.bezierCurveTo(-21.7, -694.2, -20.7, -692.4, -20.7, -690.4)
ctx.lineTo(-20.7, -689.0)
ctx.bezierCurveTo(-20.7, -688.2, -20.9, -687.4, -21.2, -686.7)
ctx.lineTo(-35.4, -652.7)
ctx.lineTo(35.2, -652.7)
ctx.lineTo(21.0, -686.7)
ctx.bezierCurveTo(20.7, -687.4, 20.5, -688.2, 20.5, -689.0)
ctx.lineTo(20.5, -690.0)
ctx.bezierCurveTo(20.5, -692.0, 21.5, -693.8, 23.1, -694.9)
ctx.bezierCurveTo(24.7, -696.0, 26.8, -696.2, 28.7, -695.4)
ctx.lineTo(71.5, -677.6)
ctx.lineTo(71.5, -748.2)
ctx.lineTo(28.7, -730.4)
ctx.bezierCurveTo(26.9, -729.6, 24.8, -729.8, 23.1, -730.9)
ctx.bezierCurveTo(21.5, -732.0, 20.5, -733.8, 20.5, -735.8)
ctx.lineTo(20.5, -737.0)
ctx.bezierCurveTo(20.5, -737.8, 20.7, -738.6, 21.0, -739.3)
ctx.lineTo(35.2, -773.3)
ctx.lineTo(-35.3, -773.3)
ctx.lineTo(-21.1, -739.3)
ctx.bezierCurveTo(-20.2, -737.1, -20.7, -734.5, -22.4, -732.8)
ctx.bezierCurveTo(-24.1, -731.1, -26.6, -730.6, -28.9, -731.5)
ctx.lineTo(-70.7, -748.9)
ctx.lineTo(-70.7, -678.3)
ctx.lineTo(-28.9, -695.7)
ctx.bezierCurveTo(-27.1, -696.6, -25.0, -696.3, -23.3, -695.3)
ctx.moveTo(57.4, -504.9)
ctx.bezierCurveTo(56.4, -507.7, 55.1, -511.1, 73.7, -581.1)
ctx.bezierCurveTo(80.1, -605.2, 86.8, -629.1, 90.1, -640.8)
ctx.lineTo(44.2, -640.8)
ctx.lineTo(44.2, -640.8)
ctx.lineTo(-44.2, -640.8)
ctx.lineTo(-90.1, -640.8)
ctx.bezierCurveTo(-86.8, -629.0, -80.1, -605.2, -73.7, -581.1)
ctx.bezierCurveTo(-55.1, -511.2, -56.4, -507.7, -57.4, -504.9)
ctx.bezierCurveTo(-59.4, -499.5, -70.8, -484.0, -78.9, -473.4)
ctx.lineTo(79.0, -473.4)
ctx.bezierCurveTo(70.9, -484.0, 59.5, -499.5, 57.4, -504.9)
ctx.moveTo(110.9, -417.0)
ctx.bezierCurveTo(109.0, -430.8, 101.4, -445.8, 88.3, -461.5)
ctx.lineTo(-88.3, -461.5)
ctx.bezierCurveTo(-101.5, -445.7, -109.1, -430.8, -110.9, -417.0)
ctx.lineTo(-86.9, -417.0)
ctx.lineTo(86.9, -417.0)
ctx.lineTo(110.9, -417.0)
ctx.moveTo(79.0, -405.2)
ctx.lineTo(-79.1, -405.2)
ctx.bezierCurveTo(-73.5, -391.8, -60.1, -384.1, -56.2, -382.1)
ctx.lineTo(56.1, -382.1)
ctx.bezierCurveTo(60.0, -384.1, 73.4, -391.8, 79.0, -405.2)
ctx.moveTo(102.4, -205.9)
ctx.bezierCurveTo(76.4, -249.0, 44.3, -302.3, 42.5, -370.3)
ctx.lineTo(-42.5, -370.3)
ctx.bezierCurveTo(-44.3, -302.4, -76.4, -249.0, -102.4, -205.9)
ctx.bezierCurveTo(-117.8, -180.4, -131.0, -158.4, -132.9, -140.9)
ctx.bezierCurveTo(-136.4, -108.7, -119.2, -98.4, -115.2, -96.4)
ctx.lineTo(115.2, -96.4)
ctx.bezierCurveTo(119.3, -98.4, 136.4, -108.7, 132.9, -140.9)
ctx.bezierCurveTo(131.0, -158.4, 117.8, -180.4, 102.4, -205.9)
ctx.moveTo(-110.5, -55.7)
ctx.lineTo(110.5, -55.7)
ctx.lineTo(110.5, -84.6)
ctx.lineTo(-110.5, -84.6)
}
export let horn = (ctx, fill, stroke) =>
{
ctx.lineJoin = "round"
ctx.lineWidth = 12
ctx.fillStyle = fill
ctx.strokeStyle = stroke
ctx.beginPath()
ctx.moveTo(-40, -475)
ctx.lineTo(-100, -600)
ctx.lineTo(0, -525)
ctx.fill()
ctx.stroke()
}
export let wings = (ctx, fill, stroke) =>
{
ctx.lineCap = "round"
ctx.fillStyle = fill
ctx.strokeStyle = stroke
ctx.save()
ctx.translate(75, -225)
ctx.rotate(-Math.PI / 8)
ctx.beginPath()
ctx.ellipse(0, 0, 50, 75, 0, 0, 8)
ctx.fill()
ctx.lineWidth = 6
ctx.beginPath()
ctx.moveTo(-20, -15)
ctx.quadraticCurveTo(-25, 15, -10, 70)
ctx.moveTo(20, -15)
ctx.quadraticCurveTo(25, 15, 10, 70)
ctx.stroke()
ctx.beginPath()
ctx.ellipse(-23, -30, 23, 27, 0, 0, Math.PI)
ctx.fill()
ctx.stroke()
ctx.beginPath()
ctx.ellipse(23, -30, 23, 27, 0, 0, Math.PI)
ctx.fill()
ctx.stroke()
ctx.lineWidth = 12
ctx.beginPath()
ctx.ellipse(0, 0, 50, 75, 0, 0, 8)
ctx.stroke()
ctx.restore()
}
let shaded = (drawFill, drawStroke) => (ctx, fill, stroke, flipped) =>
{
let s = 1
if (flipped) s = -1
ctx.beginPath()
ctx.fillStyle = stroke
drawStroke(ctx)
ctx.fill()
ctx.save()
ctx.beginPath()
drawFill(ctx)
ctx.clip()
ctx.beginPath()
ctx.fillStyle = fill
ctx.fillRect(-1024, -1024, 2048, 2048)
ctx.save()
ctx.translate(4 * s, 4)
ctx.rect(-1024, -1024, 2048, 2048)
drawFill(ctx)
ctx.clip()
ctx.translate(-4 * s, -4)
ctx.beginPath()
ctx.fillStyle = "#FFF8"
ctx.fillRect(-1024, -1024, 2048, 2048)
ctx.restore()
ctx.save()
ctx.translate(-8 * s, -8)
ctx.rect(-1024, -1024, 2048, 2048)
drawFill(ctx)
ctx.clip()
ctx.translate(8 * s, 8)
ctx.beginPath()
ctx.fillStyle = "#0004"
ctx.fillRect(-1024, -1024, 2048, 2048)
ctx.restore()
ctx.restore()
}
export let pawn = shaded(fillPawn, strokePawn)
export let rook = shaded(fillRook, strokeRook)
export let knight = shaded(fillKnight, strokeKnight)
export let bishop = shaded(fillBishop, strokeBishop)
export let queen = shaded(fillQueen, strokeQueen)
export let king = shaded(fillKing, strokeKing)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment