Come scrivere un programma Tic-Tac-Toe in Java

Introduzione:

Tic-Tac-Toe è un gioco molto comune che è abbastanza facile da giocare. Le regole del gioco sono semplici e ben note. A causa di queste cose, Tic-Tac-Toe è abbastanza facile da codificare. In questo tutorial, vedremo come codificare un gioco funzionante di Tic-Tac-Toe in Java. In questa esercitazione si presuppone la conoscenza della sintassi di base di Java e l'accesso a un compilatore Java funzionante. Questo tutorial utilizzerà l'IDE Eclipse.

Schema generale:

Esistono molti modi per implementare un gioco di Tic-Tac-Toe in Java, quindi prima di iniziare a programmare, dobbiamo pensare a come implementeremo il gioco in modo specifico. Per questo tutorial, codificheremo una versione testuale di Tic-Tac-Toe. Il nostro Tic-Tac-Toe inizierà stampando il tabellone e quindi chiedendo input al primo giocatore che specificherà dove sul tabellone posizionare il segno di quel giocatore. Dopo aver posizionato il segno, stamperemo di nuovo lo stato del tabellone e quindi chiederemo la mossa all'altro giocatore. Tale processo continuerà fino a quando un giocatore vince o il tavolo viene riempito (indicando che si è verificato un pareggio). L'input che verrà utilizzato per specificare dove posizionare un segno sarà nel formato di due numeri interi, che specificano la riga e la colonna in cui deve essere posizionato il segno. Di seguito è riportato un esempio di come verrà giocato un gioco.

Passaggio 1: creazione del progetto

Il primo passo per scrivere un codice è creare un nuovo progetto! Nel tuo IDE, crea un nuovo progetto Java chiamato TicTacToe. In questo Instructable, il pacchetto predefinito è quello che verrà utilizzato. All'interno del pacchetto di progetto, crea due classi: Main.java e TTT.java. Main.java ospiterà il metodo principale e verrà utilizzato per eseguire il codice in TTT.java. TTT.java conterrà un oggetto Tic-Tac-Toe che contiene lo stato del tabellone e i metodi per manipolare il gioco.

Passaggio 2: avvio della classe TTT

Prima di poter creare codice per eseguire il nostro oggetto TTT, dobbiamo creare un oggetto TTT funzionante. Poiché un oggetto TTT è rappresentativo di un gioco di Tic-Tac-Toe, deve contenere due variabili membro. Di seguito sono riportate le variabili membro che devono essere inserite nella classe TTT seguite da descrizioni del motivo per cui sono necessarie.

private char [] [] board;

Questa variabile è una matrice 2D di personaggi che sarà rappresentativa della tavola tre per tre di un gioco di Tic-Tac-Toe. Manterrà lo stato del gioco all'interno dell'oggetto TTT in qualsiasi momento.

char privato currentPlayerMark;

Questa variabile conterrà una 'x' o una 'o', che rappresenta il turno del giocatore in un dato momento. I metodi della classe TTT lo useranno quando si segna la scheda per determinare quale tipo di segno verrà posizionato.

Passaggio 3: inizializzazione dei prototipi dei metodi nella classe TTT

Di seguito è una configurazione generale del programma. Di seguito sono riportate tutte le intestazioni dei metodi per i metodi che appartengono alla classe TTT. Questi metodi agiranno sulle variabili membro della classe TTT per rendere mutevole il gioco del Tic-Tac-Toe. Ognuno ha una breve descrizione di ciò che il metodo farà sotto di esso. Questi comportamenti sono necessari per giocare una partita completa di Tic-Tac-Toe.

TTT pubblico ()

Questo è il costruttore. Sarà responsabile di assicurare che il tabellone venga inizializzato correttamente e di stabilire chi sarà il primo giocatore.

public void initializeBoard ()

Questo metodo inizializzerà la variabile della scheda in modo tale che tutti gli slot siano vuoti.

public void printBoard ()

Questo metodo stampa la scheda Tic-Tac-Toe sull'output standard.

pubblico booleano isBoardFull ()

Questo metodo verificherà se la scheda è piena o meno. Restituirà vero se la scheda è piena e un falso altrimenti.

pubblica booleana checkForWin ()

