Compare commits

...

2 commits

Author SHA1 Message Date
Louis Burke 68d85ba833 Sped up build 2024-10-14 17:38:03 -04:00
Louis Burke 6c30f0447b More working build, trying to optimize 2024-10-11 00:04:05 -04:00
18 changed files with 627 additions and 2457 deletions

1
.gitignore vendored
View file

@ -16,3 +16,4 @@ generated/**
!images/**
.ninja_log
build.ninja

1348
.ninja_log

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
package iditacards
#AssetKind: "image" | "tex" | "template" | "cat"
#AssetKind: "image" | "tex" | "texdoc" | "template" | "cat"
#Asset: {
// passed to convert to create the "print" version (usually to add bleed)
@ -37,6 +37,10 @@ package iditacards
source: string
size: #Dimensions
}
if kind == "texdoc" {
source: string
}
}
// Assets are what actually need to be printed/created/etc

View file

@ -13,3 +13,10 @@ assets:
source: iditaboard.tex
size: 4875x3075
instructions:
kind: texdoc
source: instructions.tex
instructions-anatomy:
kind: texdoc
source: instructions-anatomy.tex

File diff suppressed because it is too large Load diff

View file

@ -40,7 +40,7 @@ assets: {
for deckname, deck in decks
for cardname, freq in deck
let card = cards[cardname] {
"\(deckname)-\(cardname)[\(freq.count)]": {
"cards/\(deckname)-\(cardname)[\(freq.count)]": {
size: "750x1050"
print: "-set option:distort:viewport 825x1125-37-37 -virtual-pixel Edge -distort SRT 0 +repage"
@ -72,7 +72,7 @@ pseudoassets: {
contents: [
for cardname, freq in deck
for idx in list.Range(0, freq.count, 1) {
"\(deckname)-\(cardname)[\(freq.count)]"
"cards/\(deckname)-\(cardname)[\(freq.count)]"
},
]
}
@ -84,7 +84,7 @@ pseudoassets: {
for deckname, deck in decks
for cardname, card in deck {
for idx in list.Range(0, card.count, 1) {
"\(deckname)-\(cardname)[\(card.count)]"
"cards/\(deckname)-\(cardname)[\(card.count)]"
}
},
]

179
configure.jq Normal file → Executable file
View file

@ -1,68 +1,121 @@
#!/usr/bin/env -S jq -r -f
# Takes iditacards output json and produces the dynamic ninja build
# Example usage: cue export -- *.cue *.yaml | ./configure.jq > output/build.ninja
def expandout:
to_entries[] | .value + { name: .key };
def ifblank(x): if . | length > 0 then . else x end;
def cuesources: $ARGS.positional | join(" ");
def header: "# Generated from configure.jq, do not edit this file!
def everything:
(
(.assets | map_values(. + { pseudo: false })),
(.pseudoassets | map_values(. + { pseudo: true }))
) | expandout;
root = .
def cuesources:
$ARGS.positional | join(" ");
rule configure
description = recreate build.ninja using configure.jq
command = cue export -- *.cue *.yaml | ./configure.jq --args -- *.cue *.yaml > $out
generator = 1
"# Generated from configure.jq, do not edit this file!",
"",
"root = .",
"",
"rule configure",
" description = recreate build.ninja using configure.jq via configure.sh",
" command = bash configure.sh > build.ninja",
" generator = 1",
" restat = 1",
"",
"build build.ninja: configure | configure.jq configure.sh \(cuesources)",
"include rules.ninja",
"",
"build output/everything.json: cuegen \(cuesources)",
" filter = .",
"", (
everything | (
select(.kind == "template") |
.w = (.size | split("x")[0]) |
.h = (.size | split("x")[1]) |
.rawsuffix = (if .print then "raw." else "" end) |
"build output/\(.name).json: extract output/everything.json",
" filter = --arg asset '\(.name)' '.assets[$$asset].data'",
"build output/\(.name).tex: template2tex output/\(.name).json | templates/\(.template)",
" template = templates/\(.template)",
"build output/\(.name).pdf: tex2pdf output/\(.name).tex || output/\(.name).pdf.dd",
" dyndep = output/\(.name).pdf.dd",
"build output/\(.name).pdf.dd: scantex output/\(.name).tex",
"build output/\(.name).\(.rawsuffix)png: pdf2png output/\(.name).pdf",
" w = \(.w)",
" h = \(.h)",
(select(.print) | "build output/\(.name).png: convert output/\(.name).raw.png"),
(select(.print) | " args = \(.print)")
),(
select(.kind == "image") |
.rawsuffix = (if .print then "raw." else "" end) |
"build output/\(.name).\(.rawsuffix)png: copy \(.source)",
(select(.print) | "build output/\(.name).png: convert output/\(.name).raw.png"),
(select(.print) | " args = \(.print)")
),(
select(.kind == "tex") |
.w = (.size | split("x")[0]) |
.h = (.size | split("x")[1]) |
.rawsuffix = (if .print then "raw." else "" end) |
"build output/\(.name).pdf: tex2pdf \(.source) || output/\(.name).pdf.dd",
" dyndep = output/\(.name).pdf.dd",
"build output/\(.name).pdf.dd: scantex \(.source)",
"build output/\(.name).\(.rawsuffix)png: pdf2png output/\(.name).pdf",
" w = \(.w)",
" h = \(.h)",
(select(.print) | "build output/\(.name).png: convert output/\(.name).raw.png"),
(select(.print) | " args = \(.print)")
)
)
build build.ninja: configure | configure.jq \(cuesources)
base = .
include rules.ninja
build output/.everything.json: cuegen \(cuesources)
filter = .
";
def dirof: split("/")[0:-1] | join("/") | if . | length > 0 then . + "/" else "" end;
def filof: . as $saved | split("/")[-1] | ifblank($saved);
def rawof: filof as $saved | split(".")[0:-1] | join(".") | ifblank($saved);
def generate_pdf_builds($dir; $raw; $tex): "
build output/\($dir)\($raw).pdf: tex2pdf \($tex) || output/\($dir).\($raw).pdf.dd
dyndep = output/\($dir).\($raw).pdf.dd
build output/\($dir).\($raw).pdf.dd: scantex \($tex)
target = output/\($dir)\($raw).pdf
";
def generate_png_from_pdf_builds($dir; $raw; $pdf):
(.size | split("x")[0]) as $w |
(.size | split("x")[1]) as $h |
(if .print then "raw." else "" end) as $ext | "
build output/\($dir)\($raw).\($ext)png: pdf2png \($pdf)
w = \($w)
h = \($h)
";
def generate_png_copy_builds($dir; $raw; $png):
(if .print then "raw." else "" end) as $ext | "
build output/\($dir)\($raw).\($ext)png: copy \($png)
";
def generate_print_png_builds($dir; $raw; $rawpng):
if .print then "
build output/\($dir)\($raw).png: convert \($rawpng)
args = \(.print)
" else empty end;
def generate_template_builds:
(.name | dirof) as $dir |
(.name | rawof) as $raw | ("
build output/\($dir).\($raw).update | output/\($dir).\($raw).json: extract output/.everything.json
filter = --arg asset '\(.name)' '.assets[$$asset].data'
target = output/\($dir).\($raw).json
build output/\($dir)/tex/\($raw).tex: template2tex output/\($dir).\($raw).json | templates/\(.template)
template = templates/\(.template)
",
generate_pdf_builds($dir; $raw; "output/\($dir)/tex/\($raw).tex"),
generate_png_from_pdf_builds($dir; $raw; "output/\($dir)\($raw).pdf"),
generate_print_png_builds($dir; $raw; "output/\($dir)\($raw).raw.png")
);
def generate_image_builds:
(.name | dirof) as $dir |
(.name | rawof) as $raw | (
generate_png_copy_builds($dir; $raw; .source),
generate_print_png_builds($dir; $raw; "output/\($dir)\($raw).raw.png")
);
def generate_tex_builds:
(.size | split("x")[0]) as $w |
(.size | split("x")[1]) as $h |
(.name | dirof) as $dir |
(.name | rawof) as $raw | (
generate_pdf_builds($dir; $raw; .source),
generate_png_from_pdf_builds($dir; $raw; "output/\($dir)\($raw).pdf"),
generate_print_png_builds($dir; $raw; "output/\($dir)\($raw).raw.png")
);
def generate_texdoc_builds:
(.name | dirof) as $dir |
(.name | rawof) as $raw | "
build output/\($dir)\($raw).pdf: tex2pdf2x \(.source) || output/\($dir).\($raw).pdf.dd
dyndep = output/\($dir).\($raw).pdf.dd
build output/\($dir).\($raw).pdf.dd: scantex \(.source)
target = output/\($dir)\($raw).pdf
";
def generate_cat_builds:
(.contents | map("output/" + . + ".pdf") | join(" ")) as $pdfcontents |
(.contents | map("output/" + . + ".png") | join(" ")) as $pngcontents |
(.contents | map("output/" + . + ".raw.png") | join(" ")) as $rawcontents |
(.name | dirof) as $dir |
(.name | rawof) as $raw | "
build output/\($dir)\($raw).pdf: pdfunite \($pdfcontents)
build output/\($dir)\($raw).png: pngunite \($pngcontents)
build output/\($dir)\($raw).raw.png: pngunite \($rawcontents)
";
def generate_builds:
(select(.kind == "template") | generate_template_builds),
(select(.kind == "image") | generate_image_builds),
(select(.kind == "tex") | generate_tex_builds),
(select(.kind == "texdoc") | generate_texdoc_builds),
(select(.kind == "cat") | generate_cat_builds);
def expandout: to_entries[] | .value + { name: .key };
def everything: (.assets, .pseudoassets) | expandout;
header,
(everything | generate_builds)

98
configure.py Normal file
View file

@ -0,0 +1,98 @@
#!/usr/bin/env python3
""" Generates build.ninja for iditacards build in output/. """
import glob
import subprocess
import json
import os
cue_sources = glob.glob(f'*.cue')
yaml_sources = glob.glob(f'*.yaml')
sources = cue_sources + yaml_sources
everything = json.loads(subprocess.run(['cue', 'export', '--'] + sources, stdout=subprocess.PIPE).stdout)
assets = everything['assets']
pseudos = everything['pseudoassets']
all_assets = { **assets, **pseudos }
print('# Generated from configure.sh, do not edit this file!\n')
with open(f'{script_dir}/rules.ninja', 'r') as f:
print(f.read())
print(f'''
base = .
rule configure
description = recreate $out using $in
command = $in > $out
generator = 1
restat = 1
build build.ninja: configure ./configure.py | {' '.join(sources)}
build output/.everything.json: cuegen {' '.join(sources)}
filter = .
''')
for name, asset in all_assets.items():
assetdir = os.path
if asset['kind'] == 'template':
print(f'''
build output/.{name}.update | .{name}.json: extract .everything.json
filter = --arg asset '{name}' '.assets[$$asset].data'
target = .{name}.json
build tex/{name}.tex: template2tex .{name}.json | ../templates/{asset["template"]}
template = ../templates/{asset["template"]}
build {name}.pdf: tex2pdf tex/{name}.tex || .{name}.pdf.dd
dyndep = .{name}.pdf.dd
build .{name}.pdf.dd: scantex tex/{name}.tex
target = {name}.pdf
build {name}.{'raw.' if 'print' in asset else ''}png: pdf2png {name}.pdf
w = {asset['size'].split('x')[0]}
h = {asset['size'].split('x')[1]}
''')
if asset['kind'] == 'image':
print(f'''
build {name}.{'raw.' if 'print' in asset else ''}png: copy ../{asset['source']}
''')
if asset['kind'] == 'tex':
print(f'''
build {name}.pdf: tex2pdf ../{asset['source']} || .{name}.pdf.dd
dyndep = .{name}.pdf.dd
build .{name}.pdf.dd: scantex ../{asset['source']}
target = {name}.pdf
build {name}.{'raw.' if 'print' in asset else ''}png: pdf2png {name}.pdf
w = {asset['size'].split('x')[0]}
h = {asset['size'].split('x')[1]}
''')
if asset['kind'] == 'texdoc':
print(f'''
build {name}.pdf: tex2pdf2x ../{asset['source']} || .{name}.pdf.dd
dyndep = .{name}.pdf.dd
build .{name}.pdf.dd: scantex ../{asset['source']}
target = {name}.pdf
''')
if asset['kind'] == 'cat':
print(f'''
build {name}.pdf: pdfunite {' '.join(content + '.pdf' for content in asset['contents'])}
''')
if 'print' in asset:
print(f'''
build {name}.png: convert {name}.raw.png
args = {asset['print']}
''')

View file

@ -1,4 +1,141 @@
#!/bin/bash
# The real configure script uses jq to parse cue output
cue export -- *.cue *.yaml | jq -r -f configure.jq --args -- *.cue *.yaml
# Outputs a build.ninja script for placing into $1 (or output/ if omitted)
scriptdir="$(dirname -- "${BASH_SOURCE[0]}")"
builddir="${1-output}"
cue_sources=( "$scriptdir"/*.cue "$scriptdir"/*.yaml )
everything="$(cue export -- "${cue_sources[@]}" | jq -c)"
ASSET_TO_JSON="| to_entries[] | .value + { name: .key }"
mapfile -t assets < <(jq -c ".assets $ASSET_TO_JSON" <<<"$everything")
mapfile -t pseudos < <(jq -c ".pseudoassets $ASSET_TO_JSON" <<<"$everything")
# base is the directory that contains the script
base="$(realpath -s --relative-to="$builddir" "$scriptdir")"
# root is the directory that the assets are generated into
root=.
relative_cue_sources=( )
for cue_source in "${cue_sources[@]}"; do
relative_cue_sources+=( "$base/$cue_source" )
done
cat <<EOF
# Generated from configure.sh, do not edit this file!
base = $base
EOF
cat "$scriptdir/rules.ninja"
cat <<EOF
rule configure
description = recreate build.ninja using $base/configure.sh
command = $base/configure.sh $root
generator = 1
restat = 1
build ./build.ninja: configure | $base/configure.sh ${relative_cue_sources[*]}
build $root/.everything.json: cuegen ${relative_cue_sources[*]}
filter = .
EOF
for asset in "${assets[@]}" "${pseudos[@]}"; do
# reset asset variables, also quiets shellcheck
name=
print=
kind=
source=
template=
size=
data=
contents=
eval "$(jq -r 'to_entries[] | "\(.key)=\(.value|@text|@sh)"' <<<"$asset")"
rawsuffix="$(echo -n "$print" | sed 's/.*/raw./')"
case $kind in
template)
cat <<EOF
build $root/.$name.updated | $root/.$name.json: extract $root/.everything.json
filter = --arg asset '$name' '.assets[\$\$asset].data'
target = $root/.$name.json
build $root/tex/$name.tex: template2tex $root/.$name.json | $base/templates/$template
template = $base/templates/$template
build $root/$name.pdf: tex2pdf $root/tex/$name.tex || $root/.$name.pdf.dd
dyndep = $root/.$name.pdf.dd
build $root/.$name.pdf.dd: scantex $root/tex/$name.tex
target = $root/$name.pdf
build $root/$name.${rawsuffix}png: pdf2png $root/$name.pdf
w = ${size%x*}
h = ${size#*x}
EOF
;;
image)
cat <<EOF
build $root/$name.${rawsuffix}png: copy $base/$source
EOF
;;
tex)
cat <<EOF
build $root/$name.pdf: tex2pdf $base/$source || $root/.$name.pdf.dd
dyndep = $root/.$name.pdf.dd
build $root/.$name.pdf.dd: scantex $base/$source
target = $root/$name.pdf
build $root/$name.${rawsuffix}png: pdf2png $root/$name.pdf
w = ${size%x*}
h = ${size#*x}
EOF
;;
texdoc)
cat <<EOF
build $root/$name.pdf: tex2pdf2x $base/$source || $root/.$name.pdf.dd
dyndep = $root/.$name.pdf.dd
build $root/.$name.pdf.dd: scantex $base/$source
target = $root/$name.pdf
EOF
;;
cat)
mapfile -t ins < <(jq -r ".[]" <<<"$contents")
echo -n "build $root/$name.pdf: pdfunite"
for i in "${ins[@]}"; do
echo -n " $root/$i.pdf"
done
echo
;;
*)
echo "ERROR! UNKNOWN ASSET TYPE $kind!" >&2
;;
esac
# always run convert if print is non-empty
if [ -n "$print" ]; then
cat <<EOF
build $root/$name.png: convert $root/$name.raw.png
args = $print
EOF
fi
done

