Oppure

Loading
20/05/12 13:42
eclix
Salve a tutti. Sto incontrando alcune difficoltà nell'implementazione di un algoritmo. Come da titolo, l'esercizio è riferito al cammino casuale di due pedine su una scacchiera (la traccia dell'esercizio è nel codice). Quello che non riesco a fare è tenere traccia del cammino della pedina, ed inoltre mi capita che a volte il cammino termina quando le due pedine si incontrano, mentre altre volte no. Qualcuno riesce a farmi capire qual è l'errore che faccio?? 8-|

/**Si vuole sviluppare un algoritmo del cammino casuale di una pedina. Un cammino si svolge su una scacchiera in cui ogni casella
rappresenta una possibile posizione del cammino della pedina. Stando in una casella, una pedina può muoversi solo nella casella
a destra, nella casella a sinistra, nella casella sopra o nella casella sotto. La scelta di una tra queste quattro caselle deve
essere fatta a caso (generando per esempio un numero intero in {0,1,2,3}).
Ogni movimento da una casella all’altra è detto passo del cammino. L’algoritmo usa un array 2D nxn, con n=30, per simulare la scacchiera.
Ci sono due pedine sulla scacchiera, e all’inizio una si trova nella casella in alto a sinistra e l’altra nella casella in basso a destra.
A ogni movimento di una pedina, segue il movimento dell’altra pedina. Fare attenzione al movimento di una pedina quando si trova sul bordo
della scacchiera. L’algoritmo procede finché accade che le due pedine tentano di muoversi sulla stessa casella della scacchiera; in tal caso
l’algoritmo termina (cammino terminato), restituendo il numero di passi effettuati. Organizzare l’algoritmo come una function che restituisce
il numero di passi (lunghezza) del cammino. Scrivere un main che per 100 volte chiama la function e visualizza la lunghezza di ogni cammino
effettuati.**/

Ultima modifica effettuata da eclix 11/06/12 17:43
aaa
21/05/12 13:58
subazu
23: Perché passi singolarmente tutti quei valori quando puoi passare direttamente le 2 struct "ped_1" e "ped_2"? con una semplice modifica puoi inserire anche il carattere che rappresenta la pedina nella struttura

Come mai disegni il movimento delle pedine a video se non è richiesto nella consegna?

Ultima modifica effettuata da subazu 21/05/12 14:40
aaa
22/05/12 7:59
eclix
Cioè cosa dovrei fare esattamente? È da poco che ho cominciato a programmare in C, non sono una cima :D.

Scusa come faccio a stabilire se il cammino termina una volta che le due pedine si incontrano senza vederlo prima?
aaa
22/05/12 15:59
subazu
intanto puoi modificare il prototipo della funzione da così:
int function_mia (char [][N], int *, int *, char, int *, int *, char);

a così
int function_mia (struct pedina*, struct pedina*);

apportando però prima delle modifiche alla struttura
1 dargli un nome (struct pedina{....} al posto di struct {})
2 inserirci una variabile di tipo char nella struttura

in modo che poi all'interno della funzione tu possa usare le variabili utilizzando questa sintassi:
void funzioneProva(struct pedina *p){
  *p.x = 10;
  *p.y = 15;
  *p.simbolo = 'x';
}
aaa
25/05/12 17:17
eclix
Ma funzioneProva sarebbe una nuova funzione per poter gestire ogni singola pedina?? Non riesco a capire! :-|
aaa
25/05/12 19:16
subazu
Non mi sono spiegato bene, la funzione "function_mia" ha come prototipo:
int function_mia (char [][N], int *, int *, char, int *, int *, char);

Passare così tanti parametri alla funzione può essere solo che fonte di errore, no?
Non sarebbe più comodo passare le "pedine" alla funzione, invece che ogni loro capo?
così è come invochi tu la tua funzione:
conta_passi=function_mia(walk, &ped_1.x, &ped_1.y, pawn1, &ped_2.x, &ped_2.y, pawn2);

così è come dovresti invocarla
conta_passi=function_mia(walk, &ped_1, &ped_2);

Questo è solo un consiglio che è però necessario seguire per programmare correttamente, anche non seguendolo il programma funzionerà, ma la sua fluidità logica ne risente.

Per il tuo problema principale invece devi ripensare un attimo a cosa devi fare.
Intanto in informatica i concetti: "scrivere", "leggere" e sopratutto "vedere" sono sempre relativi.

Per vedere se due pedine sono nello stesso posto basta confrontarne le coordinate
if ((p1.x == p2.x) && (p1.y == p2.y)) {
   //le pedine sono nello stesso posto
}
else{
  //le pedine sono in posti diversi
}

La parte logica del programma deve essere, indipendente da ciò che vedi a video.
Non so se è chiaro ma la parte video (i caratteri del terminale per intenderci) sono l'ultima cosa a cui devi pensare, prima devi pensare alle variabili, ai loro valori, e a come gestirle.

Il problema è chiaro, devi:
1posizionare** le pedine
2fino a che non si scontrano
1muovi una delle pedine (prima una, il ciclo dopo l'altra)
3fine.

**anche posizionare in questo caso è relativo, infatti non devi posizionare proprio niente da nessuna parte, questo perché a te interessano solo le coordinate delle pedine (tralascia il comparto video per ora, lo risolviamo in seguito).
aaa
25/05/12 23:48
eclix
allora... ho aggiustato un pochino il codice apportando delle modifiche mie e dei vari suggerimenti che mi hai dato aggiungendo man mano anche dei commenti per ogni riga.
Ti posto ora l'intero codice in modo tale che tu abbia una panoramica più chiara di cosa abbia potuto combinare XD
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 30
#define SU 0
#define GIU 1
#define DESTRA 2
#define SINISTRA 3
//struttura
struct pedina {
    int x;
    int y;
    char simb;
    };
// viene definito un nuovo tipo 'Pedina'
typedef struct pedina Pedina;
//prototipi delle function
void build_chess(char [][N]);
void show_chess(char v[][N]);
void movimento_casuale(char [][30],Pedina*,int);
int function_mia (char [][N], Pedina *, Pedina *);

void main ()

{

    Pedina p1={0,0,''}, p2={29,29,'y'}; /* le pedine p1 e p2 sono variabili di tipo struttura alle quali vengono assegnate,
    per ciascuna pedina, le proprie coordinate (1° campo e 2° campo) e il corrispettivo simbolo (3° campo)*/
    char walk[N][N]; //dichiarazione della matrice (scacchiera 30x30)
    int conta_passi;// variabile utilizzata per chiamare la function che dovrebbe restituire il numero dei passi delle pedine
    build_chess(walk); //chiamata alla void function che costruisce la scacchiera
    walk[p1.x][p1.y]=p1.simb; //postazione iniziale della pedina1
    walk[p2.x][p2.y]=p2.simb; //postazione iniziale della pedina2
    printf("\n");
    show_chess(walk); //chiamata alla procedura per la visualizzazione su schermo della scacchiera
    system("pause");
    system("cls"); //pulisce lo schermo
    conta_passi=function_mia(walk, &p1, &p2);
    printf("Cammino terminato!\nNumero di passi eseguiti: %d", conta_passi);

}



/*La void function seguente esegue lo spostamento della pedina in base alla direzione ottenuta attraverso la chiamata alla rand.
Per ciascun caso (case) viene stabilito l'intervallo delle coordinate entro le quali la pedina può eseguire lo spostamento, evitando, in tal modo,
che essa possa uscire fuori dai bordi della scacchiera*/

void movimento_casuale(char walk[][30], Pedina *pawn,int direz)
{

    switch(direz)
    {
        case SU:	    if((*pawn).x==0)
                        {walk[(*pawn).x][(*pawn).y]='.'; walk[++(*pawn).x][(*pawn).y]=(*pawn).simb;}
                        else
                        {walk[(*pawn).x][(*pawn).y]='.'; walk[--(*pawn).x][(*pawn).y]=(*pawn).simb;}          break;//pedina verso nord

		case GIU:       if((*pawn).x==N-1)
                        {walk[(*pawn).x][(*pawn).y]='.'; walk[--(*pawn).x][(*pawn).y]=(*pawn).simb;}
		                else
		                {walk[(*pawn).x][(*pawn).y]='.'; walk[++(*pawn).x][(*pawn).y]=(*pawn).simb;}          break;//pedina verso sud

		case SINISTRA:  if((*pawn).y==0)
                        {walk[(*pawn).x][(*pawn).y]='.'; walk[(*pawn).x][++(*pawn).y]=(*pawn).simb;}
		                else
		                {walk[(*pawn).x][(*pawn).y]='.'; walk[(*pawn).x][--(*pawn).y]=(*pawn).simb;}          break;//pedina verso ovest

		case DESTRA:	if((*pawn).y==N-1)
                        {walk[(*pawn).x][(*pawn).y]='.'; walk[(*pawn).x][--(*pawn).y]=(*pawn).simb;}
                        else
                        {walk[(*pawn).x][(*pawn).y]='.'; walk[(*pawn).x][++(*pawn).y]=(*pawn).simb;}          break;//pedina verso est
	}

}
int function_mia (char walk[][N], Pedina *p1, Pedina *p2)
{
    int direz, passi=0;
    //il ciclo while termina una volta che entrambe le pedine si trovano sulla stessa casella
    while (walk[(*p1).x][(*p1).y]!=walk[(*p2).x][(*p2).y]){
        srand((unsigned)time(0));

        direz=rand()%4;
        movimento_casuale(walk, p1,direz); //chiamata alla function per effettuare il cammino della pedina 1
        show_chess(walk); //stampa a video del movimento della pedina 1

        system("cls");
        direz=rand()%4;
        movimento_casuale(walk, p2,direz); //chiamata alla function per effettuare il cammino della pedina 2
        show_chess(walk); //stampa a video del movimento della pedina 2

        system("cls");
        passi++; //incremento della variabile 'passi' fintanto che non termina il ciclo while (pedine nella stessa casella)

}return passi;
}



Situazione migliorata o peggiorata? XD
Ah... ti ringrazio per l'aiuto e l'impegno che mi stai prestando... :)
Ultima modifica effettuata da eclix 14/06/12 17:32
aaa
27/05/12 20:08
subazu
Ecco, io direi molto bene, già solo con 2 modifiche alla struttura tutto il programma ne giova.
Un altro modo per passare i parametri alle funzioni è per reference, e si fa così
int function_mia (char [][N], Pedina &, Pedina &);

con questo tipo di parametri puoi accedere ai campi della struttura con una sintassi semplificata, da così
(*pawn).x=0;

a così
pawn.x=0;


Il prossimo passo è fare il restyling del main, anche se non è corretto che ti imposti io l'intero programma, in questo caso ti risparmio un sacco di teoria, ovvio che hai l'obbligo di mettere in discussione i miei metodi dove non ti garbano, e ricevere delle spiegazioni :k:

Prima di tutto io diminuirei al minimo le istruzioni base dal main, non so se hai mai sentito del principio "divide et impera", bene tienilo sempre a mente.
Atomizzare il codice, spezzettare e dividere in unità più piccole tutto ciò che si può porta ad un sacco di vantaggi
- leggibilità maggiore
- meno errori
- facilita la correzione e gli upgrade
- rende più facile scovare i bug
- ecc.
Per programmi così piccoli non dovrebbe essere necessario tutto questo rigore, ma prima si impara a programmare così, prima si è in grado di capire quando non è necessario farlo.
io ad esempio farei così;
void main (){
    //variabili
    Pedina p1, p2; //pedine
    int conta_passi; //contatore
    int nPed= TRUE ; //true se ped1, false se ped2
    //inizializzazione
    initialize(p1,p2); //imposta i valori iniziali alle pedine

    while (! ((p1.x == p2.x) && (p1.y == p2.y))){ //se due pedine non hanno coordinate uguali
        system("cls"); //pulisce lo schermo
        show_chess(p1,p2); //disegno le 2 pedine
        //muovo a turno una delle pedine
        if (nPed) {
            //muovo la pedina 1
            movimento_casuale(p1);
            nPed = ! nPed; //cambio la pedina che verrà mossa il giro dopo
        }
        else{
            //muovo la pedina 2
            movimento_casuale(p2);
            nPed = ! nPed;
        }
        conta_passi++; //incremento il numero di mosse
        }
    }
    printf("Cammino terminato!\nNumero di passi eseguiti: %d", conta_passi);
}

Se hai qualche dubbio chiedi, anche se leggendo solo i commenti il codice si spiega da solo.
Devi intanto capire come funziona, per le altre implementazioni ci penserai dopo, sono comunque tutte molto semplici (non ti spaventare se non vedi la matrice perché in realtà non ti serve)
Credo che questo sia una impostazione abbastanza carina, il codice non è testato e potrebbero esserci degli errori di SINTASSI.
Ultima modifica effettuata da subazu 27/05/12 20:14
aaa