El servidor és l'encarregat de gestionar les connexions dels jugadors
i emparellar-los perquè juguen entre ells.
El servidor esperarà a que es connecten dos jugadors perquè comencen una partida entre ells.
Quan dos jugadors es connecten, llançarà un nou fil que gestionarà la partida entre els dos jugadors.
El codi font és el següent:
TicTacToeServer.java
packageud3.exercises.tictactoe.server;importjava.io.IOException;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.ArrayList;importjava.util.List;importjava.util.Scanner;publicclassTicTacToeServerextendsThread{ServerSocketserver;List<TicTacToeGame>games;TicTacToeGamenextGame;booleanrunning;publicTicTacToeServer(intport)throwsIOException{server=newServerSocket(port);games=newArrayList<>();nextGame=newTicTacToeGame(0);running=true;}publicvoidclose(){running=false;this.interrupt();}/** * TODO: Execució del servidor. * <p> * El servidor accepta les connexions dels clients. * Quan dos jugadors es connecten, els emparella per començar una partida. */@Overridepublicvoidrun(){while(running){try{// TODO}catch(IOExceptione){System.err.println("Error while accepting new connection");System.err.println(e.getMessage());}}}publicstaticvoidmain(String[]args){try{Scannerscanner=newScanner(System.in);TicTacToeServerserver=newTicTacToeServer(1234);server.start();scanner.nextLine();server.close();}catch(IOExceptione){thrownewRuntimeException(e);}}}
TicTacToeServerPlayerHandler.java
packageud3.exercises.tictactoe.server;importud3.exercises.tictactoe.models.BoardChoice;importud3.exercises.tictactoe.models.TicTacToeMessage;importud3.exercises.tictactoe.models.TicTacToeMessageType;importjava.io.*;importjava.net.Socket;import staticud3.exercises.tictactoe.models.TicTacToeMessageType.*;publicclassTicTacToeServerPlayerHandler{privatefinalSocketsocket;privatefinalObjectOutputStreamout;privatefinalObjectInputStreamin;publicTicTacToeServerPlayerHandler(Socketsocket)throwsIOException{this.socket=socket;this.in=newObjectInputStream(socket.getInputStream());this.out=newObjectOutputStream(socket.getOutputStream());}publicvoidsendMessage(TicTacToeMessageTypetype,Stringmessage)throwsIOException{out.writeObject(newTicTacToeMessage(type,message));}publicvoidsendMessage(TicTacToeMessageTypetype,Stringmessage,Objectobj)throwsIOException{TicTacToeMessageticTacToeMessage=newTicTacToeMessage(type,message);ticTacToeMessage.setObject(obj);out.writeObject(ticTacToeMessage);}publicvoidsendMessage(TicTacToeMessageTypetype)throwsIOException{out.writeObject(newTicTacToeMessage(type));}publicBoardChoicegetChoice()throwsIOException,ClassNotFoundException{TicTacToeMessagereceivedMessage=(TicTacToeMessage)in.readObject();while(receivedMessage.getType()!=POST){sendMessage(ERROR,"Expected a POST message.");receivedMessage=(TicTacToeMessage)in.readObject();}return(BoardChoice)receivedMessage.getObject();}publicvoidclose()throwsIOException{this.socket.close();}}
Com que és una aplicació amb múltiples clients,
la gestió de cada client és independent en el seu propi fil d'execució.
Aquest fil és l'encarregat de portar a terme la partida entre els dos jugadors connectats.
Internament, emmagatzemara el tauler Board amb l'estat de la partida actual.
Preguntarà per torns als jugadors per un moviment, que anirà actualitzant en el seu tauler. A més,
comunicarà a cada jugador els moviments perquè el client puga actualitzar el seu tauler.
La comunicació es gestionarà mitjançant objectes TicTacToeMessage, el qual té un TicTacToeMessageType, un missatge i un objecte.
TicTacToeGame.java
packageud3.exercises.tictactoe.server;importud3.exercises.tictactoe.models.Board;importud3.exercises.tictactoe.models.BoardChoice;importud3.exercises.tictactoe.models.TicTacToeMessageType;importjava.io.IOException;importjava.net.Socket;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.ThreadLocalRandom;import staticud3.exercises.tictactoe.models.TicTacToeMessageType.*;publicclassTicTacToeGameextendsThread{privatefinalintid;privatefinalList<TicTacToeServerPlayerHandler>players;privatefinalBoardboard;privatebooleanfinished;privateintcurrentPlayer;publicTicTacToeGame(intid){this.id=id;this.players=newArrayList<>();board=newBoard();finished=false;}publicvoidaddPlayer(Socketclient)throwsIOException{if(players.size()<2)players.add(newTicTacToeServerPlayerHandler(client));}publicbooleanenoughPlayers(){returnplayers.size()>=2;}publicTicTacToeServerPlayerHandlergetCurrentPlayer(){returnplayers.get(currentPlayer);}publicvoidsendGlobalMessage(TicTacToeMessageTypetype)throwsIOException{for(TicTacToeServerPlayerHandlerplayer:players){player.sendMessage(type);}}publicvoidsendGlobalMessage(TicTacToeMessageTypetype,Stringmessage)throwsIOException{for(TicTacToeServerPlayerHandlerplayer:players){player.sendMessage(type,message);}}publicvoidsendGlobalMessage(TicTacToeMessageTypetype,Stringmessage,Objectobj)throwsIOException{for(TicTacToeServerPlayerHandlerplayer:players){player.sendMessage(type,message,obj);}}/** * TODO: Send the choice to all players, so they update the board. */publicvoidupdateClientBoards(BoardChoicechoice)throwsIOException{}publicvoidchangeTurn(){currentPlayer=(currentPlayer+1)%players.size();}privatevoidclose()throwsIOException{for(TicTacToeServerPlayerHandlerplayer:players){player.close();}}/** * Server side of TicTacToe game. * <p> * TODO: The server should keep track of: * - Comunication with both connected players. * - The TicTacToe Board. It should be updated given * the players choices. * - It's a turn based game. * - Winner/Loser or draw. */@Overridepublicvoidrun(){try{// TODO}catch(IOException|ClassNotFoundExceptione){System.err.println(e.getMessage());}}}
El client es composarà d'un únic fil d'execució que ha de reaccionar als missatges enviats pel servidor
i actuar en conseqüència, seguint el protocol.
TicTacToeClient.java
packageud3.exercises.tictactoe.client;importud3.exercises.tictactoe.models.Board;importud3.exercises.tictactoe.models.BoardChoice;importud3.exercises.tictactoe.models.TicTacToeMessage;importud3.exercises.tictactoe.models.TicTacToeMessageType;importjava.io.IOException;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.net.Socket;importjava.util.Scanner;import staticud3.exercises.tictactoe.models.TicTacToeMessageType.*;publicclassTicTacToeClient{privatefinalSocketsocket;privatefinalScannerscanner;privatefinalObjectOutputStreamout;privatefinalObjectInputStreamin;privateBoardboard;privatebooleanfinished;publicTicTacToeClient(Stringhost,intport)throwsIOException{this.scanner=newScanner(System.in);this.socket=newSocket(host,port);this.out=newObjectOutputStream(socket.getOutputStream());this.in=newObjectInputStream(socket.getInputStream());this.board=newBoard();this.finished=false;}privateTicTacToeMessagereadMessage()throwsIOException,ClassNotFoundException{return(TicTacToeMessage)in.readObject();}privatevoidsendMessage(TicTacToeMessageTypetype,Stringmessage,Objectobj)throwsIOException{TicTacToeMessageticTacToeMessage=newTicTacToeMessage(type,message);ticTacToeMessage.setObject(obj);out.writeObject(ticTacToeMessage);}/** * TODO: Ask for the position where the user wants to play. * Send the user's choice to the server. */privatevoidplayMove()throwsIOException{}/** * Client-side TicTacToe game. * <p> * TODO: This method should recevie a TicTacToeMessage from the server and implement * the accions based on the message type. * */publicvoidgame()throwsIOException,ClassNotFoundException{}publicstaticvoidmain(String[]args){System.out.println("Connectant-se amb el servidor...");try{TicTacToeClientticTacToeClient=newTicTacToeClient("localhost",1234);ticTacToeClient.game();}catch(IOException|ClassNotFoundExceptione){System.err.println(e.getMessage());}}}