View file

View file

@ -79,7 +79,9 @@
\clearpage
\section{Overview}
% Your background story/recap on what situation the players are getting themselves into. It sets the scene (thematically, usually) for the entire game.
% Your background story/recap on what situation the players are getting
% themselves into. It sets the scene (thematically, usually) for the entire
% game.
Iditacards is a game where you race your opponents in the last great race on
earth - The Iditarod. You will face starvation, hypothermia, and inclement
@ -89,7 +91,10 @@ form to come out ahead.
The first player to cross the finish line wins!
\section{Components}
% This isnt so important for playtesters at this point, but is important for the final rulebook and print and plays (PnP). This way players (including yourself) know whether or not there are missing pieces, or in the case of PnP players, if they have everything they need in order to play.
% This isnt so important for playtesters at this point, but is important for
% the final rulebook and print and plays (PnP). This way players (including
% yourself) know whether or not there are missing pieces, or in the case of PnP
% players, if they have everything they need in order to play.
This game contains many cards. They can be sorted based on the symbol in the
bottom right corner:
@ -118,7 +123,10 @@ The game also contains:
\clearpage
\section{Objective}
% What the players are trying to accomplish. It should also make it clear how players are competing (free-for-all, teams, cooperative, etc.). This is the more technical/mechanical explanation of the 'Overview'. For example: “To be the last player with multiple spaceships orbiting the black hole”.
% What the players are trying to accomplish. It should also make it clear how
% players are competing (free-for-all, teams, cooperative, etc.). This is the
% more technical/mechanical explanation of the 'Overview'. For example: “To be
% the last player with multiple spaceships orbiting the black hole”.
Every turn each player will move forward one space. The cards they play will
increase this, while the places they encounter will work to decrease it. When
@ -126,7 +134,11 @@ the first player reaches the finish line the game ends. The finish line is the
square \emph{after} the last square on the board.
\section{Setup}
% How to get the game ready for play. There shouldnt be anything in here that mentions what components are used for or why they are important--save that for the 'Gameplay' section. Just make sure that in this section everything is laid out clearly--if diagrams are necessary (they almost always are) dont be afraid to put those in!
% How to get the game ready for play. There shouldnt be anything in here that
% mentions what components are used for or why they are important--save that for
% the 'Gameplay' section. Just make sure that in this section everything is laid
% out clearly--if diagrams are necessary (they almost always are) dont be
% afraid to put those in!
To start the game each player must pick a colour. They take the token of that
colour and place it in the ``Start'' space.
@ -145,7 +157,9 @@ Before starting the game everybody draws 6 cards. The first player to grab the
weather die goes first. They roll it, then take their turn.
\section{Gameplay}
% The main gameplay section tells you how the game is broken up (rounds, turns, phases, etc.) and summarizes what players do in each of those stages. This section should explain the flow of the game from start to completion.
% The main gameplay section tells you how the game is broken up (rounds, turns,
% phases, etc.) and summarizes what players do in each of those stages. This
% section should explain the flow of the game from start to completion.
The game is broken into turns. Each turn you may either play a card, or take
a new day. At the end of your turn you automatically move a distance equal to
@ -160,7 +174,11 @@ limit on hand size, however if there aren't enough cards in your deck to fill
your hand, then your hand will consist only of however many cards are available
to be drawn.
% Once thats done, you go into the gameplay specifics, which should be explained in the order in which they occur in game. This is where you explain exactly what happens during each turn, action, round, etc. You also should have sections dedicated to complicated subjects and their edge cases (for instance, our section on Collisions for “Pulled into Darkness”).
% Once thats done, you go into the gameplay specifics, which should be
% explained in the order in which they occur in game. This is where you explain
% exactly what happens during each turn, action, round, etc. You also should
% have sections dedicated to complicated subjects and their edge cases (for
% instance, our section on Collisions for “Pulled into Darkness”).
\subsection{Movement}
As in any race, movement is important. Whenever you move you add your current
@ -185,7 +203,7 @@ If you pass the checkerboard finish line you win the game.
\subsection{Card Anatomy}
\includegraphics{instructions-anatomy.pdf}
\includegraphics{output/instructions-anatomy.pdf}
In this example card, the energy cost is \emph{X} the health cost is \emph{Y}
and the risk cost is \emph{Z}.

