Codice dei programmi nella directory:
///File: HanoiSimulatore.h
#ifndef HANOI_SIM_H
#define HANOI_SIM_H
#include "raylib.h"
#include <stdbool.h>
#define MAX_DISCHI 8
// Struttura interna per gestire lo stato della simulazione
typedef struct {
int pioli[3][MAX_DISCHI]; // CORRETTO: Matrice per i 3 pioli
int conteggio[3]; // CORRETTO: Array per il numero di dischi su ciascuno dei 3 pioli
int totaleDischi;
bool erroreRegole;
const char* messaggioErrore;
} HanoiSim;
// Variabile globale statica per mantenere lo stato nascosto all'utente
static HanoiSim sim;
// Inizializza la finestra grafica e i dischi sul primo piolo
void InizializzaSimulazione(int numDischi) {
if (numDischi > MAX_DISCHI) numDischi = MAX_DISCHI;
if (numDischi < 1) numDischi = 1;
sim.totaleDischi = numDischi;
sim.erroreRegole = false;
sim.messaggioErrore = "";
// Inizializza i conteggi dei tre pioli
sim.conteggio[0] = numDischi;
sim.conteggio[1] = 0;
sim.conteggio[2] = 0;
// Riempie il primo piolo (indice 0) con i dischi dal più grande al più piccolo
for (int i = 0; i < numDischi; i++) {
sim.pioli[0][i] = numDischi - i;
}
// --- AGGIUNGI QUESTA RIGA QUI ------------------------------------------
// Disabilita completamente i messaggi di testo iniziali di Raylib
SetTraceLogLevel(LOG_NONE);
// -----------------------------------------------------------------------
// Inizializza la finestra bloccata a 60 FPS fluidi
InitWindow(800, 450, "Esercizio: Torre di Hanoi");
SetTargetFPS(60);
}
// Funzione di disegno interna (Resta pura, non chiama Begin/End Drawing)
static void DisegnaElementiScena(int discoInMovimento, float movX, float movY) {
float posizioniX[] = { 200.0f, 400.0f, 600.0f };
float basePegY = 350.0f;
float altezzaDisco = 25.0f;
float larghezzaUnita = 20.0f;
// Dichiarazione e assegnazione separata dei colori
Color colori[8];
colori[0] = GetColor(0xe12a2aff); // Rosso
colori[1] = GetColor(0xff8100ff); // Arancione
colori[2] = GetColor(0xffd300ff); // Giallo
colori[3] = GetColor(0x27ae60ff); // Verde
colori[4] = GetColor(0x2980b9ff); // Blu
colori[5] = GetColor(0x8e44adff); // Viola
colori[6] = GetColor(0xf1c40fff); // Giallo chiaro
colori[7] = GetColor(0x2c3e50ff); // Blu scuro
ClearBackground(RAYWHITE);
if (sim.erroreRegole) {
DrawText(sim.messaggioErrore, 20, 20, 20, RED);
}
// Base e pioli
DrawRectangle(50, (int)basePegY, 700, 20, BROWN);
for (int i = 0; i < 3; i++) {
DrawRectangle((int)posizioniX[i] - 5, (int)basePegY - 220, 10, 220, GRAY);
}
// Dischi fermi
for (int p = 0; p < 3; p++) {
for (int d = 0; d < sim.conteggio[p]; d++) {
int taglia = sim.pioli[p][d];
float larghezza = taglia * larghezzaUnita + 30;
float x = posizioniX[p] - (larghezza / 2);
float y = basePegY - ((d + 1) * altezzaDisco);
DrawRectangleRounded((Rectangle){x, y, larghezza, altezzaDisco - 2}, 0.3f, 4, colori[taglia % 8]);
DrawRectangleLinesEx((Rectangle){x, y, larghezza, altezzaDisco - 2}, 1, BLACK);
}
}
// Disco in movimento animato
if (discoInMovimento > 0) {
float larghezza = discoInMovimento * larghezzaUnita + 30;
float x = movX - (larghezza / 2);
float y = movY;
DrawRectangleRounded((Rectangle){x, y, larghezza, altezzaDisco - 2}, 0.3f, 4, colori[discoInMovimento % 8]);
DrawRectangleLinesEx((Rectangle){x, y, larghezza, altezzaDisco - 2}, 1, BLACK);
}
}
// Chiude la finestra di simulazione alla fine
void ChiudiSimulazione(void) {
while (!WindowShouldClose()) {
BeginDrawing();
DisegnaElementiScena(0, 0, 0);
EndDrawing();
}
CloseWindow();
}
/**
* Muove un disco rispettando le regole con un'animazione a tempo costante e fluida.
*/
void MuoviDisco(int da, int a, int velocita) {
if (sim.erroreRegole || WindowShouldClose()) return;
if (velocita < 1) velocita = 1;
if (velocita > 100) velocita = 100;
int idxDa = da - 1;
int idxA = a - 1;
// Controlli didattici di sicurezza
if (idxDa < 0 || idxDa > 2 || idxA < 0 || idxA > 2) {
sim.erroreRegole = true;
sim.messaggioErrore = "ERRORE: Indici dei pioli non validi! Usa valori da 1 a 3.";
while (!WindowShouldClose()) { BeginDrawing(); DisegnaElementiScena(0, 0, 0); EndDrawing(); }
return;
}
if (sim.conteggio[idxDa] <= 0) {
sim.erroreRegole = true;
sim.messaggioErrore = "ERRORE: Tentativo di muovere un disco da un piolo vuoto!";
while (!WindowShouldClose()) { BeginDrawing(); DisegnaElementiScena(0, 0, 0); EndDrawing(); }
return;
}
int tagliaDiscoDaMuovere = sim.pioli[idxDa][sim.conteggio[idxDa] - 1];
if (sim.conteggio[idxA] > 0) {
int tagliaDiscoDestinazione = sim.pioli[idxA][sim.conteggio[idxA] - 1];
if (tagliaDiscoDaMuovere > tagliaDiscoDestinazione) {
sim.erroreRegole = true;
sim.messaggioErrore = "ERRORE: Impossibile mettere un disco piu' grande sopra uno piu' piccolo!";
while (!WindowShouldClose()) { BeginDrawing(); DisegnaElementiScena(0, 0, 0); EndDrawing(); }
return;
}
}
// Estrazione logica temporanea per l'effetto visivo
sim.conteggio[idxDa]--;
// Configurazione geometrica
float posizioniX[] = { 200.0f, 400.0f, 600.0f };
float basePegY = 350.0f;
float altezzaDisco = 25.0f;
float altezzaMassimaSollevamento = basePegY - 240.0f;
float startX = posizioniX[idxDa];
float startY = basePegY - ((sim.conteggio[idxDa] + 1) * altezzaDisco);
float endX = posizioniX[idxA];
float endY = basePegY - ((sim.conteggio[idxA] + 1) * altezzaDisco);
// Se la velocità è al massimo, esegui all'istante senza frame intermedi
if (velocita >= 98) {
sim.pioli[idxA][sim.conteggio[idxA]] = tagliaDiscoDaMuovere;
sim.conteggio[idxA]++;
BeginDrawing();
DisegnaElementiScena(0, 0, 0);
EndDrawing();
return;
}
// Calcolo del tempo totale del movimento (da 1.2 secondi a 0.05 secondi)
float tempoTotaleAnimazione = 1.2f * (1.0f - (float)(velocita - 1) / 97.0f);
if (tempoTotaleAnimazione < 0.05f) tempoTotaleAnimazione = 0.05f;
float tempoTrascorso = 0.0f;
float curX = startX;
float curY = startY;
// UNICO LOOP DI ANIMAZIONE SINCRONIZZATO CON IL MONITOR (60 FPS)
while (tempoTrascorso < tempoTotaleAnimazione && !WindowShouldClose()) {
tempoTrascorso += GetFrameTime();
if (tempoTrascorso > tempoTotaleAnimazione) tempoTrascorso = tempoTotaleAnimazione;
// Frazione globale del tempo (va da 0.0 a 1.0)
float p = tempoTrascorso / tempoTotaleAnimazione;
// Suddividiamo il tempo totale equamente in 3 sotto-fasi (0.33 ciascuna)
if (p <= 0.333f) {
// Fase 1: Salita
float tFase = p / 0.333f;
curX = startX;
curY = startY + (altezzaMassimaSollevamento - startY) * tFase;
}
else if (p <= 0.666f) {
// Fase 2: Spostamento orizzontale
float tFase = (p - 0.333f) / 0.333f;
curX = startX + (endX - startX) * tFase;
curY = altezzaMassimaSollevamento;
}
else {
// Fase 3: Discesa
float tFase = (p - 0.666f) / 0.334f;
curX = endX;
curY = altezzaMassimaSollevamento + (endY - altezzaMassimaSollevamento) * tFase;
}
// Singolo rendering a frame, fluido e privo di lag
BeginDrawing();
DisegnaElementiScena(tagliaDiscoDaMuovere, curX, curY);
EndDrawing();
}
// Inserimento definitivo
sim.pioli[idxA][sim.conteggio[idxA]] = tagliaDiscoDaMuovere;
sim.conteggio[idxA]++;
}
#endif // HANOI_SIM_H
///(Fine file: HanoiSimulatore.h)
///File: main-errore-movimento.c
#include "HanoiSimulatore.h"
int main(void) {
int numeroDischi = 3; // Puoi cambiarlo liberamente (fino a un massimo di 8)
// Inizializza l'ambiente grafico con il numero di dischi scelto
InizializzaSimulazione(numeroDischi);
// Avvia il tuo algoritmo dicendo di muovere i dischi dal piolo 1 al piolo 3 usando il 2
MuoviDisco(1,2,5); // terzo parametro velocità da 1 a 100
//MuoviDisco(1,2,30); // dovrebbe dare errore o rifiutarsi....
MuoviDisco(2,3,5);
MuoviDisco(2,3,5); // dovrebbe dare errore piolo vuoto
// Gestisce la chiusura finale e blocca la finestra per farti vedere il risultato
ChiudiSimulazione();
return 0;
}
///(Fine file: main-errore-movimento.c)
///File: TorreHanoi.html
<html>
<head>
<title>Dimostrazione Gioco Torre di Hanoi — </title>
<link href='http://fonts.googleapis.com/css?family=Chewy&text=Tower%20of%20Hanoi%20Game' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="css/TowerOfHanoi.min.css?v=0.1" />
<link rel="stylesheet" type="text/css" href="css/DemoPage.css?v=0.1" />
</head>
<body>
<div class="demo-block" id="main">
<h2>Gioco della Torre di Hanoi (max 7 dischi)</h2>
<div id="game-container"></div>
<p id="step-information">
Nuomero di passi che hai fatto: <span id="step">0</span>.
Per vincere devi fare non piu' di <span id="max-step">0</span> passi.
</p>
<p>
<label for="number-of-pegs">Numero di Pioli:</label>
<select id="number-of-pegs">
<option>3</option>
</select> |
<label for="number-of-discs">Numero di Dischi:</label>
<select id="number-of-discs">
<option>1</option>
<option>2</option>
<option selected>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
</select> |
<a id="Pausa" href="#">Pause</a> |
<a id="Ricomincia" href="#">Restart</a>
</p>
</div>
<div class="demo-block" id="footer">
<p>Copyright © 2012 Akeda Bagus admin at gedex.web.id - Modificato 2020</p>
</div>
<script src="js/jquery-1.7.1.min.js"></script>
<script src="js/jquery-ui.min.js"></script>
<script src="js/TowerOfHanoi.min.js?v=0.1"></script>
<script>
jQuery(function() {
// Instantiate new game with numOfDiscs = 3.
var game = new Game({
numOfDiscs: 3,
// Callback after object game is initialized.
afterInit: function(g) {
jQuery('#max-step').text(g.maxSteps);
},
// Callback after steps is performed.
afterStep: function(g) {
var steps = g.getSteps();
jQuery('#step').text(steps);
setTimeout(function() {
if ( g.isWin() === 1 ) {
alert("Hai Vinto!");
g.freeze();
} else if (steps >= g.getMaxSteps()) {
alert("Gioco Terminato");
g.freeze();
}
}, 200);
}
});
var stepInformation = jQuery('#step-information');
var stepInfoText;
// Callback can be given later to game object.
// Callback when the game is paused.
game.onPause = function(g) {
// Backups the step text.
stepInfoText = stepInformation.html();
// Replaces information step with pause information.
stepInformation.html('Game paused');
jQuery('#pause').text('Resume');
};
game.onResume = function(g) {
// Restores the steps information.
stepInformation.html(stepInfoText);
jQuery('#pause').text('Pause');
}
jQuery('#pause').click(function(e) {
if (game.state === 'playing') {
game.pause();
} else if (game.state === 'pause') {
game.resume();
}
e.preventDefault();
});
jQuery('#restart').click(function(e) {
game.restart();
jQuery('#max-step').text(game.maxSteps);
jQuery('#step').text(0);
e.preventDefault();
});
// Callback when number of discs or pegs is changed.
function gameChange() {
if (!confirm("Faccio ripartire il gioco, ok?")) {
return false;
}
var pegs = jQuery('#number-of-pegs').val();
var discs = jQuery('#number-of-discs').val();
game.restart({
numOfPegs: pegs,
numOfDiscs: discs,
destinationPeg: pegs,
});
jQuery('#max-step').text(game.maxSteps);
jQuery('#step').text(0);
}
jQuery('#number-of-pegs').change(gameChange);
jQuery('#number-of-discs').change(gameChange);
});
</script>
</body>
</html>
///(Fine file: TorreHanoi.html)
///File: hanoi.c
#include "HanoiSimulatore.h"
#include <stdio.h>
unsigned int mosse=0;
// --- IL TUO ESERCIZIO RICORSIVO -------------------------------------
void Hanoi(int n, int da, int a, int appoggio) {
// n==dischi, da == piolo partenza, a == piolo arrivo, appoggio = piolo appoggio
// Caso base: se c'è solo 1 disco, lo sposti direttamente dal piolo di partenza a quello di arrivo
mosse++;
if (n == 1) {
//MuoviDisco(da, a, appoggio);
printf("Muovi un disco da %d a %d\n",da,a);
return;
}
// 1. Sposta n-1 dischi dal piolo di partenza a quello di appoggio, usando l'arrivo come transito
Hanoi(n - 1, da, appoggio, a);
// 2. Muovi il disco più grande rimasto sul piolo di partenza direttamente all'arrivo
//MuoviDisco(da, a, 50); // Richiamo grafica Hanoi.h
printf("Muovi un disco da %d a %d\n",da,a);
// 3. Sposta gli n-1 dischi dall'appoggio al piolo di arrivo definitivo, usando la partenza come transito
Hanoi(n - 1, appoggio, a, da);
}
// --------------------------------------------------------------------
int main(void) {
int dischi;
printf("Quanti dischi ? ->"); // fino a un massimo di 8 per la grafica
scanf("%d", &dischi);
// Inizializza l'ambiente grafico con il numero di dischi scelto
// InizializzaSimulazione(dischi);
// Avvia il tuo algoritmo dicendo di muovere i dischi dal piolo 1 al piolo 3 usando il 2 come appoggio
Hanoi(dischi, 1, 3, 2);
printf("\n\nMosse fatte = %d\n",mosse);
// Gestisce la chiusura finale e blocca la finestra per farti vedere il risultato
// ChiudiSimulazione();
return 0;
}
///(Fine file: hanoi.c)