diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/contest.mdx b/src/fibonacci-secondarie/2023-terza-fase/contest/contest.mdx
new file mode 100644
index 0000000..8f626ce
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/contest.mdx
@@ -0,0 +1,15 @@
+import { S1Cioccolato } from "problemset";
+import { S2Montagna } from "problemset";
+import { S3Calcolatrice } from "problemset";
+import { S4Superbunny } from "problemset";
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/header.md b/src/fibonacci-secondarie/2023-terza-fase/contest/header.md
new file mode 100644
index 0000000..397759a
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/header.md
@@ -0,0 +1,19 @@
+# Giochi di Fibonacci 2023/2024
+
+## Fase finale - Scuole secondarie
+
+Questa prova contiene _4 domande_ da risolvere in _3 ore_.
+Tutte le domande sono di **programmazione** tramite blocchi, e sono ordinate per difficoltà crescente.
+**Attento che la difficoltà è soggettiva!** Se stai passando tanto tempo cercando di risolvere una domanda, prova a passare ad altre domande e altre categorie!
+
+## Punteggio
+
+Tutte le domande sono a _blocchi_ e richiedono di scrivere un singolo programma a blocchi, che viene valutato su 10 diversi livelli.
+Per ciascuna domanda e per ciascun livello, Il punteggio che puoi ottenere è:
+
+- 5 punti se il programma produce la risposta _corretta_;
+- 0 punti se il programma produce una risposta _sbagliata_.
+
+Quindi ogni domanda a blocchi può valere fino a 50 punti in totale.
+
+In ogni domanda a blocchi, i primi 5 livelli vengono anche visualizzati graficamente, mentre gli ultimi 5 livelli non vengono visualizzati.
\ No newline at end of file
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies0.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies0.asy
new file mode 100644
index 0000000..fbdd963
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies0.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(bunny.drawing(0.85, bunny.allie_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies1.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies1.asy
new file mode 100644
index 0000000..4833c3a
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies1.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(bunny.drawing(0.85, bunny.bunny_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies2.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies2.asy
new file mode 100644
index 0000000..7f2d9f7
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies2.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(bunny.drawing(0.85, bunny.carol_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies3.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies3.asy
new file mode 100644
index 0000000..d1cb8b2
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunnies3.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(bunny.drawing(0.85, bunny.tiptap_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunny.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunny.asy
new file mode 100644
index 0000000..9d0a185
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/bunny.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(reflect((2, 1), (2, 0))*bunny.drawing(0.85, bunny.tiptap_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/chocolate.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/chocolate.asy
new file mode 100644
index 0000000..bcbaf4b
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/asy/chocolate.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/chocolate.asy" as chocolate;
+
+add(chocolate.drawing());
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/customBlocks.yaml b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/customBlocks.yaml
new file mode 100644
index 0000000..fef6502
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/customBlocks.yaml
@@ -0,0 +1,95 @@
+- type: start
+ message0: inizia qui
+ nextStatement: null
+ colour: 20
+ tooltip: L'esecuzione inizia da qui
+ helpUrl: ""
+ maxInstances: 1
+ js: ""
+
+- type: larghezza
+ message0: larghezza
+ output: Number
+ colour: 20
+ tooltip: larghezza della tavoletta rimasta
+ helpUrl: ""
+ js:
+ - hiddenState.N
+ - ORDER_MEMBER
+
+- type: altezza
+ message0: altezza
+ output: Number
+ colour: 20
+ tooltip: altezza della tavoletta rimasta
+ helpUrl: ""
+ js:
+ - hiddenState.M
+ - ORDER_MEMBER
+
+- type: compagni
+ message0: compagni
+ output: Number
+ colour: 20
+ tooltip: numero di compagni rimasti
+ helpUrl: ""
+ js:
+ - hiddenState.K
+ - ORDER_MEMBER
+
+- type: spezza in orizzontale
+ message0: spezza %1 quadratini in orizzontale
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ previousStatement: null
+ nextStatement: null
+ colour: 20
+ tooltip: spezza x quadratini in orizzontale
+ helpUrl: ""
+ js: |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i <= 0 || Math.floor(i) != i) exit(false, "numero di righe " + i + " non valido");
+ if (i > hiddenState.M) exit(false, "non ci sono " + i + " righe");
+ hiddenState.M -= i;
+ hiddenState.K -= 1;
+ hiddenState.cuts.push(i);
+ })(%0);
+
+- type: spezza in verticale
+ message0: spezza %1 quadratini in verticale
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ previousStatement: null
+ nextStatement: null
+ colour: 20
+ tooltip: spezza x quadratini in verticale
+ helpUrl: ""
+ js: |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i <= 0 || Math.floor(i) != i) exit(false, "numero di colonne " + i + " non valido");
+ if (i > hiddenState.N) exit(false, "non ci sono " + i + " colonne");
+ hiddenState.N -= i;
+ hiddenState.K -= 1;
+ hiddenState.cuts.push(-i);
+ })(%0);
+
+- type: termina
+ message0: termina
+ previousStatement: null
+ colour: 20
+ tooltip: termina il procedimento
+ helpUrl: ""
+ js: |
+ if (hiddenState.K > 0)
+ exit(false, "ci sono ancora compagni che vogliono cioccolato");
+ if (hiddenState.N*hiddenState.M < hiddenState.sol)
+ exit(false, "potevi tenerti più cioccolato");
+ exit(true, "hai distribuito bene il cioccolato, complimenti!");
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/initialBlocks.json b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/initialBlocks.json
new file mode 100644
index 0000000..64bd836
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/initialBlocks.json
@@ -0,0 +1,14 @@
+{
+ "blocks": {
+ "languageVersion": 0,
+ "blocks": [
+ {
+ "type": "start",
+ "id": "y=zq)Uya2A/{vyOtN[i6",
+ "x": 61,
+ "y": 81
+ }
+ ]
+ },
+ "variables": []
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/lorenzo.jpg b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/lorenzo.jpg
new file mode 100644
index 0000000..96aab59
Binary files /dev/null and b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/lorenzo.jpg differ
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/question.mdx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/question.mdx
new file mode 100644
index 0000000..4cab150
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/question.mdx
@@ -0,0 +1,42 @@
+import initialBlocks from "./initialBlocks.json";
+import customBlocks from "./customBlocks.yaml";
+import testcases from "./testcases.py";
+import Visualizer from "./visualizer.jsx";
+
+Tip-Tap adora il cioccolato, e allora si è comprato una tavoletta di cioccolato fatta di $N \times M$ quadratini.
+Anche i $K$ suoi compagni di fattoria vorrebbero mangiare il cioccolato, e Tip-Tap è troppo buono per non dargliene!
+Quindi per $K$ volte spezza la tavoletta in due parti rettangolari, non necessariamente uguali, e dà una delle due ad uno dei suoi $K$ compagni tenendo infine l'ultimo pezzo per sè.
+
+
+
+La tavoletta può essere spezzata solo lungo i bordi dei quadratini, in orizzontale o verticale, in modo tale da non dividere nessun quadratino in due.
+Inoltre una volta spezzata una parte, quella viene subito presa e mangiata da un amico senza dargli la possibilità di spezzarla ulteriormente.
+Tip-Tap vorrebbe sapere come spezzare la tavoletta $K$ volte in modo che gli rimangano il maggior numero possibile di quadratini. Puoi aiutarlo?
+
+Puoi usare questi blocchi:
+
+- `larghezza`: la larghezza attuale della tavoletta.
+- `altezza`: l'altezza attuale della tavoletta.
+- `compagni`: il numero di compagni che ancora chiedono del cioccolato.
+- `spezza x quadratini in orizzontale`: spezza la tavoletta in orizzontale, lasciando $x$ file ad un compagno.
+- `spezza x quadratini in verticale`: spezza la tavoletta in verticale, lasciando $x$ colonne ad un compagno.
+- `termina`: mangia il cioccolato rimasto.
+
+Aiuta Tip-Tap a spezzare la tavoletta $K$ volte, in modo gli rimanga il maggior numero possibile di quadratini!
+
+
+
+> Un possibile programma corretto è il seguente:
+>
+> 
+>
+> Secondo questo programma, per ognuno dei compagni di Tip-Tap, il protagonista
+> controlla se la tavoletta è più larga o più alta, e gli passa una singola fila
+> o colonna a seconda di quale delle due è più piccola. In questo modo, si
+> assicura che alla fine gli rimanga più cioccolato possibile.
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/sol.png b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/sol.png
new file mode 100644
index 0000000..873fbce
Binary files /dev/null and b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/sol.png differ
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/testcases.py b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/testcases.py
new file mode 100644
index 0000000..8ac8d71
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/testcases.py
@@ -0,0 +1,57 @@
+from random import randint, seed
+import json
+import math
+
+seed(42)
+
+L = [2, 5, 10, 10, 10, 90, 900, 900, 900, 900]
+U = [3, 10, 20, 20, 20, 100, 1000, 1000, 1000, 1000]
+type = [0, 1, 2, 3, 0, 3, 0, 2, 0, 4]
+
+params = [L, U, type]
+
+def solve(n, m, k):
+ if n > m:
+ n, m = m, n
+ d = min(k, m - n)
+ k -= d
+ m -= d
+ n -= k // 2
+ m -= k // 2 + k % 2
+ return n*m
+
+def generate(L, U, type):
+ args = set(locals()) | set(['args'])
+
+ # base generator
+ if type == 1:
+ # M = 1
+ N = randint(L, U)
+ M = 1
+ elif type == 2:
+ #quadrato
+ N = M = randint(L, U)
+ elif type == 3:
+ #rettangolo stretto e allungato
+ M = randint(L, U)
+ N = randint(1, L)
+ else:
+ #generico
+ N = randint(L, U)
+ M = randint(L, U)
+
+ if type == 4:
+ K = randint(max(N+M-5, 1), N+M-2)
+ else:
+ K = randint(1, N+M-2)
+
+ # additional state for visualizer
+ sol = solve(N, M, K)
+ cuts = []
+
+ return {k:v for k,v in locals().items() if k not in args}
+
+testcases = []
+for args in zip(*params):
+ testcases.append(generate(*args))
+print(json.dumps(list(testcases)))
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/visualizer.jsx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/visualizer.jsx
new file mode 100644
index 0000000..b8d753d
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-1-cioccolato/visualizer.jsx
@@ -0,0 +1,62 @@
+import React from "react";
+import { range } from "lodash-es";
+
+import { Canvas, Sprite, Rectangle, Variables } from "~/utils/visualizer";
+
+import bunny from "./asy/bunny.asy?w=66";
+import chocolate from "./asy/chocolate.asy?w=25";
+
+const bunnies = import.meta.glob("./asy/bunnies*.asy", {
+ eager: true,
+ import: "default",
+ query: { w: 50 },
+});
+
+export default function Visualizer({ variables }) {
+ const { blocklyVariables, hiddenState } = variables;
+ if (!hiddenState) return;
+
+ var blocks = [];
+ var xoffs = 1.5;
+ var yoffs = 9;
+ var sep = 0.15;
+
+ function chocblock(N0, N, M0, M, name="cioc") {
+ for (var i=N0; i)
+ }
+
+ var N = hiddenState.N;
+ var M = hiddenState.M;
+ if (N <= 20 && M <= 20) {
+ chocblock(0, N, 0, M);
+ for (var i=hiddenState.cuts.length-1; i>=0; --i) {
+ var c = hiddenState.cuts[i];
+ if (c > 0) {
+ yoffs -= sep;
+ chocblock(0, N, M, M+c);
+ M += c;
+ } else {
+ xoffs += sep;
+ chocblock(N, N-c, 0, M);
+ N -= c;
+ }
+ }
+ }
+
+ var len = Object.keys(bunnies).length;
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/bunny.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/bunny.asy
new file mode 100644
index 0000000..ec63788
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/bunny.asy
@@ -0,0 +1,14 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+filldraw((2,-1) -- (2.5,0) -- (6,0) -- (5.5,-1) -- cycle, heavyblue*0.5 + lightgray*0.5, blue+3);
+add(shift(-0.7,0.3)*reflect((2, 1), (2, 0))*bunny.drawing(0.85, bunny.bunny_col));
+add(shift(1.2,0.6)*reflect((2, 1), (2, 0))*bunny.drawing(0.85, bunny.tiptap_col));
+add(shift(0.5,0)*reflect((2, 1), (2, 0))*bunny.drawing(0.85, bunny.carol_col));
+filldraw((2,-1) -- (5.5,-1) -- (6, -2) -- (2, -2) -- cycle, heavyblue, blue+3);
+filldraw((6,0) -- (5.5,-1) -- (6, -2) -- (6.5,-1) -- cycle, darkblue, blue+3);
+for (int i=0; i<2; ++i) {
+ filldraw(circle((3+2*i,-2), 0.7), gray, black+3);
+ filldraw(circle((3+2*i,-2), 0.2), mediumgray, black+2);
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/leftri.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/leftri.asy
new file mode 100644
index 0000000..40efdfe
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/leftri.asy
@@ -0,0 +1,9 @@
+unitsize(1cm);
+
+pen lightcol = rgb("9e6b5a");
+pen darkcol = brown+2;
+
+path bord = (0,0) {dir(10)}..{dir(30)} (1,1);
+
+fill(bord -- (1,0) -- cycle, lightcol);
+fill((0,0) {dir(0)}..{dir(35)} (1,1) -- reverse(bord) -- cycle, darkcol);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/leftsnow.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/leftsnow.asy
new file mode 100644
index 0000000..9e4532e
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/leftsnow.asy
@@ -0,0 +1,10 @@
+unitsize(1cm);
+
+pen lightcol = rgb("9e6b5a");
+pen darkcol = brown+2;
+
+path bord = (0,0) {dir(60)}..{E} (1,1);
+
+fill(bord -- (1,0) -- cycle, lightcol);
+fill(point(bord, 0.2) {E}..{dir(50)} (1,0.45) -- (1,1) -- subpath(bord, 1, 0.2) -- cycle, palegray);
+fill((0,0) {dir(55)}..{dir(5)} (1,1) -- reverse(bord) -- cycle, darkcol);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/offcharge.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/offcharge.asy
new file mode 100644
index 0000000..7f40816
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/offcharge.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/charger.asy" as charger;
+
+add(charger.drawing());
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/oncharge.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/oncharge.asy
new file mode 100644
index 0000000..d69ce48
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/oncharge.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/charger.asy" as charger;
+
+add(charger.drawing(1, lightyellow, green));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/rightri.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/rightri.asy
new file mode 100644
index 0000000..fd827f1
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/rightri.asy
@@ -0,0 +1,9 @@
+unitsize(1cm);
+
+pen lightcol = rgb("9e6b5a");
+pen darkcol = brown+2;
+
+path bord = (0,1) {dir(-30)}..{dir(-10)} (1,0);
+
+fill((0,0) -- bord -- cycle, lightcol);
+fill((0,1) {dir(-35)}..{dir(0)} (1,0) -- reverse(bord) -- cycle, darkcol);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/rightsnow.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/rightsnow.asy
new file mode 100644
index 0000000..a8bf648
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/rightsnow.asy
@@ -0,0 +1,10 @@
+unitsize(1cm);
+
+pen lightcol = rgb("9e6b5a");
+pen darkcol = brown+2;
+
+path bord = (0,1) {E}..{dir(-60)} (1,0);
+
+fill((0,0) -- bord -- cycle, lightcol);
+fill((0,0.45) {dir(10)}.. subpath(bord, 0.4, 0) -- cycle, palegray);
+fill((0,1) {dir(-5)}..{dir(-55)} (1,0) -- reverse(bord) -- cycle, darkcol);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/square.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/square.asy
new file mode 100644
index 0000000..086e3eb
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/square.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+pen lightcol = rgb("9e6b5a");
+
+fill((0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle, lightcol);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/squarecap.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/squarecap.asy
new file mode 100644
index 0000000..1f5e128
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/asy/squarecap.asy
@@ -0,0 +1,7 @@
+unitsize(1cm);
+
+pen lightcol = rgb("9e6b5a");
+pen darkcol = brown+2;
+
+fill((0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle, lightcol);
+fill((0,1) {dir(-15)}..{dir(15)} (1,1) -- cycle, darkcol);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/customBlocks.yaml b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/customBlocks.yaml
new file mode 100644
index 0000000..3b8791c
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/customBlocks.yaml
@@ -0,0 +1,117 @@
+- type: start
+ message0: inizia qui
+ nextStatement: null
+ colour: 20
+ tooltip: L'esecuzione inizia da qui
+ helpUrl: ""
+ maxInstances: 1
+ js: ""
+
+- type: N
+ message0: N
+ output: Number
+ colour: 20
+ tooltip: numero di colonnine lungo il percorso
+ helpUrl: ""
+ js:
+ - hiddenState.N
+ - ORDER_MEMBER
+
+- type: energia
+ message0: energia
+ output: Number
+ colour: 20
+ tooltip: energia rimasta
+ helpUrl: ""
+ js:
+ - hiddenState.energy
+ - ORDER_MEMBER
+
+- type: altitudine della colonnina
+ message0: altitudine della colonnina %1
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: altitudine della colonnina i-esima
+ helpUrl: ""
+ js:
+ - |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "la colonnina " + i + " non esiste");
+ return hiddenState.H[i-1];
+ })(%0)
+ - ORDER_FUNCTION_CALL
+
+- type: avanza
+ message0: avanza
+ previousStatement: null
+ nextStatement: null
+ colour: 20
+ tooltip: avanza fino alla prossima colonnina
+ helpUrl: ""
+ js: |
+ hiddenState.charging = false;
+ if (hiddenState.posx == hiddenState.N-1)
+ exit(false, "sei già arrivato alla fine");
+ delta = hiddenState.H[hiddenState.posx+1] - hiddenState.H[hiddenState.posx];
+ hiddenState.rot = Math.atan2(hiddenState.scale * delta, 1);
+ pause(1);
+ if (hiddenState.energy >= delta) {
+ hiddenState.posx += 1;
+ hiddenState.posy += hiddenState.scale * delta;
+ hiddenState.energy -= delta;
+ } else {
+ hiddenState.posx += hiddenState.energy / delta;
+ hiddenState.posy += hiddenState.scale * hiddenState.energy;
+ hiddenState.energy = 0;
+ exit(false, "hai finito l'energia prima di arrivare");
+ }
+ pause(1);
+ if (hiddenState.posx < hiddenState.N-1)
+ hiddenState.rot = (
+ Math.atan2(hiddenState.scale * (hiddenState.H[hiddenState.posx+1] - hiddenState.H[hiddenState.posx]), 1) +
+ Math.atan2(hiddenState.scale * (hiddenState.H[hiddenState.posx] - hiddenState.H[hiddenState.posx-1]), 1)
+ )/2;
+ else hiddenState.rot = 0;
+
+- type: ricarica
+ message0: ricarica per %1 minuti
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ previousStatement: null
+ nextStatement: null
+ colour: 20
+ tooltip: ricarica per x minuti
+ helpUrl: ""
+ js: |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 0 || i > 1000000 || Math.floor(i) != i)
+ exit(false, "numero di minuti " + i + " non valido");
+ hiddenState.time += i;
+ hiddenState.energy += i;
+ hiddenState.charging = true;
+ })(%0);
+
+- type: termina
+ message0: termina
+ previousStatement: null
+ colour: 20
+ tooltip: termina il procedimento
+ helpUrl: ""
+ js: |
+ hiddenState.charging = false;
+ if (hiddenState.pos < hiddenState.N-1)
+ exit(false, "non sei arrivato alla fine");
+ if (hiddenState.time > hiddenState.sol)
+ exit(false, "potevi aspettare meno alle colonnine");
+ exit(true, "sei arrivato in fretta, complimenti!");
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/initialBlocks.json b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/initialBlocks.json
new file mode 100644
index 0000000..64bd836
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/initialBlocks.json
@@ -0,0 +1,14 @@
+{
+ "blocks": {
+ "languageVersion": 0,
+ "blocks": [
+ {
+ "type": "start",
+ "id": "y=zq)Uya2A/{vyOtN[i6",
+ "x": 61,
+ "y": 81
+ }
+ ]
+ },
+ "variables": []
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/question.mdx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/question.mdx
new file mode 100644
index 0000000..7395d1c
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/question.mdx
@@ -0,0 +1,50 @@
+import initialBlocks from "./initialBlocks.json";
+import customBlocks from "./customBlocks.yaml";
+import testcases from "./testcases.py";
+import Visualizer from "./visualizer.jsx";
+
+I conigli della fattoria Fibonacci hanno appena comprato una nuova efficentissima macchina elettrica!
+
+Non vedono l'ora di provarla, quindi organizzano un viaggio di prova sulle montagne vicine. Il tragitto che vogliono fare è fatto da tratti in salita e tratti in discesa.
+Lungo il percorso ci sono $N$ colonnine di ricarica dove potersi fermare, a diverse altezze. La macchina **usa** un'unità di energia **salendo** di $1$ metro di altitudine,
+mentre **guadagna** un'unità di energia **scendendo** di $1$ metro di altitudine, e non le serve energia per avanzare nei tratti in piano.
+Purtroppo la macchina parte senza energia, e per ricaricarsi può attendere **un minuto** ad una delle colonnine per ogni unità di energia che vuole ottenere in quel momento.
+
+Puoi usare questi blocchi:
+
+- `N`: la lunghezza $N$ del percorso.
+- `energia`: la quantità corrente di energia.
+- `altitudine della colonnina i`: l'altitudine della colonnina di ricarica $i$-esima nel percorso.
+- `avanza`: prosegui il viaggio fino alla prossima colonnina, se hai abbastanza energia.
+- `ricarica per x minuti`: attendi $x$ minuti ad una colonnina per ricaricare $x$ unità di energia.
+- `termina`: spegni la macchina.
+
+I conigli partono dalla colonnina 1, e devono arrivare alla colonnina $N$.
+Organizza il viaggio sulle montagne, evitando che la macchina si fermi prima di arrivare!
+
+
+
+> Un possibile programma corretto è il seguente:
+>
+> 
+>
+> Secondo questo programma, per ognuna delle colonnine a partire dalla seconda, si controlla
+> se c'è abbastanza energia rimasta per coprire la differenza di altezza tra la prossima
+> colonnina $i$ e quella corrente $i-1$. Se non è sufficiente, ci si ricarica
+> alla colonnina per la quantità di minuti minima indispensabile. Poi in ogni
+> caso si procede alla colonnina successiva.
+>
+> Un altro possibile approccio è il seguente:
+>
+> 
+>
+> Secondo questo programma, prima si calcola la massima altezza di una qualunque colonnina
+> lungo il percorso. A questo punto, ci si ricarica una singola volta della quantità di energia
+> necessaria per salire dall'altezza iniziale fino all'altezza massima. A questo punto c'è
+> abbastanza energia per procedere fino alla fine senza fermarsi.
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/sol1.png b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/sol1.png
new file mode 100644
index 0000000..c88d8e8
Binary files /dev/null and b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/sol1.png differ
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/sol2.png b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/sol2.png
new file mode 100644
index 0000000..2fecb2c
Binary files /dev/null and b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/sol2.png differ
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/testcases.py b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/testcases.py
new file mode 100644
index 0000000..f33f1e3
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/testcases.py
@@ -0,0 +1,52 @@
+from random import randint, seed
+import json
+import math
+seed(0)
+
+N = [5, 7, 10, 20, 30, 100, 1000, 1000, 1000, 1000]
+INF = [8, 10, 20, 20, 30, 10000, 10000, 10000, 10000, 10000]
+type = [2, 2, 2, 2, 2, 2, 0, 2, 1, 2]
+
+params = [N, INF, type]
+
+def generate(n, INF, type):
+ args = set(locals()) | set(['args'])
+
+ # base generator
+ N = n
+ H = []
+ if type == 0:
+ H.append(randint(1, 100))
+ for i in range(1, N):
+ H.append(H[i-1] + randint(0, 10) + 1)
+ elif type == 1:
+ for i in range(N):
+ if i%2:
+ H.append(randint(0, 100))
+ else:
+ H.append(randint(INF - 100, INF))
+ else:
+ H.append(0)
+ H.append(randint(2, INF//2))
+ H.append(H[1] - randint(1, 2))
+ H.append(randint(INF//2+1, INF-1))
+ H.append(H[3] + 1)
+ for i in range(5, N):
+ H.append(randint(0, INF))
+
+ # additional state for visualizer
+ scale = 10 / max(H)
+ rot = 0
+ posx = 0
+ posy = H[0]
+ time = 0
+ energy = 0
+ sol = max(H) - H[0]
+ charging = False
+
+ return {k:v for k,v in locals().items() if k not in args}
+
+testcases = []
+for args in zip(*params):
+ testcases.append(generate(*args))
+print(json.dumps(list(testcases)))
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/visualizer.jsx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/visualizer.jsx
new file mode 100644
index 0000000..f77a1fa
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-2-montagna/visualizer.jsx
@@ -0,0 +1,124 @@
+import React from "react";
+import { range } from "lodash-es";
+
+import { Canvas, Sprite, Rectangle, Variables } from "~/utils/visualizer";
+
+import bunny from "./asy/bunny.asy?w=50";
+import leftri from "./asy/leftri.asy?w=40";
+import rightri from "./asy/rightri.asy?w=40";
+import leftsnow from "./asy/leftsnow.asy?w=40";
+import rightsnow from "./asy/rightsnow.asy?w=40";
+import square from "./asy/square.asy?w=40";
+import squarecap from "./asy/squarecap.asy?w=40";
+import offcharge from "./asy/offcharge.asy?w=20";
+import oncharge from "./asy/oncharge.asy?w=20";
+
+export default function Visualizer({ variables }) {
+ const { blocklyVariables, hiddenState } = variables;
+ if (!hiddenState) return;
+
+ var dry = 0.6;
+ var dy = 0;
+ var mountains = [];
+ var eps = 0.03;
+ var de = eps;
+ var h = hiddenState.H[0] * hiddenState.scale - 1;
+ if (hiddenState.N <= 30) {
+ mountains.push(
+
+ );
+ mountains.push(
+
+ );
+ for (var i=0; i
+ );
+ if (hiddenState.H[i] < hiddenState.H[i+1]) {
+ var delta = (hiddenState.H[i+1] - hiddenState.H[i]) * hiddenState.scale;
+ var snow = 0;
+ var cap = i < hiddenState.N-2 && hiddenState.H[i+1] > hiddenState.H[i+2];
+ if (cap) {
+ var bounce = (hiddenState.H[i+1] - hiddenState.H[i+2]) * hiddenState.scale;
+ if (bounce >= delta) snow = 1;
+ else snow = bounce / delta;
+ }
+ if (snow > 0 && snow < 1) {
+ mountains.push(
+
+ );
+ }
+ if (snow > 0)
+ mountains.push(
+
+ );
+ if (snow < 1)
+ mountains.push(
+
+ );
+ } else if (hiddenState.H[i] > hiddenState.H[i+1]) {
+ var delta = (hiddenState.H[i] - hiddenState.H[i+1]) * hiddenState.scale;
+ var snow = 0;
+ var cap = i > 0 && hiddenState.H[i] > hiddenState.H[i-1];
+ if (cap) {
+ var bounce = (hiddenState.H[i] - hiddenState.H[i-1]) * hiddenState.scale;
+ if (bounce >= delta) snow = 1;
+ else snow = bounce / delta;
+ }
+ if (snow > 0 && snow < 1) {
+ mountains.push(
+
+ );
+ }
+ if (snow > 0)
+ mountains.push(
+
+ );
+ if (snow < 1)
+ mountains.push(
+
+ );
+ } else {
+ mountains.push(
+
+ );
+ }
+ }
+ h = hiddenState.H[hiddenState.N-1] * hiddenState.scale - 1;
+ mountains.push(
+
+ );
+ mountains.push(
+
+ );
+ }
+
+ function pos(i) {
+ if (i == 0 || i == hiddenState.N-1) return hiddenState.H[i];
+ return (hiddenState.H[i-1] + hiddenState.H[i+1])*0.025 + hiddenState.H[i] * 0.95;
+ }
+
+ var bx = -0.6;
+ var by = dy+8.7;
+ var br = 0;
+ if (hiddenState.N <= 30) {
+ bx = hiddenState.posx-0.6 + dry*Math.cos(1.5707963267948966+hiddenState.rot);
+ by = dy+8.7-(hiddenState.posx % 1 == 0 ? pos(hiddenState.posx) : hiddenState.posy)*hiddenState.scale + dry - dry*Math.sin(1.5707963267948966+hiddenState.rot);
+ br = -hiddenState.rot/6.283185307179586;
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/asy/bunny.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/asy/bunny.asy
new file mode 100644
index 0000000..6e2b799
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/asy/bunny.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(reflect((2, 1), (2, 0))*bunny.drawing(0.85, bunny.carol_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/calcolatrice.svg b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/calcolatrice.svg
new file mode 100644
index 0000000..07259bc
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/calcolatrice.svg
@@ -0,0 +1,94 @@
+
+
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/customBlocks.yaml b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/customBlocks.yaml
new file mode 100644
index 0000000..ea473cd
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/customBlocks.yaml
@@ -0,0 +1,38 @@
+- type: start
+ message0: inizia qui
+ nextStatement: null
+ colour: 20
+ tooltip: L'esecuzione inizia da qui
+ helpUrl: ""
+ maxInstances: 1
+ js: ""
+
+- type: N
+ message0: N
+ output: Number
+ colour: 20
+ tooltip: il numero da raggiungere
+ helpUrl: ""
+ js:
+ - hiddenState.N
+ - ORDER_MEMBER
+
+- type: termina
+ message0: termina in %1 operazioni
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ previousStatement: null
+ colour: 20
+ tooltip: termina in x operazioni
+ helpUrl: ""
+ js: |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 0 || Math.floor(i) != i) exit(false, "numero di operazioni " + i + " non valido");
+ if (i > hiddenState.sol) exit(false, "potevi fare meno di " + i + " operazioni");
+ if (i < hiddenState.sol) exit(false, "non si può ottenere " + hiddenState.N + " con " + i + " operazioni");
+ exit(true, i + " è il numero minimo di operazioni, complimenti!");
+ })(%0);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/initialBlocks.json b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/initialBlocks.json
new file mode 100644
index 0000000..64bd836
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/initialBlocks.json
@@ -0,0 +1,14 @@
+{
+ "blocks": {
+ "languageVersion": 0,
+ "blocks": [
+ {
+ "type": "start",
+ "id": "y=zq)Uya2A/{vyOtN[i6",
+ "x": 61,
+ "y": 81
+ }
+ ]
+ },
+ "variables": []
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/question.mdx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/question.mdx
new file mode 100644
index 0000000..008f983
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/question.mdx
@@ -0,0 +1,53 @@
+import initialBlocks from "./initialBlocks.json";
+import customBlocks from "./customBlocks.yaml";
+import testcases from "./testcases.py";
+import Visualizer from "./visualizer.jsx";
+
+Carol ha fatto cadere la sua calcolatrice, e ora non funziona più come dovrebbe!
+Gli unici tasti funzionanti sono il $-$, il $\times$, l'$1$ e il $2$.
+Per utilizzare la calcolatrice è costretta a partire dal numero $1$ o dal numero $2$ (premendo il tasto corrispondente) e applicare zero o più volte una delle $4$ possibili operazioni funzionanti:
+
+- sottrarre $1$
+- sottrarre $2$
+- moltiplicare per $1$
+- moltiplicare per $2$
+
+Per fare uno scherzo ai suoi amici, vorrebbe raggiungere sulla calcolatrice il numero $N$. Quante operazioni deve fare al minimo per farlo?
+
+_**Nota:** premere il tasto $1$ o $2$ all'inizio conta come un'operazione, inoltre la calcolatrice è danneggiata quindi Carol è costretta a partire sempre da $1$ o $2$ (**non** può ad esempio premere $2$ e poi $1$ per partire dal numero $21$) e le uniche operazioni ammesse sono quelle precedentemente elencate (**non** può per esempio moltiplicare o sottrarre $12$ o $21$)._
+
+Puoi usare questi blocchi:
+
+- `N`: il numero $N$ che vuole raggiungere.
+- `termina in x operazioni`: riporta che è possibile raggiungere il numero $N$ in $x$ operazioni.
+
+_**Attenzione:** non ti viene richiesto di ricostruire le operazioni da fare, basta che calcoli il numero di operazioni necessario!_
+
+
+
+> Un possibile programma corretto è il seguente:
+>
+> 
+>
+> L'idea di questa soluzione è di ragionare al contrario, partendo dal numero
+> che si vuole raggiungere e tornando indietro con le operazioni inverse. Per
+> esempio, se vogliamo raggiungere il numero 5, ci chiediamo quale numero potrebbe
+> essere l'ultimo che raggiungiamo prima di arrivare al 5. Visto che 5 è dispari,
+> non può essere che l'ultima operazione sia un raddoppio, e moltiplicare per 1
+> non è mai utile. Quindi il numero prima potrebbe essere o il 6 (da cui sottraendo
+> 1 si arriva al 5), oppure il 7 (da cui sottraendo 2 si arriva al 5). Il 7 però
+> non sembra conveniente, perché essendo dispari ci si può arrivare solo da un'altro
+> numero ancora più grande (8 o 9), il che ci allontana dal nostro obiettivo.
+> Si può quindi mostrare che quando dobbiamo raggiungere un valore $n$ dispari,
+> la cosa migliore è raggiungere prima $n+1$. Similmente, quando dobbiamo raggiungere
+> un valore $n$ pari, la cosa migliore è raggiungere prima $n/2$. Ripetiamo quindi
+> questo procedimento a ritroso a partire dal nostro obiettivo $N$, fino a che
+> non raggiungiamo 1 o 2, che sono numeri che possiamo direttamente scrivere
+> sulla nostra calcolatrice. Nel frattempo contiamo quante operazioni stiamo
+> facendo nella variabile risposta, risolvendo il quesito!
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/sol.png b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/sol.png
new file mode 100644
index 0000000..4da2381
Binary files /dev/null and b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/sol.png differ
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/testcases.py b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/testcases.py
new file mode 100644
index 0000000..6d0a4c3
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/testcases.py
@@ -0,0 +1,36 @@
+import random
+import json
+import math
+random.seed(0)
+
+MIN = [2, 2, 2, 500, 1e4-500, 1e6-500, 1e7, 1e11, 1e15-1e9, 1e15-1e9]
+MAX = [5, 10, 20, 1e3, 1e4, 1e6, 1e9, 1e12, 1e15, 1e15]
+type = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
+
+params = [MIN, MAX, type]
+
+def solve(N):
+ risposta = 1;
+ while N > 2:
+ if N%2 == 1:
+ N += 1
+ else:
+ N /= 2
+ risposta += 1
+ return risposta
+
+def generate(MIN, MAX, type):
+ args = set(locals()) | set(['args'])
+
+ # base generator
+ N = random.randint(int(MIN), int(MAX))
+
+ # additional state for visualizer
+ sol = solve(N)
+
+ return {k:v for k,v in locals().items() if k not in args}
+
+testcases = []
+for args in zip(*params):
+ testcases.append(generate(*args))
+print(json.dumps(list(testcases)))
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/visualizer.jsx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/visualizer.jsx
new file mode 100644
index 0000000..63a7834
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-3-calcolatrice/visualizer.jsx
@@ -0,0 +1,29 @@
+import React from "react";
+import { range } from "lodash-es";
+
+import { Canvas, Sprite, Rectangle, Variables } from "~/utils/visualizer";
+
+import bunny from "./asy/bunny.asy?w=100";
+import calcolatrice from "./calcolatrice.svg?w=200";
+
+export default function Visualizer({ variables }) {
+ const { blocklyVariables, hiddenState } = variables;
+ if (!hiddenState) return;
+
+ var num;
+ if (hiddenState.N < 10000) {
+ num = {hiddenState.N}} />
+ }
+
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/bunny.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/bunny.asy
new file mode 100644
index 0000000..f8f6fe5
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/bunny.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/bunny_polychrome.asy" as bunny;
+
+add(reflect((2, 1), (2, 0))*bunny.drawing(0.85, bunny.bunny_col));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/platform.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/platform.asy
new file mode 100644
index 0000000..e5b2aa7
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/platform.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/platform.asy" as platform;
+
+add(platform.drawing(8, 1, .75, (0,0), 0, deepgray, (0.5*deepgray + 0.5*white)+5));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/pole.asy b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/pole.asy
new file mode 100644
index 0000000..d088994
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/asy/pole.asy
@@ -0,0 +1,5 @@
+unitsize(1cm);
+
+access "../../../../../asy_library/pictures/pole.asy" as pole;
+
+add(pole.drawing(15, 1, (0,0), 90, lightgray, (0.5*lightgray + 0.5*black)+5));
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/customBlocks.yaml b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/customBlocks.yaml
new file mode 100644
index 0000000..3dbdfad
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/customBlocks.yaml
@@ -0,0 +1,218 @@
+- type: start
+ message0: inizia qui
+ nextStatement: null
+ colour: 20
+ tooltip: L'esecuzione inizia da qui
+ helpUrl: ""
+ maxInstances: 1
+ js: ""
+
+- type: N
+ message0: N
+ output: Number
+ colour: 20
+ tooltip: il numero di ostacoli
+ helpUrl: ""
+ js:
+ - hiddenState.N
+ - ORDER_MEMBER
+
+- type: pedana alta
+ message0: pedana alta %1
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: l'altezza della pedana più in alto dell'ostacolo dato
+ helpUrl: ""
+ js:
+ - |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "l'ostacolo " + i + " non esiste");
+ return hiddenState.A[i-1];
+ })(%0)
+ - ORDER_FUNCTION_CALL
+
+- type: pedana bassa
+ message0: pedana bassa %1
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: l'altezza della pedana più in basso dell'ostacolo dato
+ helpUrl: ""
+ js:
+ - |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "l'ostacolo " + i + " non esiste");
+ return hiddenState.B[i-1];
+ })(%0)
+ - ORDER_FUNCTION_CALL
+
+- type: differenza assoluta
+ message0: differenza assoluta tra %1 e %2
+ args0:
+ - type: input_value
+ name: FIRST
+ value: 0
+ check: Number
+ - type: input_value
+ name: SECOND
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: la differenza assoluta tra x e y
+ helpUrl: ""
+ js:
+ - |-
+ (function(x, y) {
+ if (x === undefined || y === undefined) exit(false, "un argomento del blocco non ha un valore");
+ if (x < y) return y - x;
+ else return x - y;
+ })(%0, %1)
+ - ORDER_FUNCTION_CALL
+
+- type: minimo
+ message0: minimo tra %1 e %2
+ args0:
+ - type: input_value
+ name: FIRST
+ value: 0
+ check: Number
+ - type: input_value
+ name: SECOND
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: il valore minimo tra x e y
+ helpUrl: ""
+ js:
+ - |-
+ (function(x, y) {
+ if (x === undefined || y === undefined) exit(false, "un argomento del blocco non ha un valore");
+ if (x < y) return x;
+ else return y;
+ })(%0, %1)
+ - ORDER_FUNCTION_CALL
+
+- type: termina
+ message0: termina in %1 tempo
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ previousStatement: null
+ colour: 20
+ tooltip: termina in x tempo
+ helpUrl: ""
+ js: |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 0 || Math.floor(i) != i) exit(false, "tempo " + i + " non valido");
+ if (i > hiddenState.sol) exit(false, "potevi metterci meno di " + i + " tempo");
+ if (i < hiddenState.sol) exit(false, "non si può finire il livello in " + i + " tempo");
+ exit(true, i + " è il tempo minimo per finire il livello, complimenti!");
+ })(%0);
+
+- type: valore pedana alta
+ message0: valore pedana alta %1
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: valore salvato per la pedana più in alto dell'ostacolo dato
+ helpUrl: ""
+ js:
+ - |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "l'ostacolo " + i + " non esiste");
+ return hiddenState.VA[i-1];
+ })(%0)
+ - ORDER_FUNCTION_CALL
+
+- type: valore pedana bassa
+ message0: valore pedana bassa %1
+ args0:
+ - type: input_value
+ name: LENGTH
+ value: 0
+ check: Number
+ output: Number
+ colour: 20
+ tooltip: valore salvato per la pedana più in basso dell'ostacolo dato
+ helpUrl: ""
+ js:
+ - |-
+ (function(i) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "l'ostacolo " + i + " non esiste");
+ return hiddenState.VB[i-1];
+ })(%0)
+ - ORDER_FUNCTION_CALL
+
+- type: imposta valore pedana alta
+ message0: imposta valore pedana alta %1 a %2
+ args0:
+ - type: input_value
+ name: INDEX
+ value: 0
+ check: Number
+ - type: input_value
+ name: VALUE
+ value: 0
+ check: Number
+ previousStatement: null
+ nextStatement: null
+ colour: 20
+ tooltip: salva un valore per la pedana più in alto dell'ostacolo dato
+ helpUrl: ""
+ js: |-
+ (function(i, x) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "l'ostacolo " + i + " non esiste");
+ hiddenState.VA[i-1] = x;
+ })(%0, %1);
+
+- type: imposta valore pedana bassa
+ message0: imposta valore pedana bassa %1 a %2
+ args0:
+ - type: input_value
+ name: INDEX
+ value: 0
+ check: Number
+ - type: input_value
+ name: VALUE
+ value: 0
+ check: Number
+ previousStatement: null
+ nextStatement: null
+ colour: 20
+ tooltip: salva un valore per la pedana più in basso dell'ostacolo dato
+ helpUrl: ""
+ js: |-
+ (function(i, x) {
+ if (i === undefined) exit(false, "l'argomento del blocco non ha un valore");
+ if (i < 1 || i > hiddenState.N || Math.floor(i) != i)
+ exit(false, "l'ostacolo " + i + " non esiste");
+ hiddenState.VB[i-1] = x;
+ })(%0, %1);
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/initialBlocks.json b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/initialBlocks.json
new file mode 100644
index 0000000..64bd836
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/initialBlocks.json
@@ -0,0 +1,14 @@
+{
+ "blocks": {
+ "languageVersion": 0,
+ "blocks": [
+ {
+ "type": "start",
+ "id": "y=zq)Uya2A/{vyOtN[i6",
+ "x": 61,
+ "y": 81
+ }
+ ]
+ },
+ "variables": []
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/question.mdx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/question.mdx
new file mode 100644
index 0000000..dfe4db5
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/question.mdx
@@ -0,0 +1,57 @@
+import initialBlocks from "./initialBlocks.json";
+import customBlocks from "./customBlocks.yaml";
+import testcases from "./testcases.py";
+import Visualizer from "./visualizer.jsx";
+
+Il nuovissimo videogioco *SuperBunny* è finalmente in commercio! Bunny, il protagonista del videogioco, in ogni livello deve superare $N$ ostacoli numerati da $1$ ad $N$.
+Su ogni ostacolo ci sono $2$ pedane (ad altezze diverse) su cui Bunny può saltare: l'ostacolo numero $i$ è fatto da una pedana più in alto che si trova ad una altezza di $A_i$ metri, e da una pedana più in basso ad un'altezza di $B_i$ metri.
+
+Bunny parte da terra ad altezza $0$ e deve per prima cosa saltare sull'ostacolo numero $1$ scegliendo una delle due pedane. Una volta raggiunto l'ostacolo $1$, sceglierà una delle due pedane dell'ostacolo successivo, il $2$, e ci salterà sopra.
+L'obiettivo del gioco è superare in ordine tutti gli ostacoli fino all'ostacolo numero $N$. Anche se Bunny può scegliere ogni volta su quale pedana di un ostacolo saltare, non tutti i salti sono uguali!
+Infatti, più il salto è grande e più tempo ci vuole per farlo. Per saltare da pedana ad altezza $h$ fino ad una pedana sull'ostacolo successivo ad altezza $k$, Bunny ci metterà una quantità di secondi pari alla _differenza assoluta_ tra $h$ e $k$.
+
+_**Nota:** la differenza assoluta tra $h$ e $k$, in formule $|h - k|$, indica il valore della differenza tra $h$ e $k$ ignorando il segno: quindi $h - k$ se $h > k$ o $k - h$ se $k > h$._
+
+Il tempo totale impiegato per completare un livello è la somma dei tempi impiegati in ogni salto. Quanti secondi servono a Bunny per completare il livello?
+Puoi usare questi blocchi:
+
+- `N`: il numero $N$ di ostacoli.
+- `pedana alta i`: l'altezza $A_i$ della $i$-esima pedana più in alto.
+- `pedana bassa i`: l'altezza $B_i$ della $i$-esima pedana più in basso.
+- `differenza assoluta tra x e y`: la differenza assoluta $|x - y|$ tra $x$ e $y$.
+- `minimo tra x e y`: il valore minimo tra due numeri $x$ e $y$.
+- `termina in x tempo`: riporta che è possibile raggiungere l'$N$-esimo ostacolo in $x$ tempo.
+
+Inoltre, se ti serve, avrai la possibilità di annotarti un valore a tua scelta su ogni piattaforma, che verrà anche mostrato nella figura, con questi blocchi:
+
+- `valore pedana alta i`: il valore scritto sulla pedana alta $i$-esima.
+- `valore pedana bassa i`: il valore scritto sulla pedana bassa $i$-esima.
+- `imposta valore pedana alta i a x`: scrivi sulla pedana alta $i$-esima il valore $x$.
+- `imposta valore pedana bassa i a x`: scrivi sulla pedana bassa $i$-esima il valore $x$.
+
+_**Attenzione:** non ti viene richiesto di ricostruire i salti da fare, basta che calcoli il tempo necessario!_
+
+_**Avvertimento:** incastrare un blocco grosso in un altro blocco può non essere semplice. Cerca di mettere la **punta sinistra** del blocco grosso nello spazio in cui vuoi inserirlo, per non avere difficoltà!_
+
+
+
+> Un possibile programma corretto è il seguente:
+>
+> 
+>
+> In questo programma, segnamo come valore su ciascuna pedana il **tempo minimo per raggiungerla**.
+> Per le pedane sul primo ostacolo, il tempo per raggiungerle è pari alla loro altezza.
+> Per ogni pedana successiva (alta o bassa), il tempo minimo per raggiungerla è pari al minimo tra due cose:
+>
+> - se decidiamo di arrivarci dalla pedana alta precedente, allora è pari al tempo minimo (valore) della pedana alta precedente, più la differenza assoluta tra la pedana che stiamo considerando e la pedana alta precedente;
+> - se decidiamo di arrivarci dalla pedana bassa precedente, allora si può calcolare analogamente ma considerando il valore e la differenza assoluta con la pedana bassa precedente.
+>
+> Una volta scritti tutti questi valori, il migliore tempo per chiudere il livello sarà il minore
+> tra il tempo minimo (valore) per raggiungere l'ultima pedana alta, e il tempo minimo (valore)
+> per raggiungere l'ultima pedana bassa.
\ No newline at end of file
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/sol.png b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/sol.png
new file mode 100644
index 0000000..dc56ad3
Binary files /dev/null and b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/sol.png differ
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/testcases.py b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/testcases.py
new file mode 100644
index 0000000..7176592
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/testcases.py
@@ -0,0 +1,55 @@
+from random import randint, seed
+import json
+import math
+
+seed(0)
+
+N = [2, 5, 10, 25, 50, 100, 200, 500, 800, 1000]
+INF = [15, 30, 25, 10, 20, 100, 300, 1000, 3000, 10000]
+type = [0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
+
+params = [N, INF, type]
+
+def solve(N, A, B):
+ A = [0] + A
+ B = [0] + B
+ TA = [0, 0]
+ TB = [0, 0]
+
+ for i in range(N):
+ TA[(i+1)%2] = min(abs(A[i+1]-A[i]) + TA[i%2], abs(A[i+1]-B[i]) + TB[i%2])
+ TB[(i+1)%2] = min(abs(B[i+1]-A[i]) + TA[i%2], abs(B[i+1]-B[i]) + TB[i%2])
+
+ return min(TA[N%2], TB[N%2])
+
+def generate(n, INF, type):
+ args = set(locals()) | set(['args'])
+
+ # base generator
+ N = n
+ A = []
+ B = []
+
+ if type == 1:
+ # rottura greedy
+ goal = randint((INF*4)//5, INF)
+ for i in range(N):
+ A.append(randint(goal-2, goal+2))
+ B.append(randint(1, INF//5))
+ else:
+ for i in range(N):
+ A.append(randint(1, INF))
+ B.append(randint(1, A[i]))
+
+ VA = [0 for _ in range(N)]
+ VB = [0 for _ in range(N)]
+
+ # additional state for visualizer
+ sol = solve(N, A, B)
+
+ return {k:v for k,v in locals().items() if k not in args}
+
+testcases = []
+for args in zip(*params):
+ testcases.append(generate(*args))
+print(json.dumps(list(testcases)))
diff --git a/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/visualizer.jsx b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/visualizer.jsx
new file mode 100644
index 0000000..44e8e49
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/contest/s-4-superbunny/visualizer.jsx
@@ -0,0 +1,43 @@
+import React from "react";
+import { range } from "lodash-es";
+
+import { Canvas, Sprite, Rectangle, Variables } from "~/utils/visualizer";
+
+import bunny from "./asy/bunny.asy?w=50";
+import pole from "./asy/pole.asy?w=15";
+import platform from "./asy/platform.asy?w=90";
+
+export default function Visualizer({ variables }) {
+ const { blocklyVariables, hiddenState } = variables;
+ if (!hiddenState) return;
+
+ var xoffs = 3;
+ var yoffs = 6.5;
+ var poles = [];
+ var platforms = [];
+ var hmax = 0;
+ if (hiddenState.N <= 50) {
+ for (var i=0; i)
+ platforms.push()
+ platforms.push()
+ h = hiddenState.B[i]/hmax*2+0.1;
+ platforms.push()
+ platforms.push()
+ }
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/fibonacci-secondarie/2023-terza-fase/index.jsx b/src/fibonacci-secondarie/2023-terza-fase/index.jsx
new file mode 100644
index 0000000..f8bc958
--- /dev/null
+++ b/src/fibonacci-secondarie/2023-terza-fase/index.jsx
@@ -0,0 +1,16 @@
+import { OlinfoAuth } from "~/utils/olinfo-auth";
+
+import Header from "./contest/header.md";
+import Statement from "./contest/contest.mdx";
+
+export const title = "Giochi di Fibonacci 2023/2024 - Fase Finale";
+export const description = "Fase Finale dei Giochi di Fibonacci 2023/2024";
+
+export function App() {
+ return (
+
+
+
+
+ );
+}
diff --git a/src/index.jsx b/src/index.jsx
index 29dfbfc..2c2c741 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -20,7 +20,7 @@ const contests = {
},
"fibonacci-secondarie": {
name: "Giochi di Fibonacci - Scuole secondarie",
- editions: ["2023 - Seconda fase", "2023 - Seconda fase - Demo", "2023 - Prima fase", "2022 - Prima fase"],
+ editions: ["2023 - Terza fase", "2023 - Seconda fase", "2023 - Seconda fase - Demo", "2023 - Prima fase", "2022 - Prima fase"],
},
scolastiche: {
name: "Selezioni scolastiche delle Olimpiadi Italiane di Informatica",