Questo metodo verificherà se un giocatore ha vinto e, in tal caso, tornerà vero.

check booleano privatoRowsForWin ()

Questo metodo controllerà specificamente le righe per una vittoria.

check booleano privatoColumnsForWin ()

Questo metodo controllerà specificamente le colonne per una vittoria.

check booleano privatoDiagonalsForWin ()

Questo metodo controllerà specificamente le diagonali per una vittoria.

privato booleano checkRowCol (char c1, char c2, char c3)

Questo metodo controllerà i tre caratteri specificati presi per vedere se tutti e tre sono la stessa lettera 'x' o 'o'. In tal caso, tornerà vero.

Nota : se si codificano gli stub del metodo per tutte le intestazioni del metodo nella classe TTT, il compilatore probabilmente informerà che il codice presenta errori. E 'normale. Il compilatore si aspetta semplicemente che venga restituito un valore per tutti i metodi non nulli.

Passaggio 4: inizializzare la scheda

public void initializeBoard ()

Questo imposterà la scheda su tutti i valori vuoti. All'interno di questo metodo, è necessario creare 2 per loop l'uno all'interno dell'altro che passeranno attraverso tutte le righe e le colonne impostando ogni spazio su '-'. Per scorrere tra le righe, crea un ciclo for e un numero intero, in questo caso denominato i, per rappresentare la riga che stiamo attualmente osservando.

per (int i = 0; i <3; i ++) {}

All'interno di questo per il ciclo, creeremo un secondo per il ciclo con un intero j per rappresentare quale colonna stiamo attualmente osservando.

per (int j = 0; j <3; j ++) {}

All'interno del secondo ciclo, impostiamo la posizione della scheda su '-'. Con entrambi i loop completati e nidificati correttamente, possiamo scorrere in ogni punto all'interno dell'array 2D della scheda.

board [i] [j] = '-';

In questa fase è allegata un'immagine che mostra una possibile implementazione del metodo initializeBoard ().

Passaggio 5: stampare la scheda

La scheda iniziale stampata apparirà come la prima immagine.

Sarà gestito con il metodo public void printBoard (), che si trova nella classe TTT. Per stampare la scheda dobbiamo accedere a tutti i luoghi dell'array 2D denominati board nella nostra classe TTT. Poiché abbiamo a che fare con un array 2D, questo verrà gestito con loop annidati.

Innanzitutto, dobbiamo solo stampare una linea di trattini (13 di questi in questo caso) che designano la parte superiore della scheda. Al di sotto di ciò, abbiamo bisogno di un ciclo for che attraversi ciascuna delle tre righe. Questo loop conterrà una chiamata per stampare un '|' carattere, un altro per il ciclo per scorrere tra le colonne e una chiamata alla funzione System.out.println () per stampare una nuova linea e i successivi 13 trattini sullo schermo.

Anche il nostro ciclo interno for passerà attraverso tre colonne. Poiché il nostro ciclo esterno per già stampato il primo | personaggio di ogni riga del tabellone, possiamo andare avanti per stampare il personaggio che appartiene alla scatola. Per fare ciò, stamperemo il carattere in quella riga e colonna usando board [i] [j] (i essendo la variabile usata per il ciclo esterno per, che era la riga, e j essendo la variabile usata per il ciclo interno, che è la colonna.) Questa dichiarazione di stampa conterrà anche un | carattere, per separare le caselle.

L'unica cosa rimasta è stampare l'ultima chiamata per stampare la nuova linea per separare ogni riga, seguita dai 13 trattini. La seconda immagine allegata mostra un esempio di come potrebbe apparire la funzione di stampa descritta.

Passaggio 6: Verifica della presenza di un vincitore (parte 1)

Esistono tre diverse funzioni per verificare la vincita: righe, colonne e diagonali. I computer devono separarli in condizioni diverse perché sono tutti diversi in termini di array. checkForWin () sarà la nostra funzione principale per testare tutte e 3 queste funzioni per ogni scenario interessato dall'input dell'utente.

Per il metodo checkForWin (): hai semplicemente bisogno di un'istruzione return che richiami le tre diverse funzioni. Se il controllo delle righe per win non restituisce true, controllare le colonne per win, ecc. All'interno dell'istruzione return dovrebbe apparire come: checkRowsForWin () || checkColumnsForWin () || checkDiagonalsForWin ()

