Kółko i krzyżyk... Skąd server/client wie gdzie przeciwnik stawia znak?

0

Witam,
Tak jak w temacie. Pytanie od profesora. Na szczęście projekt zaliczony, jedynie wysłać sprawozdanie w którym graficznie przedstawię jak działają sockety. Ogólnie jeśli chodzi o szczegóły pytania brzmiało następująco: "Co jest wysyłane do servera?"
"Skąd wie gdzie postawić znak na drugiej planszy? Np. gracz1 postawił znak X na środku pola, to skąd druga plansza wie zeby tam postawić, a nie w całkowicie randomowym miejscu?"

Byłbym bardzo wdzięczny za dość łopatologiczną odpowiedź żebym mógł zrozumieć :). Tutaj kod:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TicTacToeServer {

    public static void main(String[] args) throws Exception {
        ServerSocket listener = new ServerSocket(8901);
        System.out.println("Serwer TicTacToe działa");
        try {
            while (true) {
                Game game = new Game();
                Game.Player playerX = game.new Player(listener.accept(), 'X');
                Game.Player playerO = game.new Player(listener.accept(), 'O');
                playerX.setOpponent(playerO);
                playerO.setOpponent(playerX);
                game.currentPlayer = playerX;
                playerX.start();
                playerO.start();
            }
        } finally {
            listener.close();
        }
    }
}

class Game {

   
    private Player[] board = {
        null, null, null,
        null, null, null,
        null, null, null};

    Player currentPlayer;
    
    public boolean hasWinner() {
        return
            (board[0] != null && board[0] == board[1] && board[0] == board[2])
          ||(board[3] != null && board[3] == board[4] && board[3] == board[5])
          ||(board[6] != null && board[6] == board[7] && board[6] == board[8])
          ||(board[0] != null && board[0] == board[3] && board[0] == board[6])
          ||(board[1] != null && board[1] == board[4] && board[1] == board[7])
          ||(board[2] != null && board[2] == board[5] && board[2] == board[8])
          ||(board[0] != null && board[0] == board[4] && board[0] == board[8])
          ||(board[2] != null && board[2] == board[4] && board[2] == board[6]);
    }

    public boolean boardFilledUp() {
        for (int i = 0; i < board.length; i++) {
            if (board[i] == null) {
                return false;
            }
        }
        return true;
    }

    public synchronized boolean legalMove(int location, Player player) {
        if (player == currentPlayer && board[location] == null) {
            board[location] = currentPlayer;
            currentPlayer = currentPlayer.opponent;
            currentPlayer.otherPlayerMoved(location);
            return true;
        }
        return false;
    }

    class Player extends Thread {
        char mark;
        Player opponent;
        Socket socket;
        BufferedReader input;
        PrintWriter output;

        /// Tworzy wątek obsługi dla danego gniazda i oznaczenia
       // inicjalizuje pola strumienia, wyświetla pierwsze dwa
        //powitalne wiadomości.
        public Player(Socket socket, char mark) {
            this.socket = socket;
            this.mark = mark;
            try {
                input = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
                output = new PrintWriter(socket.getOutputStream(), true);
                output.println("WELCOME " + mark);
                output.println("MESSAGE Czekaj na przeciwnika");
            } catch (IOException e) {
                System.out.println("Player died: " + e);
            }
        }

       /// akceptuje przeciwnika
        public void setOpponent(Player opponent) {
            this.opponent = opponent;
        }
        
