Scambio valori array. errore nel codice

kobeilprofeta
ciao. Sto facendo un programma che permette di giocare al gioco del 15 in c.
Ci sono 4 mosse a disposizione: sopra (fai scendere la casella sopra quella vuota), sotto, destra e sinistra.
Questo è il codice (è corto, se si esclude la parte di "scrittura a schermo"):
int i,a[16],v;
char go;
//funzione scambio
int s (int n, int m)
{
     int box;
     box=a[n];
     a[n]=a[m];
     a[m]=box;
     return (a[n]);
}
main()
{
for (i=1;i<16;i++)
{
    a[i]=i;
}
a[16]=0;
//inizio gioco
do
{
clrscr();
//cerca casella vuota
for (i=1;i<17;i++)
{
    if(a[i]==0)
    {v=i;}
    else {v=v;}
}
//regolamento
gotoxy (1,6);
printf ("Comandi:\nw: sopra\na: sinistra\ns: sotto\nd: destra\nee: uscire");
//tabella
gotoxy (1,1);
for (i=1;i<5;i++)
{
    if (a[i]<10)
    {printf ("%d",a[i]);}
    else if (a[i]==10)
    {printf ("A");}
    else if (a[i]==11)
    {printf ("B");}
    else if (a[i]==12)
    {printf ("C");}
    else if (a[i]==13)
    {printf ("D");}
    else if (a[i]==14)
    {printf ("E");}
    else if (a[i]==15)
    {printf ("F");}
    else if (a[i]==0)
    {printf (" ");}
}
printf ("\n");
for (i=5;i<9;i++)
{
    if ((a[i]<10)&&(a[i]!=0))
    {printf ("%d",a[i]);}
    else if (a[i]==10)
    {printf ("A");}
    else if (a[i]==11)
    {printf ("B");}
    else if (a[i]==12)
    {printf ("C");}
    else if (a[i]==13)
    {printf ("D");}
    else if (a[i]==14)
    {printf ("E");}
    else if (a[i]==15)
    {printf ("F");}
    else if (a[i]==0)
    {printf (" ");}
}
printf ("\n");
for (i=9;i<13;i++)
{
    if ((a[i]<10)&&(a[i]!=0))
    {printf ("%d",a[i]);}
    else if (a[i]==10)
    {printf ("A");}
    else if (a[i]==11)
    {printf ("B");}
    else if (a[i]==12)
    {printf ("C");}
    else if (a[i]==13)
    {printf ("D");}
    else if (a[i]==14)
    {printf ("E");}
    else if (a[i]==15)
    {printf ("F");}
    else if (a[i]==0)
    {printf (" ");}
}
printf ("\n");
for (i=13;i<17;i++)
{
    if ((a[i]<10)&&(a[i]!=0))
    {printf ("%d",a[i]);}
    else if (a[i]==10)
    {printf ("A");}
    else if (a[i]==11)
    {printf ("B");}
    else if (a[i]==12)
    {printf ("C");}
    else if (a[i]==13)
    {printf ("D");}
    else if (a[i]==14)
    {printf ("E");}
    else if (a[i]==15)
    {printf ("F");}
    else if (a[i]==0)
    {printf (" ");}
}
gotoxy (1,13);
printf ("\n\nvuota: %d",v);
go=getche();
//sopra
if (go=='w')
{
if ((v!=1)&&(v!=2)&&(v!=3)&&(v!=4))
{s(v,(v-4));}
}
//sotto
else if (go=='s')
{
if ((v!=13)&&(v!=14)&&(v!=15)&&(v!=16))
{s(v,(v+4));}
}
//destra
else if (go=='d')
{
if ((v!=4)&&(v!=8)&&(v!=12)&&(v!=16))
{s(v,(v+1));}
}
//sinistra
else if (go=='a')
{
if ((v!=1)&&(v!=5)&&(v!=9)&&(v!=13))
{s(v,(v-1));}
}
//prova 7-8
else if (go=='p')
{
if ((v!=1)&&(v!=5)&&(v!=9)&&(v!=16))
{s(7,8);}
}
//prova 1-2
else if (go=='o')
{
if ((v!=1)&&(v!=5)&&(v!=9)&&(v!=13))
{s(1,v);}
}
}while (go!='e');
getch();     
}

Il problema è che fa la prima mossa giusta: sembra che scambi correttamente il contenuto delle due caselle... ma in realtà non riesce a capire quale cella diventa vuota dopo la mossa. E le mosse successive sono un disastro. (provate ad eseguire, io faccio la prima mossa un 'w').

Grazie mille.

Risposte
apatriarca
NdM: Usa il tag code al posto del tag spoiler per inserire del codice..

apatriarca
L'errore principale del tuo codice è che gli indici in C partono da zero, mentre nel tuo codice parti sempre da uno. In particolare a[16] è oltre i limiti del tuo array. Con ogni probabilità stai scrivendo su di un'altra variabile.. ma potrebbe anche crashare. Mancano inoltre gli #include s all'inizio del codice e ti consiglierei di usare variabili locali al posto di quelle globali. Soprattutto per quanto riguarda i, v e go.

kobeilprofeta
ok. credo di aver capito. grazie mille.

Peró potresti gentilmente spiegarmi perchè mi conviene dichiarare le variabili dentro, e non fuori, dal main? (se ho capito giusto).

ps: gli include li ho scritti nel codice, ho solo evitato di riportarli qua nel topic.

apatriarca
La principale ragione per preferire l'uso di variabili locali al posto di quelle globali è per rendere il codice di più facile comprensione ed evitare alcuni errori.

Il tuo programma è ancora molto piccolo ma considera il seguente caso. Supponi di avere, come nel tuo codice, un contatore di cicli globali e di avere quindi una funzione che ne fa uso:
void f()
{
    for (i = 0; i < N; ++i) { /* ... */ }
}

Ad un certo punto supponi di dover fare l'operazione di f più volte in un qualche ciclo. Senza guardare il codice di f uno potrebbe essere tentato di scrivere qualcosa come:
for (i = 0; i < M; ++i) { f(); }

e chiedersi perché il codice funziona in modo così strano. Questo caso è forse ancora semplice, ma prova ad immaginare cosa succede se si aumentano il numero di variabili usate come contatori e il numero di funzioni. Ogni volta che cerchi di di inserire una funzione in un'altra diventa di colpo necessario doversi guardare tutto il codice della funziona che si vuole includere e di tutte quelle da essa richiamate. Diventa insomma presto un incubo. Se invece si usano principalmente variabili locali e ogni funzione accede principalmente alle variabili che le vengono passate come argomento, tutto diventa più semplice. È infatti sufficiente sapere cosa fa una funzione per usarla.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.