Entra

View Full Version : [C] Tic-Tac-Toe


-hide-
10-07-2012, 15:53
Una buona giornata a tutti.
Da un paio di giorni mi cimento nello sviluppo del mio primo videogames, il più semplice da implementare molto probabilmente, al fine di migliorare la mia tecnica di stesura del codice e le interazioni tra funzioni e, perché no, per avvicinarmi al mondo dei videogiocatori.

Nel codice che vi allego al seguente post noterete sia presente solo la modalità "Player vs Player", questo perché prima di proseguire vorrei chiedervi dei consigli e dei pareri in merito.

int main (void) {

int tavola[10]; /* Campo di gioco */
char index = 1; /* Variabile di ingresso al ciclo infinito del menù */

system (CLEARSCREEN);

/* Visualizzo schermata iniziale di scelta */
for (; index != 27;) { // 27 è il corrispettivo carattere ASCII di ESC
screen_init ();
fflush (stdin);
index = getchar ();
while (getchar () != '\n'); //Evita di far ripetere il printf successivo

switch (index) {

case '1':
system (CLEARSCREEN);
Player_vs_Player (tavola);
system (CLEARSCREEN);
break;

case '2':
system (CLEARSCREEN);
printf("\n\n\n\t\tLa funzione attualmente\n\t\tnon è implementata");
getchar ();
system (CLEARSCREEN);
break;

case '3':
system (CLEARSCREEN);
printf("\n\n\n\t\tLa funzione attualmente\n\t\tnon è implementata");
getchar ();
system (CLEARSCREEN);
break;

case 'c':
system (CLEARSCREEN);
printf("\n\n\n\t\tLa funzione attualmente\n\t\tnon è implementata");
getchar ();
system (CLEARSCREEN);
break;

case 'i':
system (CLEARSCREEN);
screen_instructions ();
system (CLEARSCREEN);
break;

case 's':
system (CLEARSCREEN);
printf("\n\n\n\t\tLa funzione attualmente\n\t\tnon è implementata");
getchar ();
system (CLEARSCREEN);
break;

default:
system (CLEARSCREEN);
break;

}

}

return 0;

}


In grassetto ho evidenziato il primo quesito che vorrei porvi. Quelle righe di codice servono per indirizzare il programma alla scelta effettuata dall'utente prima digitando il tasto di scelta e poi invio per confermare. Se, però, erroneamente si digita invio come sceltà di menù, il programma attende un nuovo invio per procedere oltre generando un ritorno a capo davvero poco elegante. Inoltre, premendo il tasto su il terminale visualizzarà ^]]A dove i primi due caratteri corrispondono proprio ad ESC e, confermando la scelta, causerà un'uscita dal programma non richiesta. Sommando questi due difetti e sperando di essere stato chiaro (provare direttamente è molto meglio) mi domando se è possibile sostituire il meccanismo di scelta "a due tasti" in un meccanismo "a singolo tasto" (esempio - dopo la sola pressione di ESC si termina il programma; dopo la sola pressione di 1 si accede alla modalità Player vs Player; ecc..)

Altro difetto non di poco conto che ho notato. Una volta fatto accesso a qualsiasi schermata tranne Player vs Player, digitando più volte (2 o più se necessario) una delle opzioni da me scelte per gestire lo switch-case e confermando con invio invece di tornare alla schermata principale, come io mi aspetterei, entra direttamente in una delle schermate corrispondente alla scelta effettuata. Credo il problema stia nel getchar () ma come è risolvibile.

Prima di procedere oltre e mettere ulteriore carne al fuoco preferirei trovare soluzione ai due dilemmi esposti.
Ho il timore di non essere stato particolarmente chiaro ma alcuni concetti sono meglio esplicabili con il metodo visivo che con quello orale/testuale per questo vi invito a provare il programma.

valerio65
10-07-2012, 19:10
Usa la funzione getch () includendo la libreria <conio.h>

L'utilizzo è questo:

char c;
c = getch();

Legge un carattere direttamente dallo STDIN, senza necessità di premere invio. Ovviamente con gli opportuni controlli (magari con un do while) impedirai di digitare i caratteri non consentiti o che non servono!

Spero di esserti stato utile! ;)

-hide-
13-07-2012, 10:42
Usa la funzione getch () includendo la libreria <conio.h>

L'utilizzo è questo:

char c;
c = getch();

Legge un carattere direttamente dallo STDIN, senza necessità di premere invio. Ovviamente con gli opportuni controlli (magari con un do while) impedirai di digitare i caratteri non consentiti o che non servono!

Spero di esserti stato utile! ;)

Mi sei stato utile ma la conio.h gira solo su Win mi pare di capie, per UNIX che si fa? :D

-hide-
13-07-2012, 12:28
su linux/gcc c'è la libreria ncurses che dovrebbe mettere a disposizione delle funzioni opportune.

http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/scanw.html

La getch () non funziona, mi da questo errore in compilazione.
Undefined symbols:
"_stdscr", referenced from:
_main in ccQGKLtP.o
"_wgetch", referenced from:
_main in ccQGKLtP.o
ld: symbol(s) not found
collect2: ld returned 1 exit status