Per il metodo checkRowsForWin (): stiamo scorrendo le righe per vedere se ci sono vincitori. Ciò richiederà uno per il ciclo con un'istruzione if al suo interno. Il ciclo for verrà incrementato attraverso l'intero i in modo da controllare ogni riga. per (int i = 0; i <3; i ++) L'istruzione if confronta ogni spazio nella riga tra loro e fornisce un valore 'vero' se sono tutti uguali. Ad esempio, se la riga avesse tre x di fila, il metodo restituirebbe true. if (checkRowCol (board [i] [0], board [i] [1], board [i] [2]) == true) Quindi, all'interno di questa istruzione if, dovrebbe essere presente: return true; E dopo il ciclo for, se il metodo non si è mai fermato, il metodo deve restituire che questa riga non aveva tre simboli di corrispondenza consecutivi. Pertanto, proprio prima di chiudere il metodo con il suo '}' finale, scriveremo: return false; Soddisfacendo la necessità di restituire un valore booleano.

Per il metodo checkColumnsForWin (): copia e incolla il contenuto del metodo checkRowsForWin (). L'unica modifica sarà all'interno dell'istruzione if. Invece di aumentare attraverso le righe, aumenteremo attraverso le colonne. Quindi, mentre in checkRowsForWin ha un'istruzione if che dice: if (checkRowCol (board [i] [0], board [i] [1], board [i] [2]) == true) checkColumnsForWin () avrà un if istruzione che dice: if (checkRowCol (board [0] [i], board [1] [i], board [2] [i]) == true) A parte questo, tutto il resto nel metodo rimane lo stesso.

Per il metodo checkDiagonalsForWin (): tutto ciò che è stato scritto può essere contenuto tra parentesi di un'istruzione return (). Il primo controllo che eseguiremo è sulla diagonale dall'angolo in alto a sinistra all'angolo in basso a destra. Per fare ciò, controlliamo tutti gli spazi che verrebbero inclusi in questa sezione. checkRowCol (board [0] [0], board [1] [1], board [2] [2]) == true) Quindi avremo un'altra istruzione, ma separeremo i due con un simbolo OR: ' ||' La seconda istruzione controllerà dall'angolo in alto a destra nell'angolo in basso a sinistra. checkRowCol (board [0] [2], board [1] [1], board [2] [0]) == true) Quindi il tuo prodotto finale del metodo checkDiagonalsForWin () dovrebbe essere un return (), e al suo interno dovrebbe contenere la prima istruzione O la seconda istruzione.

Passaggio 7: Verifica la presenza di un vincitore (parte 2)

Ora dobbiamo assicurarci che se un giocatore ottiene tre di fila, vince. checkRowCol () sarà una funzione che confronterà tutte e tre le lettere tra loro, e se corrispondono, allora restituiranno true.

Per il metodo checkRowCol (): questo metodo viene utilizzato dagli altri metodi per inviare tre valori. Per prima cosa controlliamo che il primo valore non sia vuoto come '-'. Quindi confrontiamo il primo valore con il secondo, e il secondo con il terzo, e se e solo se tutti e tre i valori sono uguali E non sono istruzioni vuote, questo metodo restituirà true. Quindi all'interno di un'istruzione return (), la nostra prima istruzione verificherà che questo non sia un '-'. (c1! = '-') Separa la prima e la seconda istruzione con un '&&' La seconda istruzione vedrà se il primo valore è uguale al secondo valore. (c1 == c2) Separare la seconda e la terza istruzione con un '&&' La terza istruzione vedrà se il secondo valore è uguale al terzo. (c2 == c3) Quindi il tuo metodo checkRowCol () finale sarà un return () contenente la prima istruzione && la seconda istruzione && la terza istruzione.

Passaggio 8: cambio tra giocatori (x e O)

public void changePlayer ()

Il metodo changePlayer () scambia la variabile currentPlayerMark tra x e o. Per fare ciò, controlla cosa contiene attualmente la variabile. Se la variabile contiene una "x", cambiarla in una "o". Altrimenti, cambiarlo in una 'x'.

public boolean placeMark (int row, int col)

