0
\$\begingroup\$

I have been working on a two-player card game and have been stuck on updating the respective players' JPanels. Each player has their own panel and after each player makes a move, I want to allow the JPanel of both players to display the updated move. I can't get this to work! I have been able to allow each player to take turns (concurrency via locks). If there is a thread out there where I can find some help on this, please help me out. I can't find any documentation on how to get my code to work. Here is the main thread:

private static void openConnection() throws IOException{  
    int port = 2222;
    try(ServerSocket serverSocket = new ServerSocket(port);){
        setDeckAndPlayers(); 
        //Two threads.
        PlayerThreadGame game = new PlayerThreadGame();
        PlayerThreadGame.PlayerThread p1 = game.new PlayerThread(serverSocket.accept(), panel1);
        PlayerThreadGame.PlayerThread p2 = game.new PlayerThread(serverSocket.accept(), panel2);
        PlayerThreadGame.PlayerThread activeThread;

        p1.setOpponentThread(p2);
        p2.setOpponentThread(p1);

        if(p1.panel.active){
            activeThread = p1;
        }
        else{
            activeThread = p2;
        }
        game.setCurrentPlayerThread(activeThread);

        p1.start();
        p2.start(); 

    } catch(IOException ie){
        System.err.println("Could not listen on port " + port);    
    }
}

and here is the PlayerThreadGame:

public class PlayerThreadGame{
private volatile PlayerThread currentPlayer;
private volatile Table sharedTable;
private volatile Deck sharedDeck;
private volatile int[] score;



public PlayerThreadGame(){
    score = new int[2];
    score[0] = 0;
    score[1] = 0;
}

public synchronized void setCurrentPlayerThread(PlayerThread curr){
    currentPlayer = curr;
}

public PlayerThread getCurrentPlayerThread(){
    return currentPlayer;
} 

public synchronized void updateGameTable(Table t){
    sharedTable = t;
}

public synchronized void updateGameDeck(Deck d){
    sharedDeck = d;
}

public synchronized void updateGameScore(int s, int playerNum){
    score[playerNum] = s;
}

public class PlayerThread extends Thread{
    @SuppressWarnings("unused")
    private Socket socket;
    //private BufferedReader input;
    private ObjectInputStream in;
    //PrintWriter output;
    private ObjectOutputStream out;
    public volatile PlayerThread opponent;
    public volatile GamePanel panel;
    private int playerNumber;
    //public volatile Player player;
    //public volatile Player opp;

    public PlayerThread(Socket socket, GamePanel panel){
        super("PlayerThread");
        this.socket = socket;
        this.panel = panel;

        System.out.println("Deck pos in thread server: " + sharedDeck.deck_position);

        this.playerNumber = panel.P.ID;
        try{
            //Initialize the player.
            //input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            in = new ObjectInputStream(socket.getInputStream());
            out = new ObjectOutputStream(socket.getOutputStream());

            out.writeInt(this.playerNumber);
            out.flush();

            out.writeObject(panel);
            out.flush();

        }
        catch(IOException e){
            System.out.println("Bad stream for player. " + e);
        }
    }

    public void setOpponentThread(PlayerThread opp){
        this.opponent = opp;
    }

    public PlayerThread getOpponentThread(){
        return opponent;
    }

    public synchronized void updateTable(Table t){
        panel.table = t;
    }

    public synchronized void updatePlayer(Player p){
        panel.P = p;
    }

    public synchronized void updatePanel(GamePanel p){
        panel.table.number_of_heads = p.table.number_of_heads;
        panel.D = p.D;
        System.out.println("Updating the thread panel:\n\tPanel ID: " + panel.panelID 
                + "\n\tPlaying: " + panel.P.playing + "\n\tActive: " + panel.active);
        opponent.panel.table.number_of_heads = panel.table.number_of_heads;
        opponent.panel.D = panel.D;
    }

    public synchronized void updateDeck(Deck d){ 
        panel.D = d;
    }

    public void run() {
        try{
            //Setup the initial play status.
            if(panel.active){
                out.writeObject("PLAY");
                out.flush();
            }
            else{
                out.writeObject("WAIT"); 
                out.flush();
            }

            //The player must be updated here also.
            out.writeObject(panel);
            out.flush();

            synchronized(this){
                while(true){
                    String clientIn = (String) in.readObject();

                    GamePanel p = (GamePanel)in.readObject();
                    if(clientIn.equals("MOVED") && currentPlayer == this){
                        updatePanel(p);
                        //Update players' panels, and the game table and deck.

                        updateGameTable(panel.table);
                        updateGameDeck(panel.D);

                        panel.P.handSize--;

                        if(panel.P.handSize == 0 && opponent.panel.P.handSize == 0){
                            panel.P.hand.removeAllElements();
                            opponent.panel.P.hand.removeAllElements();
                            System.out.println("Both hands empty.");
                            sharedDeck.deal(panel.P, opponent.panel.P);

                            sharedTable.handSize = panel.P.handSize;
                            sharedTable.before_deal = 0;
                        }
                        System.out.println("Switch from " + currentPlayer + " to " + opponent);

                        opponent.panel.P.playing = true;
                        opponent.panel.P.dropped = false;
                        opponent.panel.active = true;

                        //Update opponents thread
                        setCurrentPlayerThread(opponent);
                        Thread.sleep(20);   //let the JVM catch up in case the system resources are being drained.
                        out.writeObject("WAIT");
                        out.flush();
                    }
                    else if(clientIn.equals("WAITING") && currentPlayer == this){   
                        //in.readObject();
                        out.writeObject("PLAY");
                        out.flush();
                    }
                    else{
                        out.writeObject("WAIT");
                        out.flush();
                    }

                    out.writeObject(panel);
                    out.flush();
                }
            }
        } catch (IOException | ClassNotFoundException | InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("Bad I/O in Thread.");
        }

    }

