Pizzeria generator

This commit is contained in:
Feufochmar 2020-12-24 15:53:53 +01:00
parent 2bf9c99567
commit 0412122555
4 changed files with 343 additions and 2 deletions

View File

@ -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)

172
src/generators/pizzeria.rkt Normal file
View File

@ -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"))

View File

@ -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") ".")))
)))

136
static/data/pizza.json Normal file
View File

@ -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}
}