Pizzeria generator
This commit is contained in:
parent
2bf9c99567
commit
0412122555
2
main.rkt
2
main.rkt
|
@ -65,6 +65,7 @@
|
|||
("PictogrammicAdventurer" weblet pages:pictogrammic-adventurer)
|
||||
("Phonagen" weblet pages:phonagen)
|
||||
("GenerCommunes" weblet pages:gener-communes)
|
||||
("Pizzeria" weblet pages:pizzeria)
|
||||
)
|
||||
; ArnYtron3000
|
||||
("ArnYtron3000" weblet pages:arnytron
|
||||
|
@ -101,6 +102,7 @@
|
|||
("Phonagen" "/Generators/Phonagen" #f)
|
||||
("Un Village en France" "/Generators/GenerCommunes" #f)
|
||||
("Road Maps" "/RoadMap" #t)
|
||||
("Pizzeria" "/Generators/Pizzeria" #t)
|
||||
)
|
||||
("ArnYtron3000" "/ArnYtron3000" #t
|
||||
("(texte brut)" "/ArnYtron3000/brut" #t)
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
#lang racket/base
|
||||
|
||||
(require
|
||||
racket/list
|
||||
json
|
||||
)
|
||||
(provide
|
||||
pizza-name pizza-price pizza-ingredients-fr
|
||||
pizzeria-menu pizzeria-name
|
||||
make-pizzeria-generator pizzeria-generate
|
||||
)
|
||||
|
||||
; Pizzeria generator
|
||||
; Generate a pizzeria and its menu
|
||||
|
||||
;;;;
|
||||
; Ingredient structure
|
||||
(struct ingredient
|
||||
(name-fr ; French name
|
||||
price ; Price in €
|
||||
frequency ; Weight when choosing ingredients
|
||||
))
|
||||
|
||||
; Empty ingredient - used as a filler if there is no ingredient of a category left for a recipe
|
||||
(define *empty-ingredient* (ingredient "" 0 0))
|
||||
|
||||
; Json deserialisation
|
||||
(define (jsexpr->ingredient js)
|
||||
(ingredient
|
||||
(hash-ref js 'name-fr)
|
||||
(hash-ref js 'price)
|
||||
(hash-ref js 'frequency)))
|
||||
|
||||
;;;;
|
||||
; Pizza structure
|
||||
(struct pizza
|
||||
(ingredients ; The list of ingredients
|
||||
name ; Name of the pizza
|
||||
))
|
||||
|
||||
; Price of a pizza
|
||||
(define (pizza-price pzz)
|
||||
(foldl
|
||||
(lambda (i res)
|
||||
(+ (ingredient-price i) res))
|
||||
0
|
||||
(pizza-ingredients pzz)))
|
||||
|
||||
; List of ingredients as a string - French names
|
||||
(define (pizza-ingredients-fr pzz)
|
||||
(foldl
|
||||
(lambda (i res)
|
||||
(define name (ingredient-name-fr i))
|
||||
(cond
|
||||
((equal? name "") res)
|
||||
((equal? res "") name)
|
||||
(#t (string-append res ", " name))))
|
||||
""
|
||||
(pizza-ingredients pzz)))
|
||||
|
||||
;;;;
|
||||
; Pizzaria structure
|
||||
(struct pizzeria
|
||||
(menu ; List of pizzas
|
||||
name ; name of the pizzeria
|
||||
))
|
||||
|
||||
;;;;
|
||||
; Range structure
|
||||
(struct range
|
||||
(min ; Minimal value of a range
|
||||
max ; Maximal value of a range
|
||||
))
|
||||
|
||||
; Generate a number in the range
|
||||
(define (range-generate rng)
|
||||
(random (range-min rng) (+ 1 (range-max rng))))
|
||||
|
||||
; Json deserialisation
|
||||
(define (jsexpr->range js)
|
||||
(range
|
||||
(hash-ref js 'min)
|
||||
(hash-ref js 'max)))
|
||||
|
||||
;;;;
|
||||
; Recipe structure
|
||||
(struct recipe
|
||||
(ingredients ; A list of ingredient categories
|
||||
frequency ; Weight when choosing recipes
|
||||
))
|
||||
|
||||
; Json deserialisation
|
||||
(define (jsexpr->recipe js)
|
||||
(recipe
|
||||
(map string->symbol (hash-ref js 'ingredients))
|
||||
(hash-ref js 'frequency)))
|
||||
|
||||
;;;;
|
||||
; Generator structure
|
||||
(struct pizzeria-generator
|
||||
(ingredients ; A table category -> list of ingredients
|
||||
recipes ; A list of generic recipes for pizzas
|
||||
ingredient-variety ; A table category -> range indicating the number of ingredients a pizzeria can have for each category
|
||||
recipe-variety ; A range indicating the number of different pizzas a pizzeria can have
|
||||
))
|
||||
|
||||
; Json deserialisation
|
||||
(define (jsexpr->pizzeria-generator js)
|
||||
(pizzeria-generator
|
||||
; ingredients
|
||||
(make-hash
|
||||
(hash-map
|
||||
(hash-ref js 'ingredients)
|
||||
(lambda (k v)
|
||||
(cons k (map jsexpr->ingredient v)))))
|
||||
; recipes
|
||||
(map jsexpr->recipe (hash-ref js 'recipes))
|
||||
; ingredient-variety
|
||||
(make-hash
|
||||
(hash-map
|
||||
(hash-ref js 'ingredient-variety)
|
||||
(lambda (k v)
|
||||
(cons k (jsexpr->range v)))))
|
||||
; recipe-variety
|
||||
(jsexpr->range (hash-ref js 'recipe-variety))))
|
||||
|
||||
; Generate from a file
|
||||
(define (make-pizzeria-generator path)
|
||||
(jsexpr->pizzeria-generator (read-json (open-input-file path))))
|
||||
|
||||
; Pizzeria generation function
|
||||
(define (pizzeria-generate pzz-gen)
|
||||
; Max number of pizza on the menu
|
||||
(define nb-pizzas (range-generate (pizzeria-generator-recipe-variety pzz-gen)))
|
||||
; Ingredients of the pizzeria
|
||||
; For each category, restrict the ingredient list with a number choosen in the range of the category
|
||||
(define ingredients
|
||||
(make-hash
|
||||
(hash-map
|
||||
(pizzeria-generator-ingredients pzz-gen)
|
||||
(lambda (k v)
|
||||
(define nb-ingredients (range-generate (hash-ref (pizzeria-generator-ingredient-variety pzz-gen) k)))
|
||||
(cons k (take (shuffle v) nb-ingredients))))))
|
||||
; Pizza recipe generation
|
||||
(define (make-recipe template ingredients-left [res '()])
|
||||
(cond
|
||||
((null? template)
|
||||
(reverse res))
|
||||
(#t
|
||||
(define category (car template))
|
||||
(define lst-ingredients (shuffle (hash-ref ingredients-left category)))
|
||||
(define ingredient (or (and (not (null? lst-ingredients)) (car lst-ingredients))
|
||||
*empty-ingredient*))
|
||||
; Remove the choosen ingredient from the table
|
||||
(when (not (null? lst-ingredients))
|
||||
(hash-set! ingredients-left category (cdr lst-ingredients)))
|
||||
; Continue with the next element of the template
|
||||
(make-recipe
|
||||
(cdr template)
|
||||
ingredients-left
|
||||
(cons ingredient res)))))
|
||||
; Generate the pizzeria
|
||||
(pizzeria
|
||||
(build-list
|
||||
nb-pizzas
|
||||
(lambda (k)
|
||||
(pizza
|
||||
(make-recipe
|
||||
(recipe-ingredients (car (shuffle (pizzeria-generator-recipes pzz-gen))))
|
||||
(hash-copy ingredients))
|
||||
(string-append "Pizza n°" (number->string (+ 1 k))))))
|
||||
"Chez Feufo"))
|
|
@ -3,14 +3,16 @@
|
|||
; Pages with minor generators, often written in javascript
|
||||
(require
|
||||
"templates.rkt"
|
||||
"../generators/pictogrammic-adventurer.rkt")
|
||||
"../generators/pictogrammic-adventurer.rkt"
|
||||
"../generators/pizzeria.rkt")
|
||||
|
||||
(provide
|
||||
pages:other-generators
|
||||
pages:color-scheme-generator
|
||||
pages:pictogrammic-adventurer
|
||||
pages:phonagen
|
||||
pages:gener-communes)
|
||||
pages:gener-communes
|
||||
pages:pizzeria)
|
||||
|
||||
; About page on the other generators
|
||||
(define pages:other-generators
|
||||
|
@ -150,3 +152,32 @@
|
|||
"and the word " (code "Sioule") " as an input of the Markov chain generating river names. "
|
||||
))
|
||||
)))
|
||||
|
||||
(define *pizzeria-generator* (make-pizzeria-generator "./static/data/pizza.json"))
|
||||
(define pages:pizzeria
|
||||
(pages:template
|
||||
#:title "Pizzeria"
|
||||
#:author "feuforeve.fr"
|
||||
#:content
|
||||
(lambda (param)
|
||||
(define pizzeria (pizzeria-generate *pizzeria-generator*))
|
||||
`(article
|
||||
(a ((href "/Generators/Pizzeria")) "Nouveau menu")
|
||||
(h2 ,(pizzeria-name pizzeria))
|
||||
(section
|
||||
,@(map
|
||||
(lambda (pzz)
|
||||
`(article
|
||||
(strong ,(string-upcase (pizza-name pzz)))
|
||||
" — "
|
||||
,(number->string (pizza-price pzz)) " €"
|
||||
" — "
|
||||
,(pizza-ingredients-fr pzz)))
|
||||
(pizzeria-menu pizzeria)))
|
||||
(section
|
||||
(p "Les prix sont toutes taxes comprises et service inclus. "))
|
||||
(section
|
||||
(h3 "À propos de ce générateur")
|
||||
(p "Ce générateur crée un menu de pizzeria à partir de divers ingrédients et de recettes types. " (br)
|
||||
"Entrée tardive pour le " (a ((href "https://feufochmar.itch.io/")) "ProcJam 2020") ".")))
|
||||
)))
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
{
|
||||
"ingredients": {
|
||||
"base": [
|
||||
{"name-fr": "", "price": 7.5, "frequency": 1}
|
||||
],
|
||||
"sauce-base": [
|
||||
{"name-fr": "sauce tomate", "price": 0.5, "frequency": 44},
|
||||
{"name-fr": "crème fraîche", "price": 0.5, "frequency": 19}
|
||||
],
|
||||
"cheese-base": [
|
||||
{"name-fr": "mozzarella", "price": 1.0, "frequency": 54}
|
||||
],
|
||||
"herb": [
|
||||
{"name-fr": "origan", "price": 0.5, "frequency": 23},
|
||||
{"name-fr": "câpres", "price": 0.5, "frequency": 2}
|
||||
],
|
||||
"meat": [
|
||||
{"name-fr": "jambon", "price": 0.5, "frequency": 15},
|
||||
{"name-fr": "pepperoni", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "merguez", "price": 0.5, "frequency": 2},
|
||||
{"name-fr": "lardons", "price": 0.5, "frequency": 4},
|
||||
{"name-fr": "bacon", "price": 1.0, "frequency": 1},
|
||||
{"name-fr": "chorizo", "price": 1.0, "frequency": 6},
|
||||
{"name-fr": "jambon serrano", "price": 1.0, "frequency": 3},
|
||||
{"name-fr": "poulet", "price": 1.0, "frequency": 3},
|
||||
{"name-fr": "jambon de Parme", "price": 2.5, "frequency": 1},
|
||||
{"name-fr": "lard", "price": 1.0, "frequency": 2},
|
||||
{"name-fr": "bœuf haché", "price": 1.5, "frequency": 3},
|
||||
{"name-fr": "foie gras", "price": 1.5, "frequency": 1},
|
||||
{"name-fr": "magret de canard fumé", "price": 1.5, "frequency": 1}
|
||||
],
|
||||
"egg": [
|
||||
{"name-fr": "œuf", "price": 1.0, "frequency": 11}
|
||||
],
|
||||
"fish": [
|
||||
{"name-fr": "anchois", "price": 0.5, "frequency": 3},
|
||||
{"name-fr": "thon", "price": 0.5, "frequency": 2},
|
||||
{"name-fr": "saumon", "price": 2.5, "frequency": 3}
|
||||
],
|
||||
"seafood": [
|
||||
{"name-fr": "crevettes", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "moules", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "calamars", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "vongoles", "price": 0.5, "frequency": 1}
|
||||
],
|
||||
"vegetable": [
|
||||
{"name-fr": "champignons", "price": 1.0, "frequency": 12},
|
||||
{"name-fr": "olives", "price": 0.5, "frequency": 12},
|
||||
{"name-fr": "poivrons", "price": 1.0, "frequency": 6},
|
||||
{"name-fr": "artichauts", "price": 0.5, "frequency": 5},
|
||||
{"name-fr": "oignons", "price": 0.5, "frequency": 7},
|
||||
{"name-fr": "roquette", "price": 1.0, "frequency": 5},
|
||||
{"name-fr": "pommes de terre", "price": 1.0, "frequency": 4}
|
||||
],
|
||||
"fruit": [
|
||||
{"name-fr": "citron", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "pignons de pin", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "confiture de figues", "price": 0.5, "frequency": 1}
|
||||
],
|
||||
"sauce": [
|
||||
{"name-fr": "bolognaise", "price": 0.5, "frequency": 1},
|
||||
{"name-fr": "miel", "price": 1.0, "frequency": 2},
|
||||
{"name-fr": "caramel balsamique", "price": 0.5, "frequency": 1}
|
||||
],
|
||||
"cheese": [
|
||||
{"name-fr": "gorgonzola", "price": 1.5, "frequency": 5},
|
||||
{"name-fr": "chèvre", "price": 1.5, "frequency": 9},
|
||||
{"name-fr": "copeaux de parmesan", "price": 1.0, "frequency": 2},
|
||||
{"name-fr": "burrata", "price": 2.0, "frequency": 1},
|
||||
{"name-fr": "emmental", "price": 0.5, "frequency": 6},
|
||||
{"name-fr": "munster", "price": 1.5, "frequency": 2},
|
||||
{"name-fr": "raclette", "price": 0.5, "frequency": 2}
|
||||
]
|
||||
},
|
||||
"recipes": [
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "herb"], "frequency": 2},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "cheese"], "frequency": 2},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "cheese", "sauce"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "egg"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "cheese"], "frequency": 2},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "cheese", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "vegetable", "sauce-base"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "vegetable", "vegetable"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "vegetable", "vegetable", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "vegetable", "vegetable", "sauce-base", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "vegetable", "vegetable", "vegetable", "sauce", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "egg"], "frequency": 2},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "egg", "herb"], "frequency": 3},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "egg", "vegetable"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "egg", "vegetable", "cheese"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "egg", "sauce-base", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "egg", "fish", "vegetable", "vegetable", "vegetable", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat"], "frequency": 2},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "cheese"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "cheese", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "vegetable", "cheese", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "egg", "vegetable", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "vegetable"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "vegetable", "sauce"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "meat", "meat", "fruit"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "fish", "cheese", "sauce-base"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "fish", "vegetable", "herb"], "frequency": 3},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "fish", "vegetable", "vegetable"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "fish", "vegetable", "vegetable", "sauce-base", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "fish", "fruit", "sauce-base", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "seafood", "seafood", "seafood", "seafood"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable", "cheese"], "frequency": 2},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable", "cheese", "sauce"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable", "cheese", "cheese", "fruit", "sauce"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable", "vegetable", "cheese"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable", "vegetable", "vegetable", "vegetable"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "vegetable", "vegetable", "vegetable", "vegetable", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "cheese", "cheese"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "cheese", "cheese", "herb"], "frequency": 1},
|
||||
{"ingredients": ["base", "sauce-base", "cheese-base", "cheese", "cheese", "cheese", "cheese", "cheese"], "frequency": 1}
|
||||
],
|
||||
"ingredient-variety": {
|
||||
"base": {"min": 1, "max": 1},
|
||||
"sauce-base": {"min": 2, "max": 2},
|
||||
"cheese-base": {"min": 1, "max": 1},
|
||||
"herb": {"min": 1, "max": 2},
|
||||
"meat": {"min": 7, "max": 9},
|
||||
"egg": {"min": 1, "max": 1},
|
||||
"fish": {"min": 3, "max": 3},
|
||||
"seafood": {"min": 0, "max": 4},
|
||||
"vegetable": {"min": 6, "max": 6},
|
||||
"fruit": {"min": 1, "max": 2},
|
||||
"sauce": {"min": 1, "max": 3},
|
||||
"cheese": {"min": 4, "max": 5}
|
||||
},
|
||||
"recipe-variety": {"min": 23, "max": 31}
|
||||
}
|
Loading…
Reference in New Issue