View file

@ -19,7 +19,7 @@ legs: [string]: #Leg
assets: {
for legname, leg in legs {
"\(legname)[1]": {
"legs/\(legname)[1]": {
size: "750x1050"
print: "-set option:distort:viewport 825x1125-37-37 -virtual-pixel Edge -distort SRT 0 +repage"
@ -40,7 +40,7 @@ pseudoassets: {
"\(deckname)": {
kind: "cat"
contents: [
for legname, one in legs {"\(legname)[1]"},
for legname, one in legs {"legs/\(legname)[1]"},
]
}
}

181
legs.yaml
View file

@ -1,6 +1,12 @@
# The legs (TODO: export shorthands for each leg effect in iditacard.cls so that
# the cue generation/gomplate instantiation can be simplified)
#
# TODO: consider returning to the old leg system, it allowed for more
# flavour and less clutter, its main downside was that the game was too
# "complicated" and that slowed it down, perhaps decrease the density of legs
# while still using the old card-based system?
legs:
# First legs
farm:
name: 'Farm'
level: firstleg
@ -9,3 +15,178 @@ legs:
3: hypo
5: damage
7: hypo
fishing_hole:
name: 'Fishing Hole'
level: firstleg
effect: '\daydraw{3}'
spaces:
3: damage
5: hypo
7: damage
hospital:
name: 'Hospital'
level: firstleg
effect: '\freecardtype{personal}'
spaces:
3: starve
5: hypo
7: starve
new_moon:
name: 'New Moon'
level: firstleg
effect: '\freecardtype{dog}'
spaces:
3: hypo
5: starve
7: hypo
repair_shop:
name: 'Repair Shop'
level: firstleg
effect: '\freecardtype{sled}'
spaces:
3: starve
5: damage
7: starve
volcano:
name: 'Volcano'
level: firstleg
effect: '\allowednot{\includegraphics[width=1cm]{icons/hypo.png}}'
spaces:
3: damage
5: starve
7: damage
# Second legs
downhill:
name: 'Downhill'
level: secondleg
effect: '\speed{3}'
spaces:
2: hypo
4: damage
6: damage
8: hypo
junkyard:
name: 'Junkyard'
level: secondleg
effect: '\healthcosts{-1}'
spaces:
2: damage
4: hypo
6: hypo
8: damage
park:
name: 'Park'
level: secondleg
effect: '\freecardtype{attachment}'
spaces:
2: starve
4: damage
6: damage
8: starve
solar_farm:
name: 'Solar Farm'
level: secondleg
effect: '\energycosts{-1}'
spaces:
2: damage
4: starve
6: starve
8: damage
town:
name: 'Town'
level: secondleg
effect: '\freecardtype{food}'
spaces:
2: hypo
4: starve
6: starve
8: hypo
village:
name: 'Village'
level: secondleg
effect: '\healthcosts{-1}'
spaces:
2: starve
4: hypo
6: hypo
8: starve
# Third legs
cliff:
name: 'Cliff'
level: thirdleg
effect: '\allowednot{\cardtypetext{personal}{}}'
spaces:
1: starve
3: hypo
5: starve
7: hypo
9: starve
wasteland:
name: 'Wasteland'
level: thirdleg
effect: '\allowednot{\cardtypetext{food}{}}'
spaces:
1: damage
3: starve
5: damage
7: starve
9: damage
exposed:
name: 'Exposed'
level: thirdleg
effect: '\daydraw{-3}'
spaces:
1: hypo
3: starve
5: hypo
7: starve
9: hypo
mountainside:
name: 'Mountainside'
level: thirdleg
effect: '\healthcosts{+1}'
spaces:
1: starve
3: damage
5: starve
7: damage
9: starve
river:
name: 'River'
level: thirdleg
effect: '\energycosts{+1}'
spaces:
1: hypo
3: damage
5: hypo
7: damage
9: hypo
swamp:
name: 'Swamp'
level: thirdleg
effect: '\speed{-3}'
spaces:
1: damage
3: hypo
5: damage
7: hypo
9: damage

View file

View file

@ -1,3 +1,13 @@
# TeX compilation takes a lot of resources and can hang a system, only do about
# 4 at a time
pool tex_pool
depth = 4
# uncomment restats when ninja stops segfaulting when you do so -.- (ninja; touch legs.yaml; ninja)
# TODO: clean up the output directory by messing with this and configure.jq
# hide all json/tex/etc in hidden files?
rule template2tex
description = convert $in to $out using $template as a template
command = gomplate --left-delim '«' --right-delim '»' -c .=$in < $template > $out
@ -7,24 +17,38 @@ rule cuegen
command = cue export $in > $out
rule extract
description = extract $out from $in via jq filter $filter
command = jq $filter < $in | bash update.sh $out
description = extract $target from $in via jq filter $filter
command = touch $out && jq -c $filter < $in | bash $base/update.sh $target
restat = 1
rule tex2pdf
description = render tex from $in to $out
command = $
xelatex $
-interaction=batchmode $
-halt-on-error $
--shell-escape $
--output-directory=$$(dirname $out) $in >/dev/null
pool = tex_pool
rule tex2pdf2x
description = render tex from $in to $out twice (for toc)
command = $
xelatex $
-interaction=batchmode $
-halt-on-error $
--shell-escape $
--output-directory=$$(dirname $out) $in >/dev/null $
&& [ $$(basename -s .tex $in) = $$(basename -s .pdf $out) ] $
|| mv $$(dirname $out)/$$(basename -s .tex $in).pdf $out
|| xelatex $
-interaction=batchmode $
-halt-on-error $
--shell-escape $
--output-directory=$$(dirname $out) $in >/dev/null
pool = tex_pool
rule scantex
description = scan tex $in for dependencies
command = bash scantex.sh $in $out > $out
command = bash $base/scantex.sh $in $target > $out
rule pdf2png
description = convert pdf $in to png $out with size $w by $h
@ -37,3 +61,15 @@ rule convert
rule copy
description = copy $in to $out
command = cp $in $out
rule pdfunite
description = unite pdfs to create $out
command = $
pdfunite $in $out $
&& pdfjam --nup 3x3 $out $
--no-landscape --delta '0.5cm 0.5cm' --scale 0.9 $
-o $$(dirname $out)/$$(basename -s .pdf $out)-mini.pdf >/dev/null 2>&1
rule pngunite
description = unite pngs to create a mosaic
command = magick montage -mode concatenate $in $out

View file

@ -2,18 +2,21 @@
echo 'ninja_dyndep_version = 1'
scriptdir="$(dirname -- "${BASH_SOURCE[0]}")"
src="$1"
dst="$2"
tgt="${dst%%.*}.pdf"
tgt="${dst%.*}.pdf"
cd "$scriptdir" || exit 1
temp="$(mktemp -p .)"
trap 'rm -rf ${temp} ${temp}.*' EXIT INT
cp "$src" "$temp.tex"
xelatex -recorder "$temp.tex" >/dev/null
xelatex -recorder --shell-escape "$temp.tex" >/dev/null
deps="$(awk -v ORS=' ' -v "temp=$temp" -v "repl=${src%%.*}" '/INPUT \./ {gsub(temp,repl,$2); print $2}' < "$temp.fls")"
outs="$(awk -v ORS=' ' -v "temp=${temp#*/}" -v "repl=${dst%%.*}" '/OUTPUT / {gsub(temp,repl,$2); print $2}' < "$temp.fls")"
deps="$(awk -v "temp=$temp" -v "repl=${src%%.*}" '/INPUT \./ {gsub(temp,repl,$2); print $2}' < "$temp.fls" | sort | uniq | tr '\n' ' ')"
outs="$(awk -v "temp=${temp#*/}" -v "repl=${dst%.*}" '/OUTPUT / {gsub(temp,repl,$2); print $2}' < "$temp.fls" | sort | uniq | tr '\n' ' ')"
echo -n "build $tgt"
[ -z "$outs" ] || echo -n " | $outs"

View file

@ -1,4 +1,4 @@
#!/bin/bash
# Counts the number of cards in the given deck.
yq r -j cards.yaml | jq -r --arg deckname "$1" '.decks[] | select(.name | test($deckname; "i")) | .cards | length'
yq r -j cards.yaml | jq -r --arg deckname "$1" '.decks[$deckname] | values | map(.count) | add'

View file

@ -10,5 +10,5 @@ new="$(sha256sum <<<"$input" | cut -d " " -f 1)"
old="$(sha256sum "$output" 2>/dev/null | cut -d " " -f 1)"
if [ "$new" != "$old" ]; then
echo -n "$input" > "$output"
echo "$input" > "$output"
fi