    public String toString(){
        return playerNumber+""; 
    }
}

}

and the client:

public class Player{ 
private static final String ip = "localhost";
private static final int PORT = 2222;
private JFrame frame = new JFrame("Game!"); 
private final static int WIDTH = 1020;
private final static int HEIGHT = 600;
private GamePanel panel;  
private static int id;
private Socket socket;
private ObjectInputStream in;
private ObjectOutputStream out;

public Player() throws IOException, ClassNotFoundException {
    try{
        socket = new Socket(ip, PORT);
        out = new ObjectOutputStream(socket.getOutputStream()); 
        out.flush();
        in = new ObjectInputStream(socket.getInputStream());
        id = in.readInt();
        panel = (GamePanel)in.readObject();

        //currentThread = (PlayerThread) in.readObject();
    } catch (UnknownHostException e){
        System.err.println("Don't know about host " + ip);
        System.exit(1);
    } catch (IOException e){
        System.err.println("Couldn't get I/O for the connection to " + ip);
        System.exit(1);
    }
}


public synchronized void updatePanel(GamePanel p){
    panel = p;
    panel.active = true;
    panel.P.playing = true;
    panel.P.dropped = false; 
    frame.add(panel);
    frame.repaint();
}


public void play() throws Exception{
    try{  
        synchronized(this){
            while(true){ 
                String status = (String) in.readObject();
                GamePanel p = (GamePanel) in.readObject();  
                if(status.equals("PLAY")){
                    updatePanel(p); 
                    System.out.println("Set panel " + id + " to active.");

                    while(!panel.message.equals("NEXT")){
                        //wait for the player to make their move
                    }
                    System.out.println("Player " + panel.P.ID + " moved.");

                    panel.active = false;
                    panel.message = "";

                    out.writeObject("MOVED");  //set the opponent panel to "active" 
                    out.flush(); 
                }
                else if(status.equals("WAIT")){
                    //in.readObject();
                    //panel.active = false;
                    out.writeObject("WAITING"); 
                    out.flush();
                }
                out.writeObject(panel); 
                out.flush();
            }
        }
    } 
    catch(Exception e){
        System.out.println("Out of while loop scope.");
        System.exit(1);
    }
    finally{
        System.err.println("Closing the socket");
        socket.close();
    }
}

public static void main(String[] args) throws Exception{
    System.out.println("in main.");
    while(true){ 
        Player client = new Player(); 
        client.createBoard();
        client.play();
        if(!client.rematch())
            break;
    }
}

private boolean rematch() {
    int response = JOptionPane.showConfirmDialog(frame, "Would you like a rematch?",
                                                " Again?", JOptionPane.YES_NO_OPTION);
    //this.dispose();
    frame.dispose();
    return response == JOptionPane.YES_OPTION;
}

private void createBoard(){
    frame.setTitle("! Player " + id);
    frame.add(panel);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    BufferedImage imgUrl = null;
    ImageIcon imgIcon = null;

    try {
        imgUrl = ImageIO.read(_Applet.class.getResource("cards/card.png"));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    imgIcon = new ImageIcon(imgUrl);
    Image img = imgIcon.getImage();
    frame.setIconImage(img);
    frame.setSize(WIDTH, HEIGHT);
    frame.setVisible(true);
    frame.setResizable(false);

    System.out.println("Deck pos in client: " + panel.D.deck_position);

    if(panel.active)
        System.out.println("Player " + id + " is first!");

}   

public String toString(){
    return id+""; 
}

You can see I'm writing the panel and then attempting to updated the other players' panel, but I am definitely not doing it right...

\$\endgroup\$
4
  • \$\begingroup\$ Why do you need 2 threads for this? \$\endgroup\$ – Bálint May 29 '18 at 22:07
  • \$\begingroup\$ This is the only way I've seen something like this done. I understand that as long as it is done as event based, the two threads should be able to update their own... when it comes to updating them with the contents of the other thread's activity, I'm having some issues. I understand the EDT would require one thread to update both panels in a real time animated game, but I don't have to do it that way for an event driven game-- play halts once one player has their turn. Any tips would be greatly appreciated. I'm hoping someone has done something like this before. \$\endgroup\$ – Ivan T. May 30 '18 at 1:47
  • 1
    \$\begingroup\$ This is a lot of code to wade through; converting it to a minimal, complete, verifiable example makes it more likely that others will read all the way through & may help you find the problem on your own. For starters, remove the code that's already commented out. \$\endgroup\$ – Pikalek May 30 '18 at 4:21
  • \$\begingroup\$ I fixed my problem. The major issue I had was that I didn't instatiate the JPanel in the Client. Now I have this fixed. But, I have new issues with repaint and paintComponent. I will create new thread with my issue. \$\endgroup\$ – Ivan T. Jun 6 '18 at 19:57
0
\$\begingroup\$

I fixed my problem. The major issue I had was that I didn't instatiate the JPanel in the Client. Now I have this fixed. But, I have new issues with repaint and paintComponent. I will create new thread with my issue.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for coming back and posting this answer! Don't forget to mark it as the "accepted" one :) \$\endgroup\$ – Vaillancourt Jun 6 '18 at 20:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.