L'ho utilizzata allo stesso modo di come riportata sopra.

-hide-
13-07-2012, 14:31
Non ho utilizzato quella dicitura ma il problema pare essersi risolto :mbe:

Ora mi sono accorto di un'altro difetto:
void Player_vs_Player (int *tavola) {

int i, k,
player = 0, /* Inizializzato a 0. */
/* Impostato ad 1 se gioca X, a 2 se gioca O */
winner = 0, /* Registra la presenza di un vincitore. */
/* Impostato ad 1 se vince X, a 2 se vince O */
move_valida; /* Verifica la validità della mossa effettuata */
char move = '0'; /* Registra l'ultima mossa effettuata */

/* Pulisco il campo di gioco */
for (k=0; k<10; tavola [k++]=0);

/* Visualizzo il campo di gioco aggiornato */
screen_game (tavola);

for (i=0; i<9 && winner==0; i++) {


/* Aggiorno il personaggio giocante */
player = i%2 + 1;

/* Inserisco una mossa e ne verifico la validità */
for (move_valida=0; !move_valida;) {
printf("\n\tPlayer%d inserisce la mossa: ", player);
move = getchar ();
my_fflush ();
if(move == 27)
return;
if( isdigit(move) && move>='1' && move<='9' ) {
if (tavola[atoi(&move)]==0)
move_valida=1;
else {
system (CLEARSCREEN);
screen_game (tavola);
printf("\n\tATTENZIONE: mossa non valida\n");
}
}
else {
system (CLEARSCREEN);
screen_game (tavola);
printf("\n\tATTENZIONE: mossa non valida\n");
}
}

/* Visualizzo il campo aggiornato */
system (CLEARSCREEN);
tavola[atoi(&move)]=player;
screen_game (tavola);

/* Verifico la resenza di un vincitore */
winner = verifica_winner (tavola);

}

/* Visualizzo a schermo il risultato della partita */
if (winner==0)
printf("\n LA PARTITA E' TERMINATA IN PARITA'");
else
printf("\n\t THE WINNER IS: PLAYER%d", winner);

}

Quel getchar () con il my_fflush (), che svuota il buffer, fanno si che immettendo il numero 1 come scelta della mossa o immettendo il numero 11, 12, 13, 111, 1487540740, ecc, non cambi nulla perché leggerà solo il primo carattere. Come fare a rendere differente l'1 dagli altri numeri che inizino per 1?

-hide-
16-07-2012, 14:39
Nell'utilizzo della libreria ncurses (davvero carina) sto trovando un problema nella riga che vi evidenzio nel codice:
/* Modalita' di gioco Umano vs Umano */
void Player_vs_Player(int *tavola) {

int i, k,
player = 0, /* Inizializzato a 0. */
/* Impostato ad 1 se gioca X, a 2 se gioca O */
winner = 0, /* Registra la presenza di un vincitore. */
/* Impostato ad 1 se vince X, a 2 se vince O */
move_valida; /* Verifica la validita' della mossa effettuata */
char move = '0'; /* Registra l'ultima mossa effettuata */

initscr();

/* Pulisco il campo di gioco */
for(k=0; k<10; tavola[k++]=0);

/* Visualizzo il campo di gioco aggiornato */
screen_game(tavola);
refresh();

for(i=0; i<9 && winner==0; i++) {

/* Aggiorno il personaggio giocante */
player = i%2 + 1;

/* Inserisco una mossa e ne verifico la validita' */
for(move_valida=0; !move_valida;) {
printw("\n\tPlayer%d inserisce la mossa: ", player);
refresh();
move = getch();
if(move == 27)
return;
else if( isdigit(move) && move>='1' && move<='9' ) {
getch();
if (tavola[atoi(&move)]==0) { /* NON FUNZIONA QUESTO CONFRONTO */
printw("\tdebug-\n");
move_valida=1;
}
else {
erase();
screen_game(tavola);
printw("\n\tATTENZIONE: mossa non valida\n");
printw("\tdebug1\n");
refresh();
}
}
else {
erase();
screen_game(tavola);
printw("\n\tATTENZIONE: mossa non valida\n");
printw("\tdebug2\n");
refresh();
}
}

/* Visualizzo il campo aggiornato */
erase();
tavola[atoi(&move)]=player;
screen_game(tavola);
refresh();

/* Verifico la presenza di un vincitore */
winner = checkwin(tavola);

}

/* Visualizzo a schermo il risultato della partita */
if (winner==0)
printw("\n LA PARTITA E' TERMINATA IN PARITA'");
else
printw("\n\t THE WINNER IS: PLAYER%d", winner);
refresh();

endwin();
return;
}


Come commentato, quel confronto non funziona assolutamente e tramite i printw di debug inseriti si può verificare come si comporta il programma. Di cosa può trattarsi, qualche conflitto con la libreria ncurses?

-hide-
17-07-2012, 14:06
up1