feat: add story engine
parent
9bf31e86ce
commit
bf71791fc5
|
@ -1 +1,2 @@
|
|||
test/*.expect
|
||||
dist/nmm
|
||||
|
|
|
@ -38,7 +38,8 @@ Here's what it looks like:
|
|||
|
||||
## 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:
|
||||
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
|
||||
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
|
||||
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.
|
||||
.
|
||||
.
|
||||
.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
|
||||
|
|
7
justfile
7
justfile
|
@ -2,10 +2,15 @@
|
|||
default:
|
||||
just --list --unsorted
|
||||
|
||||
build:
|
||||
fennel --compile-binary main.fnl dist/nmm \
|
||||
/usr/local/lib/liblua.a \
|
||||
/usr/local/include/lua5.4
|
||||
|
||||
# run tests
|
||||
test:
|
||||
#!/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
|
||||
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`.
|
||||
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`
|
||||
to have expect play the game for you up to a certain point.
|
||||
|
||||
== REQUIREMENTS ==
|
||||
## REQUIREMENTS
|
||||
|
||||
- awk
|
||||
- expect
|
||||
|
||||
== FUTURE PLANS ==
|
||||
## FUTURE PLANS
|
||||
|
||||
have actual integration tests?
|
Loading…
Reference in New Issue