        public void otherPlayerMoved(int location) {
            output.println("OPPONENT_MOVED " + location);
            output.println(
                hasWinner() ? "DEFEAT" : boardFilledUp() ? "TIE" : "");
        }

        
        public void run() {
            try {
           
                output.println("MESSAGE Gracze połączeni");

               
                if (mark == 'X') {
                    output.println("MESSAGE Twój ruch");
                }

                // otrzymuje polecenia od klienta i przetwarza je
                while (true) {
                    String command = input.readLine();
                    if (command.startsWith("MOVE")) {
                        int location = Integer.parseInt(command.substring(5));
                        if (legalMove(location, this)) {
                            output.println("VALID_MOVE");
                            output.println(hasWinner() ? "VICTORY"
                                         : boardFilledUp() ? "TIE"
                                         : "");
                        } else {
                            output.println("MESSAGE ?");
                        }
                    } else if (command.startsWith("QUIT")) {
                        return;
                    }
                }
            } catch (IOException e) {
                System.out.println("Player died: " + e);
            } finally {
                try {socket.close();} catch (IOException e) {}
            }
        }
    }

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class TicTacToeClient {

    private JFrame frame = new JFrame("Tic Tac  Toe");
    private JLabel messageLabel = new JLabel("");
    private ImageIcon icon;
    private ImageIcon opponentIcon;

    private Square[] board = new Square[9];
    private Square currentSquare;

    private static int PORT = 8901;
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;

    public TicTacToeClient(String serverAddress) throws Exception {

        socket = new Socket(serverAddress, PORT);
        in = new BufferedReader(new InputStreamReader(
            socket.getInputStream()));
        out = new PrintWriter(socket.getOutputStream(), true);

        // GUI
        messageLabel.setBackground(Color.lightGray);
        frame.getContentPane().add(messageLabel, "South");

        JPanel boardPanel = new JPanel();
        boardPanel.setBackground(Color.black);
        boardPanel.setLayout(new GridLayout(3, 3, 3, 3));
        for (int i = 0; i < board.length; i++) {
            final int j = i;
            board[i] = new Square();
            board[i].addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent e) {
                    currentSquare = board[j];
                    out.println("MOVE " + j);}});
            boardPanel.add(board[i]);
        }
        frame.getContentPane().add(boardPanel, "Center");
    }

    public void play() throws Exception {
    	String response;
        try {
            response = in.readLine();
            if (response.startsWith("WELCOME")) {
                char mark = response.charAt(8);
                if(mark == 'X')
                {
                	icon = new ImageIcon("x.gif");
                	opponentIcon = new ImageIcon("o.gif");
                }
                else if(mark == 'O')
                {
                	icon = new ImageIcon("o.gif");
                	opponentIcon = new ImageIcon("x.gif");
                }
                frame.setTitle("Tic Tac Toe - Player " + mark);
            }
            while (true) {
                response = in.readLine();
                if (response.startsWith("VALID_MOVE")) {
                    messageLabel.setText("Prawidłowy ruch, czekaj");
                    currentSquare.setIcon(icon);
                    currentSquare.repaint();
                } else if (response.startsWith("OPPONENT_MOVED")) {
                    int loc = Integer.parseInt(response.substring(15));
                    board[loc].setIcon(opponentIcon);
                    board[loc].repaint();
                    messageLabel.setText("Przeciwnik skończył, twój ruch");
                } else if (response.startsWith("VICTORY")) {
                    messageLabel.setText("WYGRAŁEŚ");
                    break;
                } else if (response.startsWith("DEFEAT")) {
                    messageLabel.setText("Przegrałeś");
                    break;
                } else if (response.startsWith("TIE")) {
                    messageLabel.setText("Remisik");
                    break;
                } else if (response.startsWith("MESSAGE")) {
                    messageLabel.setText(response.substring(8));
                }
            }
            out.println("QUIT");
        }
        finally {
            socket.close();
        }
    }

    private boolean wantsToPlayAgain() {
        int response = JOptionPane.showConfirmDialog(frame,
            "Jeszcze raz?",
            "Tic Tac Toe",
            JOptionPane.YES_NO_OPTION);
        frame.dispose();
        return response == JOptionPane.YES_OPTION;
    }

    static class Square extends JPanel {
        JLabel label = new JLabel((Icon)null);

        public Square() {
            setBackground(Color.white);
            add(label);
        }

        public void setIcon(Icon icon) {
            label.setIcon(icon);
        }
    }

    public static void main(String[] args) throws Exception {
        while (true) {
            String serverAddress = (args.length == 0) ? "localhost" : args[1];
            TicTacToeClient client = new TicTacToeClient(serverAddress);
            client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            client.frame.setSize(300, 300);
            client.frame.setVisible(true);
            client.frame.setResizable(false);
            client.play();
            if (!client.wantsToPlayAgain()) {
                break;
            }
        }
    }
}
0

Przecież kod wprost wysyła, które pole zostało naciśnięte:

out.println("MOVE " + j);
0

Ciekawe w takim razie. Powiedziałem mu że wysyła pole to spytał się jak wie, że jest to pole a nie inne... Sam juz nie wiem czy facet chce mnie uwalić czy jak. Mam mieszane myśli.

0

Z tego co zrozumiałem skąd serwer wie gdzie przesłać znak np "X" do drugiego gracza. W sensie w którym polu jest :DDDD.

0

W takim razie czy mogę napisac w sprawozdaniu, że serwer "wie" o lokalizacji wypełnienia danego pola poprzez to co napisał Patryk27?

out.println("MOVE " + j);
0

No tak - serwer wie, ponieważ klient to wysyła :-)
Nie ma fizycznie innej możliwości - przecież się ani nie domyśli, ani nie zgadnie ;-)

0
                    int loc = Integer.parseInt(response.substring(15));
                    board[loc].setIcon(opponentIcon);
                    board[loc].repaint();

tutaj jest parowana odpowiedz ktora przyszla z socketu. Klient otrzymuje string i bierze z niego Int, nastepnie aktualizuje swoj board.

Jak nie rozumiesz tego kodu to i tak w koncu zada takie pytanie na ktore nie bedziesz znal odpowiedzi. Programowanie to nie uczenie sie na pamiec. to tak nie dziala

1 użytkowników online, w tym zalogowanych: 0, gości: 1