feat: add story engine
parent
9bf31e86ce
commit
bf71791fc5
|
@ -1 +1,2 @@
|
||||||
test/*.expect
|
test/*.expect
|
||||||
|
dist/nmm
|
||||||
|
|
|
@ -38,7 +38,8 @@ Here's what it looks like:
|
||||||
|
|
||||||
## BACKGROUND
|
## BACKGROUND
|
||||||
|
|
||||||
9mm is legit a great game.
|
Nine Mens Morris is legit a great game,
|
||||||
|
and I like it a lot.
|
||||||
|
|
||||||
One time i wrote an essay about the social contract implicit to nine mens morris:
|
One time i wrote an essay about the social contract implicit to nine mens morris:
|
||||||
https://write.tildeverse.org/dozens/nine-mens-morris-cultural-meanings-and-social-contracts
|
https://write.tildeverse.org/dozens/nine-mens-morris-cultural-meanings-and-social-contracts
|
||||||
|
@ -49,3 +50,12 @@ https://en.wikipedia.org/wiki/Morabaraba
|
||||||
also look at these round cows
|
also look at these round cows
|
||||||
https://en.wikipedia.org/wiki/Spherical_cow
|
https://en.wikipedia.org/wiki/Spherical_cow
|
||||||
|
|
||||||
|
## USAGE
|
||||||
|
|
||||||
|
1. If you have fennel installed,
|
||||||
|
run `fennel main.fnl`
|
||||||
|
|
||||||
|
2. If you have fennel installed,
|
||||||
|
you can compile a binary
|
||||||
|
using `fennel --compile-binary`.
|
||||||
|
(See `justfile` for an example of how I do it.)
|
||||||
|
|
|
@ -310,6 +310,29 @@ for the client to interpret.
|
||||||
I'm still interested in the Result / Either monad option
|
I'm still interested in the Result / Either monad option
|
||||||
but I think I'm doing to first try the conventional lua way
|
but I think I'm doing to first try the conventional lua way
|
||||||
and throw an error, and then 'pcall' the function and handle the error politely.
|
and throw an error, and then 'pcall' the function and handle the error politely.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.IP "WEEK FOUR REVIEW"
|
||||||
|
Today is the end of tilde30!
|
||||||
|
I didn't get too much done this week
|
||||||
|
on account of the surgery.
|
||||||
|
At least,
|
||||||
|
I wasn't able to keep up with the daily updates.
|
||||||
|
I did end up writing a tracery-lite
|
||||||
|
type templating thing
|
||||||
|
that you can find
|
||||||
|
in `src/story`.
|
||||||
|
I did not succeed in
|
||||||
|
actually incorporating it into the game.
|
||||||
|
But it's there.
|
||||||
|
|
||||||
|
tilde30 on the whole was a fun exercise
|
||||||
|
and a success.
|
||||||
|
I had a lot of fun working on my project,
|
||||||
|
and I especially had a lot of fun hearing about other people's projects.
|
||||||
|
Even if they didn't complete them.
|
||||||
|
I am planning to do it again in September,
|
||||||
|
and am planning to continue working on 9mm
|
||||||
|
in the meantime!
|
||||||
|
|
||||||
.pl \n[nl]u
|
.pl \n[nl]u
|
||||||
|
|
7
justfile
7
justfile
|
@ -2,10 +2,15 @@
|
||||||
default:
|
default:
|
||||||
just --list --unsorted
|
just --list --unsorted
|
||||||
|
|
||||||
|
build:
|
||||||
|
fennel --compile-binary main.fnl dist/nmm \
|
||||||
|
/usr/local/lib/liblua.a \
|
||||||
|
/usr/local/include/lua5.4
|
||||||
|
|
||||||
# run tests
|
# run tests
|
||||||
test:
|
test:
|
||||||
#!/bin/zsh
|
#!/bin/zsh
|
||||||
for f in **/*.test.fnl; do fennel $f | faucet; done
|
for f in lib/**/*.test.fnl; do fennel $f | faucet; done
|
||||||
|
|
||||||
# build expect scripts
|
# build expect scripts
|
||||||
expects:
|
expects:
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
## Format
|
||||||
|
|
||||||
|
Here is a list of lists
|
||||||
|
representing a slightly augmented
|
||||||
|
deck of cards
|
||||||
|
(basically the heckadeck):
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
:: suit
|
||||||
|
spades
|
||||||
|
hearts
|
||||||
|
clubs
|
||||||
|
diamonds
|
||||||
|
acorns
|
||||||
|
clouds
|
||||||
|
swords
|
||||||
|
planets
|
||||||
|
|
||||||
|
:: face
|
||||||
|
beast
|
||||||
|
thief
|
||||||
|
jack
|
||||||
|
queen
|
||||||
|
king
|
||||||
|
|
||||||
|
:: number
|
||||||
|
zero
|
||||||
|
one
|
||||||
|
two
|
||||||
|
three
|
||||||
|
four
|
||||||
|
five
|
||||||
|
six
|
||||||
|
seven
|
||||||
|
eight
|
||||||
|
nine
|
||||||
|
ten
|
||||||
|
eleven
|
||||||
|
twelve
|
||||||
|
|
||||||
|
:: special
|
||||||
|
crone
|
||||||
|
joker
|
||||||
|
watcher
|
||||||
|
traveler
|
||||||
|
|
||||||
|
:: card
|
||||||
|
[[number]]
|
||||||
|
[[face]]
|
||||||
|
|
||||||
|
:: draw
|
||||||
|
[[card]] of [[suit]]
|
||||||
|
[[special]]
|
||||||
|
```
|
||||||
|
|
||||||
|
A list title appears on a line by itself,
|
||||||
|
preceded by a double colon (::)
|
||||||
|
and at least one space.
|
||||||
|
A list title can contain alphabet characters and a dash.
|
||||||
|
|
||||||
|
Following the list title are list items,
|
||||||
|
each on its own line.
|
||||||
|
A list item may be (or contain) a reference
|
||||||
|
to a list title in double brackets.
|
||||||
|
e.g. [[list-title]]
|
||||||
|
|
||||||
|
Blank lines are ignored.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Pass the filename of a file of lists formatted in this way
|
||||||
|
to `create_corpus`
|
||||||
|
and get a "corpus" in return.
|
||||||
|
A corpus is just a deserialized fennel table
|
||||||
|
of list titles and list items.
|
||||||
|
|
||||||
|
Then pass the corpus to `flatten`
|
||||||
|
along with a string or a list to serve as the "origin".
|
||||||
|
In this case if you pass `corpus.draw`,
|
||||||
|
then `flatten` will return a random selection from `:draw`,
|
||||||
|
expanding references along the way:
|
||||||
|
|
||||||
|
- beast of spades
|
||||||
|
- five of hearts
|
||||||
|
- jack of acorns
|
||||||
|
- watcher
|
||||||
|
- three of planets
|
||||||
|
- beast of clubs
|
||||||
|
|
||||||
|
Read and run `story.test.fnl` for an example.
|
||||||
|
|
||||||
|
## Inspiration
|
||||||
|
|
||||||
|
This is inspired by [tracery][1]
|
||||||
|
and [perchance][4]
|
||||||
|
and the [List to HTML Generator][5],
|
||||||
|
and is similar to [twee][2] format.
|
||||||
|
In fact,
|
||||||
|
with just a little modification,
|
||||||
|
you can use this story file
|
||||||
|
to generate tracery output
|
||||||
|
in a twine story
|
||||||
|
using [trice][3].
|
||||||
|
|
||||||
|
[1]: https://github.com/galaxykate/tracery
|
||||||
|
[2]: https://twinery.org/cookbook/terms/terms_twee.html
|
||||||
|
[3]: https://github.com/incobalt/Trice
|
||||||
|
[4]: https://perchance.org/
|
||||||
|
[5]: https://slightadjustments.blogspot.com/p/generator.html
|
|
@ -0,0 +1,46 @@
|
||||||
|
:: suit
|
||||||
|
spades
|
||||||
|
hearts
|
||||||
|
clubs
|
||||||
|
diamonds
|
||||||
|
acorns
|
||||||
|
clouds
|
||||||
|
swords
|
||||||
|
planets
|
||||||
|
|
||||||
|
:: face
|
||||||
|
beast
|
||||||
|
thief
|
||||||
|
jack
|
||||||
|
queen
|
||||||
|
king
|
||||||
|
|
||||||
|
:: number
|
||||||
|
zero
|
||||||
|
one
|
||||||
|
two
|
||||||
|
three
|
||||||
|
four
|
||||||
|
five
|
||||||
|
six
|
||||||
|
seven
|
||||||
|
eight
|
||||||
|
nine
|
||||||
|
ten
|
||||||
|
eleven
|
||||||
|
twelve
|
||||||
|
|
||||||
|
:: special
|
||||||
|
crone
|
||||||
|
joker
|
||||||
|
watcher
|
||||||
|
traveler
|
||||||
|
|
||||||
|
:: card
|
||||||
|
[[number]]
|
||||||
|
[[face]]
|
||||||
|
|
||||||
|
:: draw
|
||||||
|
[[card]] of [[suit]]
|
||||||
|
[[special]]
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
:: origin
|
||||||
|
[[you]] [[need]] [[go]] [[search]] [[find]] [[take]] [[return]] [[change]]
|
||||||
|
|
||||||
|
:: you
|
||||||
|
[[beginning]]
|
||||||
|
|
||||||
|
:: beginning
|
||||||
|
Once upon a time
|
||||||
|
I've told you before but I'll tell you again
|
||||||
|
Once there was
|
||||||
|
One day, a long time ago
|
||||||
|
There was and there was not
|
||||||
|
East of the sun and west of the moon
|
||||||
|
In the beginning
|
||||||
|
Back in the day
|
||||||
|
I remember when
|
||||||
|
On an old day, in the old times
|
||||||
|
Back when tigers used to smoke tobacco
|
||||||
|
That time then and once again
|
|
@ -0,0 +1,58 @@
|
||||||
|
(fn lines [filename callback]
|
||||||
|
(case (pcall #(with-open [file (io.open filename)] (each [line (file:lines)] (callback line))))
|
||||||
|
(false err) (print (string.format "Error: Could not open file %s\n%s" filename err))))
|
||||||
|
|
||||||
|
(fn _create-corpus [lines data]
|
||||||
|
(var current-key nil)
|
||||||
|
(var corpus {})
|
||||||
|
(lines data
|
||||||
|
#(let [key (string.match $1 "^::%s+([%a-]+)")
|
||||||
|
blank (or (= nil $1) (= "" $1))]
|
||||||
|
(when (not blank)
|
||||||
|
(if (not key)
|
||||||
|
(let [list (. corpus current-key)]
|
||||||
|
(table.insert list $1)
|
||||||
|
(tset corpus current-key list))
|
||||||
|
(do
|
||||||
|
(set current-key key)
|
||||||
|
(tset corpus current-key []))))))
|
||||||
|
corpus)
|
||||||
|
(local create-corpus (partial _create-corpus lines))
|
||||||
|
|
||||||
|
(fn one-of [t]
|
||||||
|
"returns a random element of a sequential or non-sequential table"
|
||||||
|
(let [len (accumulate [l 0 _ _ (pairs t)] (+ l 1)) ;; do it the hard way
|
||||||
|
;; because nonseq tables
|
||||||
|
;; have no length?
|
||||||
|
handle (io.popen "echo $RANDOM")
|
||||||
|
output (handle:read "*a")
|
||||||
|
random (output:gsub "[\n\r]" "")
|
||||||
|
seed (math.randomseed random) ;; SIDE EFFECT
|
||||||
|
whatever (handle:close) ;; SIDE EFFECT
|
||||||
|
idx (math.random len)
|
||||||
|
keys (accumulate [acc [] k v (pairs t)] (do (table.insert acc k) acc))
|
||||||
|
rndkey (. keys idx)
|
||||||
|
it (. t rndkey)]
|
||||||
|
it))
|
||||||
|
|
||||||
|
(fn flatten [corpus origin]
|
||||||
|
(let [str (if (= "string" (type origin))
|
||||||
|
origin
|
||||||
|
(if (= "table" (type origin))
|
||||||
|
(one-of origin)
|
||||||
|
(error "Origin must be a table or a string")))
|
||||||
|
template-pattern "%[%[[%a-]+%]%]" ; [[word]]
|
||||||
|
word-pattern "%[%[([%a-]+)%]%]" ; word
|
||||||
|
(i j) (string.find str template-pattern) ; indices
|
||||||
|
word (string.match str word-pattern)] ; the actual keyword
|
||||||
|
(if (not i)
|
||||||
|
str
|
||||||
|
(let [next-str (string.format "%s%s%s"
|
||||||
|
(string.sub str 1 (- i 1))
|
||||||
|
(one-of (. corpus word))
|
||||||
|
(string.sub str (+ j 1)))]
|
||||||
|
(flatten corpus next-str j))))) ;; this is a tail call!
|
||||||
|
|
||||||
|
{: create-corpus
|
||||||
|
: flatten
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
:: start
|
||||||
|
To [[do]] in the [[place]] [[preposition]] the [[color]] [[celestial]]
|
||||||
|
|
||||||
|
:: do
|
||||||
|
[[walk]]
|
||||||
|
[[feel]]
|
||||||
|
|
||||||
|
:: place
|
||||||
|
[[biome]]
|
||||||
|
[[weather]] [[biome]]
|
||||||
|
[[weather]] [[biome]]
|
||||||
|
|
||||||
|
:: feel
|
||||||
|
brood
|
||||||
|
go to pieces
|
||||||
|
wallow
|
||||||
|
percolate
|
||||||
|
ferment
|
||||||
|
pine
|
||||||
|
waste away
|
||||||
|
ponder
|
||||||
|
wonder
|
||||||
|
|
||||||
|
:: preposition
|
||||||
|
beneath
|
||||||
|
amongst
|
||||||
|
betwixt
|
||||||
|
below
|
||||||
|
between
|
||||||
|
through
|
||||||
|
around
|
||||||
|
despite
|
||||||
|
|
||||||
|
:: walk
|
||||||
|
walk
|
||||||
|
stroll
|
||||||
|
jaunt
|
||||||
|
wander
|
||||||
|
meander
|
||||||
|
amble
|
||||||
|
stalk
|
||||||
|
ambulate
|
||||||
|
|
||||||
|
:: weather
|
||||||
|
blistering
|
||||||
|
undulating
|
||||||
|
weeping
|
||||||
|
mourning
|
||||||
|
hidden
|
||||||
|
secret
|
||||||
|
wistful
|
||||||
|
taciturn
|
||||||
|
sticky
|
||||||
|
|
||||||
|
:: biome
|
||||||
|
woods
|
||||||
|
dunes
|
||||||
|
forest
|
||||||
|
plains
|
||||||
|
hills
|
||||||
|
mountains
|
||||||
|
ocean
|
||||||
|
bog
|
||||||
|
lake
|
||||||
|
|
||||||
|
:: color
|
||||||
|
chartreuse
|
||||||
|
opalescent
|
||||||
|
verdant
|
||||||
|
vermilion
|
||||||
|
aquamarine
|
||||||
|
copper
|
||||||
|
|
||||||
|
:: celestial
|
||||||
|
skies
|
||||||
|
moon
|
||||||
|
stars
|
||||||
|
planets
|
||||||
|
clouds
|
||||||
|
sun
|
|
@ -0,0 +1,16 @@
|
||||||
|
(let [{
|
||||||
|
: flatten
|
||||||
|
: create-corpus
|
||||||
|
} (require :src.story.story)]
|
||||||
|
|
||||||
|
(let [corpus (create-corpus "src/story/story.test.dat")
|
||||||
|
get-story (partial flatten corpus corpus.start)]
|
||||||
|
(print "\n== POEMS ==")
|
||||||
|
(for [_ 1 10] (print (get-story))))
|
||||||
|
|
||||||
|
(let [corpus (create-corpus "src/story/cards.dat")
|
||||||
|
get-story (partial flatten corpus corpus.draw)]
|
||||||
|
(print "\n== CARDS ==")
|
||||||
|
(for [_ 1 10] (print (get-story)))))
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
== ABOUT ==
|
## ABOUT
|
||||||
|
|
||||||
these files are to help me test the ui
|
these files are to help me test the ui.
|
||||||
|
actually, just the game state really.
|
||||||
|
|
||||||
moves are recorded in `<file>.dat`.
|
moves are recorded in `<file>.dat`.
|
||||||
then you can `awk -f test.awk file.dat > file.expect`.
|
then you can `awk -f test.awk file.dat > file.expect`.
|
||||||
|
@ -8,11 +9,11 @@ then you can `awk -f test.awk file.dat > file.expect`.
|
||||||
then you can `expect file.expect`
|
then you can `expect file.expect`
|
||||||
to have expect play the game for you up to a certain point.
|
to have expect play the game for you up to a certain point.
|
||||||
|
|
||||||
== REQUIREMENTS ==
|
## REQUIREMENTS
|
||||||
|
|
||||||
- awk
|
- awk
|
||||||
- expect
|
- expect
|
||||||
|
|
||||||
== FUTURE PLANS ==
|
## FUTURE PLANS
|
||||||
|
|
||||||
have actual integration tests?
|
have actual integration tests?
|
Loading…
Reference in New Issue