Il metodo placeMark () posizionerà la lettera corretta sulla riga e sul col specificati nella variabile board (considerata come parametri). Restituirà vero se fosse un posizionamento valido. Altrimenti, non verrà apportata alcuna modifica alla variabile board e il giocatore dovrà provare a posizionare la propria lettera in un posto diverso, in quanto è stato selezionato un punto non valido o un punto in cui un giocatore ha già posizionato la propria lettera. Per realizzare questo comportamento, è necessario verificare alcune cose. Innanzitutto, assicurati (usando un'istruzione if) che l'argomento riga sia compreso tra 0 e 2. Successivamente, verifica che l'argomento col sia compreso tra 0 e 2. Infine, verifica che il punto in questione contenga attualmente un '- ", indicando che nessun pagatore ha ancora segnato quel punto. Se tutte e tre queste condizioni sono verificate, posizionare un segno (il cui tipo è specificato dalla variabile di classe currentPlayerMark) nella posizione specificata da row e col e quindi restituire true. Se una delle tre condizioni non è soddisfatta, allora dovrebbe accadere una nota e dovrebbe essere restituito il falso.

In allegato a questo passaggio sono presenti immagini che mostrano possibili implementazioni dei metodi sopra menzionati.

Passaggio 9: input del giocatore e gioco

Ora che la classe TTT e tutti i suoi metodi sono stati completati, deve essere creato un metodo principale che attraversa un intero gioco di Tic-Tac-Toe usando l'oggetto TTT. Il metodo principale deve fare alcune cose per eseguire un gioco completo di Tic-Tac-Toe.

Innanzitutto, deve creare un oggetto Scanner per ricevere input da System.in. Inoltre, deve creare un'istanza di un oggetto TTT per giocare con il gioco Tic-Tac-Toe. Dopo queste cose, deve inizializzare la scheda dell'oggetto TTT chiamando il suo metodo initializeBoard ().

Dopo aver completato questi passaggi, è necessario tenere conto del gioco effettivo. Per superare i turni, è richiesto un ciclo do while. Il ciclo dovrebbe scoppiare quando il gioco termina, il che significa quando la tavola dell'oggetto TTT è piena o ha un vincitore. All'interno del loop, lo stato della tavola corrente deve essere stampato prima di ogni turno, quindi mostra al giocatore quali spazi sono disponibili e quali spazi sono occupati. Quindi, due input dovrebbero essere presi nel significare la riga e la colonna per posizionare un segno per il turno. Dopo aver inserito questo input, il segno dovrebbe essere posizionato usando il metodo dell'oggetto TTT, e anche il giocatore dovrebbe essere cambiato usando il metodo dell'oggetto TTT.

Sotto il ciclo while che gestisce tutti i turni fino alla fine del gioco, sarà necessario dichiarare chi è il vincitore del gioco (o se il gioco è stato un pareggio). Per fare questo, controlla se il gioco è stato un pareggio prima controllando se entrambi il tabellone era pieno e non c'erano vincitori. In questo caso, stampa che il gioco era in pareggio. Altrimenti, stampa chi ha vinto stampando l'opposto dello stato corrente della variabile currentPlayerMark dell'oggetto TTT. Ciò può essere ottenuto chiamando prima il metodo changePlayer () dell'oggetto TTT e quindi utilizzando il metodo getCurrentPlayerMark () dell'oggetto TTT per ottenere lo stato della variabile currentPlayerMark. Potrebbe anche essere utile stampare nuovamente la scheda per mostrare lo stato finale della scheda.

Un metodo principale di esempio è stato allegato come immagine.

Passaggio 10: utilizzare classe, compilazione ed esecuzione

Una volta arrivato a questo punto, il tuo progetto dovrebbe essere abbastanza completo per essere eseguito. Se ci sono errori o parentesi o punti e virgola mancanti, ora sarebbe il momento di trovarli e risolverli. Se ti sei perso per quanto riguarda l'aspetto del tuo progetto, abbiamo incluso un file scaricabile per confrontare il tuo codice con un prodotto finale funzionante. Vai avanti e compila il tuo progetto. In Eclipse c'è un pulsante di riproduzione che assomiglia all'immagine allegata a questo passaggio.

allegati

  • Download di Product.zip finale funzionante

Articoli Correlati