diff --git a/.gitignore b/.gitignore index d7eac8b..3124173 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ dist/ release/ */TAGS *.zip +.idea/ +target/ diff --git a/client/CanvasBorder.java b/client/CanvasBorder.java deleted file mode 100644 index beff21a..0000000 --- a/client/CanvasBorder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * CanvasBorder.java - * - * Created on 18. avril 2000, 16:49 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version - */ - -import java.awt.*; - -public class CanvasBorder extends JassCanvas { - Image cardBack; - Image card; - int nbrCards; - // mode:: 0 : tirage des équipes, 1 : jouer normalement - - - /** Creates new CanvasBorder */ - public CanvasBorder(String imgPath) { - mode = 1; - nbrCards = 0; - name = ""; - Toolkit tk = Toolkit.getDefaultToolkit(); - - cardBack = tk.getImage(imgPath+"dos.gif"); - } - - public void setNbrCards(int nbrCards) { - this.nbrCards = nbrCards; - } - - public void setCard(Image card) { - this.card = card; - } - - public void removeCard() { - nbrCards--; - } - - public void paint (Graphics g) { - Dimension d = getSize(); - if (mode == 1) { - int w = (d.width - 71) / 2; - int h = (d.height - nbrCards * 30 - 66) / 2 + 20; - for (int i = 0; i 19)&&(e.getY() < 116)) && ((e.getX() > 19)&&(e.getX() - < 371))) { - System.out.println("Click"); // supprimer - int x = e.getX(); - int i = 9; - boolean found = false; - while (!found && (i > 0)) { - i--; - if ((x > (19 + i * 35)) && (x < (91 + i * 35))) - if (app.cards[i] < 36) - switch (app.playCard(playerCanvas.getMode(), app.cards[i])) { - case 0 : // jouer la carte - int playedCard = app.cards[i]; - jButtonAnounce.setEnabled(false); - setStatusBar(""); // remove "a vous de..." - centerCanvas.cardsChoosen[0] = playedCard; - playerCanvas.setMode(0); - playerCanvas.hand[i] = 37; - app.cards[i] = 37; - found = true; - repaint(17); - - // sends the card to the server - if (app.atout == Card.getColor(playedCard)) - app.sendCard(playedCard, Card.valueAtout[Card.getHeight(playedCard)]); // modifier !!!! - else - app.sendCard(playedCard, Card.value[Card.getHeight(playedCard)]); - break; - case -1 : // suivre - System.out.println("Il faut suivre !!"); - found = true; - break; - case -2 : // sous-couper - System.out.println("Vous ne pouvez pas sous-couper!!"); - found = true; - } - } - } - } - - public void setName(int player, String name) { - int diff = player - app.myPlayer; - if (diff < 0) - diff += 4; - switch (diff) { - case 0 : playerCanvas.setName(name); - playerCanvas.repaint(); - break; - case 1 : rightCanvas.setName(name); - rightCanvas.repaint(); - break; - case 2 : topCanvas.setName(name); - topCanvas.repaint(); - break; - case 3 : leftCanvas.setName(name); - leftCanvas.repaint(); - } - } - - public void teamChoiceShowCard(int player, int position, int cardNumber) { - int diff = player - app.myPlayer; - if (diff < 0) - diff += 4; - switch (diff) { - case 0 : for (int i=1; i<9; i++) - playerCanvas.hand[i] = 37; - playerCanvas.hand[0] = cardNumber; - playerCanvas.repaint(); - break; - case 1 : centerCanvas.cardsChoosen[position] = app.myPlayer; - centerCanvas.repaint(); - rightCanvas.setCard(playerCanvas.cards[cardNumber]); - rightCanvas.setMode(0); // tirage des équipes - rightCanvas.repaint(); - break; - case 2 : centerCanvas.cardsChoosen[position] = app.myPlayer; - centerCanvas.repaint(); - topCanvas.setCard(playerCanvas.cards[cardNumber]); - topCanvas.setMode(0); // tirage des équipes - topCanvas.repaint(); - break; - case 3 : centerCanvas.cardsChoosen[position] = app.myPlayer; - centerCanvas.repaint(); - leftCanvas.setCard(playerCanvas.cards[cardNumber]); - leftCanvas.setMode(0); // tirage des équipes - leftCanvas.repaint(); - } - } - - public void prepareTeamChoice() { - for (int i=0; i<36; i++) - centerCanvas.cardsChoosen[i] = 10; // carte présente - for (int i=0; i<9; i++) - playerCanvas.hand[i] = 37; // effacer les cartes - leftCanvas.setNbrCards(0); - leftCanvas.setMode(1); - rightCanvas.setNbrCards(0); - rightCanvas.setMode(1); - topCanvas.setNbrCards(0); - topCanvas.setMode(1); - centerCanvas.mode = 1; - centerCanvas.repaint(); - removeLastPlie(); - lastPlieCanvas.atout = 4; - setScore(0,0); - repaint(31); - } - - void centerCanvas_mouseClicked(MouseEvent e) { - System.out.println("Click 1"); - if (centerCanvas.mode == 2) { // à ton tour de tirer une carte - System.out.println("Click Center"); - if (((e.getY() < 137) && (e.getY() > 39)) && ((e.getX() > 9) && (e.getX() < 361))) { - int nbr = (e.getX() - 10) / 8; - if (nbr > 35) { - if (centerCanvas.cardsChoosen[35] == 10) - nbr = 35; - else if ((centerCanvas.cardsChoosen[34] == 10) && (e.getX() < 353)) - nbr = 34; - else if ((centerCanvas.cardsChoosen[33] == 10) && (e.getX() < 345)) - nbr = 33; - else if ((centerCanvas.cardsChoosen[32] == 10) && (e.getX() < 337)) - nbr = 32; - } - - if (centerCanvas.cardsChoosen[nbr] == 10) { - centerCanvas.cardsChoosen[nbr] = app.myPlayer; - centerCanvas.repaint(); - } - else if (centerCanvas.cardsChoosen[nbr-1] == 10) { - nbr--; - centerCanvas.cardsChoosen[nbr] = app.myPlayer; - centerCanvas.repaint(); - } - else if (centerCanvas.cardsChoosen[nbr-2] == 10) { - nbr-=2; - centerCanvas.cardsChoosen[nbr] = app.myPlayer; - centerCanvas.repaint(); - } - else if (centerCanvas.cardsChoosen[nbr-3] == 10) { - nbr-=3; - centerCanvas.cardsChoosen[nbr] = app.myPlayer; - centerCanvas.repaint(); - } - centerCanvas.mode = 1; // on ne peut plus choisir une carte - setStatusBar(""); // remove "veuillez tirer..." - app.sendCard(nbr, 0); - } - } - } - - // prépare l'écran pour une nouvelle partie - void prepareMatch() { - for (int i=0; i<4; i++) - centerCanvas.cardsChoosen[i] = 36; - centerCanvas.mode = 3; // mode de jeu - lastPlieCanvas.atout = 4; - lastPlieCanvas.repaint(); - repaint(31); // repaint les 5 canvas - setStatusBar(""); - removeLastPlie(); - } - - // affiche une carte jouée - void showPlayedCard(int player, int number) { - int diff = player - app.myPlayer; - if (diff < 0) - diff += 4; - switch (diff) { - case 1 : centerCanvas.cardsChoosen[1] = number; - rightCanvas.removeCard(); - rightCanvas.repaint(); - break; - case 2 : centerCanvas.cardsChoosen[2] = number; - topCanvas.removeCard(); - topCanvas.repaint(); - break; - case 3 : centerCanvas.cardsChoosen[3] = number; - leftCanvas.removeCard(); - leftCanvas.repaint(); - } - centerCanvas.repaint(); - statusBar.setText(app.players[player].getFirstName() + " a joué..."); - } - - // ramasse la plie - void pickUpPlie(String player) { - statusBar.setText(player + " a pris la plie"); - for (int i=0; i<4; i++) { - System.out.println(i); - lastPlieCanvas.cards[i] = playerCanvas.cards[centerCanvas.cardsChoosen[i]]; - centerCanvas.cardsChoosen[i] = 36; - } - lastPlieCanvas.display = true; - lastPlieCanvas.repaint(); - centerCanvas.repaint(); - } - - void removeLastPlie() { - lastPlieCanvas.display = false; - lastPlieCanvas.repaint(); - } - - void setScore(int ourScore, int theirScore) { - lastPlieCanvas.ourScore = ourScore; - lastPlieCanvas.theirScore = theirScore; - lastPlieCanvas.repaint(); - } - - - void setStatusBar(String text) { - statusBar.setText(text); - } - - void setAnounceEnabled(boolean b) { - jButtonAnounce.setEnabled(b); - } - - void setAtout(int player) { - int diff = player - app.myPlayer; - if (diff < 0) - diff += 4; - - playerCanvas.setAtout(false); - rightCanvas.setAtout(false); - topCanvas.setAtout(false); - leftCanvas.setAtout(false); - - switch (diff) { - case 0 : - playerCanvas.setAtout(true); - break; - case 1 : - rightCanvas.setAtout(true); - break; - case 2 : - topCanvas.setAtout(true); - break; - case 3 : - leftCanvas.setAtout(true); - } - repaint(31); - } -} diff --git a/client/ClientListener.java b/client/ClientListener.java deleted file mode 100644 index 9827c43..0000000 --- a/client/ClientListener.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ClientListener.java - * - * Created on 18. avril 2000, 18:15 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version 1.2 - */ - -import java.io.*; -import java.net.*; - -public class ClientListener extends Thread{ - FlatJassClientSystem app; - Socket threadSocket; - InputStreamReader isr; - BufferedReader is; - public boolean stop = false; - - public ClientListener(FlatJassClientSystem app, Socket cs) { - this.app = app; - threadSocket=cs; - stop = false; - try { - isr = new InputStreamReader(threadSocket.getInputStream()); - is = new BufferedReader(isr); - } - catch (IOException e) { - System.out.println("LISTENER:Impossible stream"); - } - } - -/* public ClientListener(FlatJassClientSystem app) { - this.app = app; - }*/ - - public void setSocket(Socket cs) { - threadSocket = cs; - try { - isr = new InputStreamReader(threadSocket.getInputStream()); - is = new BufferedReader(isr); - } - catch (IOException e) { - System.out.println("LISTENER:Impossible stream"); - } - } - - public void run() { - /* int c; - StringBuffer s = new StringBuffer(50); - String answer; - int len; - System.out.println("Client Listener : prêt"); - try { - while (true) { - s.setLength(0); - try { - while ((c = System.in.read()) != '\n') - s.append((char)c); - } - catch (IOException e) { - } - answer = s.toString(); - len = answer.length(); - app.execute(answer.substring(0, len-1)); - // app.execute(answer); - } - } - catch (Exception e) { - }*/ - System.out.println("Starting Listener..."); - - while (!stop) { - String rcvTemp = null; - - //implementer timeout + exc - - try { - rcvTemp=is.readLine(); - System.out.println("LISTENER:Reception:"+rcvTemp); - app.execute(rcvTemp); - } - catch (IOException e) { - System.out.println("LISTENER:Erreur reception"); - //System.exit(1); - } - } - - //this.stop(); - } -} diff --git a/client/ClientNetwork.java b/client/ClientNetwork.java deleted file mode 100644 index fbd1e7e..0000000 --- a/client/ClientNetwork.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ClientNetwork.java - * - * Created on 18. avril 2000, 18:17 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version 1.2 - */ - -import java.net.*; -import java.io.*; - -public class ClientNetwork { - - public static final int PORT_NUM=32107; - Socket myClientSocket=null; - - PrintWriter os; - - public ClientNetwork() { - - } - - public Socket connect(String ipAddress) { - - //streams - try { - myClientSocket = new Socket(ipAddress, PORT_NUM); - - os = new PrintWriter(myClientSocket.getOutputStream(),false); - System.out.println("Connection successful"); - } - catch (IOException e) { - System.out.println("Unable to create socket"); - System.out.println(e); - //System.exit(1); - return null; - } - - return this.myClientSocket; - } - - public void sendTo(String msg) { - os.println(msg); - os.flush(); - System.out.println("Envoi au serveur : " + msg); - } - - public void disconnect() { - try { - myClientSocket.close(); - } - catch (IOException e) { - System.out.println("Error while closing socket"); - //System.exit(1); - } - } -} diff --git a/client/DialogAtout.java b/client/DialogAtout.java deleted file mode 100644 index af33aa6..0000000 --- a/client/DialogAtout.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * DialogAtout.java - * - * Created on 19. avril 2000, 11:52 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version - */ -public class DialogAtout extends javax.swing.JDialog { - int number = 0; - - /** Creates new form DialogAtout */ - public DialogAtout(java.awt.Frame parent,boolean modal, boolean pass) { - super (parent, modal); - initComponents (); - pack (); - if (pass) - jButtonPass.setEnabled(false); - jComboBoxAtout.addItem("Pique"); - jComboBoxAtout.addItem("Coeur"); - jComboBoxAtout.addItem("Carreau"); - jComboBoxAtout.addItem("Trèfle"); - } - - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the FormEditor. - */ - private void initComponents () {//GEN-BEGIN:initComponents - jLabel1 = new javax.swing.JLabel (); - jComboBoxAtout = new javax.swing.JComboBox (); - jButtonOk = new javax.swing.JButton (); - jButtonPass = new javax.swing.JButton (); - getContentPane ().setLayout (new AbsoluteLayout ()); - setSize(300, 180); - setResizable (false); - setTitle ("Choix de l'atout"); - addWindowListener (new java.awt.event.WindowAdapter () { - public void windowClosing (java.awt.event.WindowEvent evt) { - closeDialog (evt); - } - } - ); - - jLabel1.setText ("Veuillez choisir l'atout"); - - - getContentPane ().add (jLabel1, new AbsoluteConstraints (20, 20, -1, -1)); - - - - getContentPane ().add (jComboBoxAtout, new AbsoluteConstraints (120, 60, -1, -1)); - - jButtonOk.setText ("Ok"); - jButtonOk.addActionListener (new java.awt.event.ActionListener () { - public void actionPerformed (java.awt.event.ActionEvent evt) { - jButtonOkActionPerformed (evt); - } - } - ); - - - getContentPane ().add (jButtonOk, new AbsoluteConstraints (40, 110, -1, -1)); - - jButtonPass.setText ("Passer"); - jButtonPass.addActionListener (new java.awt.event.ActionListener () { - public void actionPerformed (java.awt.event.ActionEvent evt) { - jButtonPassActionPerformed (evt); - } - } - ); - - - getContentPane ().add (jButtonPass, new AbsoluteConstraints (180, 110, -1, -1)); - - }//GEN-END:initComponents - - private void jButtonPassActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPassActionPerformed -// Add your handling code here: - number = 4; - this.dispose(); - }//GEN-LAST:event_jButtonPassActionPerformed - - private void jButtonOkActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOkActionPerformed -// Add your handling code here: - number = jComboBoxAtout.getSelectedIndex(); - this.dispose(); - }//GEN-LAST:event_jButtonOkActionPerformed - - /** Closes the dialog */ - private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog - setVisible (false); - dispose (); - }//GEN-LAST:event_closeDialog - - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel jLabel1; - private javax.swing.JComboBox jComboBoxAtout; - private javax.swing.JButton jButtonOk; - private javax.swing.JButton jButtonPass; - // End of variables declaration//GEN-END:variables - -} diff --git a/client/DialogNewPart.java b/client/DialogNewPart.java deleted file mode 100644 index 347a3f1..0000000 --- a/client/DialogNewPart.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * DialogNewPart.java - * - * Created on 11. avril 2002, 22:17 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version - */ -public class DialogNewPart extends javax.swing.JDialog { - boolean newPart = false; - - /** Creates new form DialogNewPart */ - public DialogNewPart(java.awt.Frame parent,boolean modal) { - super (parent, modal); - initComponents (); - pack (); - } - - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the FormEditor. - */ - private void initComponents () {//GEN-BEGIN:initComponents - jLabel1 = new javax.swing.JLabel (); - jButtonYes = new javax.swing.JButton (); - jButtonNo = new javax.swing.JButton (); - - getContentPane ().setLayout (new AbsoluteLayout ()); - setSize(320, 180); - setResizable (false); - setTitle ("Nouvelle partie"); - addWindowListener (new java.awt.event.WindowAdapter () { - public void windowClosing (java.awt.event.WindowEvent evt) { - closeDialog (evt); - } - } - ); - - jLabel1.setText ("Voulez vous faire une nouvelle partie?"); - - - getContentPane ().add (jLabel1, new AbsoluteConstraints (30, 20, -1, -1)); - - jButtonYes.setText ("Oui"); - jButtonYes.addActionListener (new java.awt.event.ActionListener () { - public void actionPerformed (java.awt.event.ActionEvent evt) { - jButtonYesActionPerformed (evt); - } - } - ); - - - getContentPane ().add (jButtonYes, new AbsoluteConstraints (40, 100, -1, -1)); - - jButtonNo.setText ("Non"); - jButtonNo.addActionListener (new java.awt.event.ActionListener () { - public void actionPerformed (java.awt.event.ActionEvent evt) { - jButtonNoActionPerformed (evt); - } - } - ); - - - getContentPane ().add (jButtonNo, new AbsoluteConstraints (180, 100, -1, -1)); - - - - - - - }//GEN-END:initComponents - - private void jButtonNoActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonManualActionPerformed -// Add your handling code here: - newPart = false; - this.dispose(); - }//GEN-LAST:event_jButtonManualActionPerformed - - private void jButtonYesActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonHasardActionPerformed -// Add your handling code here: - newPart = true; - this.dispose(); - }//GEN-LAST:event_jButtonHasardActionPerformed - - /** Closes the dialog */ - private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog - setVisible (false); - dispose (); - }//GEN-LAST:event_closeDialog - - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel jLabel1; - private javax.swing.JButton jButtonYes; - private javax.swing.JButton jButtonNo; - // End of variables declaration//GEN-END:variables - -} diff --git a/client/DialogPartnerChoice.java b/client/DialogPartnerChoice.java deleted file mode 100644 index 4f487ff..0000000 --- a/client/DialogPartnerChoice.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * DialogPartnerChoice.java - * - * Created on 19. avril 2000, 11:44 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version - */ -public class DialogPartnerChoice extends javax.swing.JDialog { - int number = 0; - - /** Creates new form DialogPartnerChoice */ - public DialogPartnerChoice(java.awt.Frame parent,boolean modal) { - super (parent, modal); - initComponents (); - pack (); - } - - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the FormEditor. - */ - private void initComponents () {//GEN-BEGIN:initComponents - jComboBoxPartner = new javax.swing.JComboBox (); - jButtonOk = new javax.swing.JButton (); - jLabel1 = new javax.swing.JLabel (); - getContentPane ().setLayout (new AbsoluteLayout ()); - setSize(300, 200); - setResizable (false); - setTitle ("Choix du partenaire"); - addWindowListener (new java.awt.event.WindowAdapter () { - public void windowClosing (java.awt.event.WindowEvent evt) { - closeDialog (evt); - } - } - ); - - - - getContentPane ().add (jComboBoxPartner, new AbsoluteConstraints (100, 50, -1, -1)); - - jButtonOk.setText ("Ok"); - jButtonOk.addActionListener (new java.awt.event.ActionListener () { - public void actionPerformed (java.awt.event.ActionEvent evt) { - jButtonOkActionPerformed (evt); - } - } - ); - - - getContentPane ().add (jButtonOk, new AbsoluteConstraints (120, 120, -1, -1)); - - jLabel1.setText ("Veuillez choisir votre partenaire"); - - - getContentPane ().add (jLabel1, new AbsoluteConstraints (20, 20, -1, -1)); - - }//GEN-END:initComponents - - private void jButtonOkActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOkActionPerformed -// Add your handling code here: - number = jComboBoxPartner.getSelectedIndex(); - this.dispose(); - }//GEN-LAST:event_jButtonOkActionPerformed - - /** Closes the dialog */ - private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog - setVisible (false); - dispose (); - }//GEN-LAST:event_closeDialog - - - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JComboBox jComboBoxPartner; - private javax.swing.JButton jButtonOk; - private javax.swing.JLabel jLabel1; - // End of variables declaration//GEN-END:variables - - public void addPlayer(String name) { - jComboBoxPartner.addItem(name); - } -} diff --git a/client/FlatJassClientSystem.java b/client/FlatJassClientSystem.java deleted file mode 100644 index 35edaa2..0000000 --- a/client/FlatJassClientSystem.java +++ /dev/null @@ -1,695 +0,0 @@ -/* - * FlatJassClientSystem.java - * - * Created on 18. avril 2000, 16:09 - */ - - - -/** - * - * @author Berclaz Jérôme - * @version 1.2 - */ -import java.net.*; - -public class FlatJassClientSystem extends Object { - // Variables - ClientFrame frame = new ClientFrame(this); - - // Variables du moteur de jeu - ClientListener listener; // classe qui écoute - ClientNetwork network = new ClientNetwork(); // classe qui implémente socket - public int myPlayer; // id du joueur - Player[] players = new Player[4]; // les 4 joueurs - int[] cards = new int[9]; // main du joueur - int atout; // atout - Plie currentPlie = new Plie(); // plie en cours - Anounce[] myAnounces = new Anounce[3]; // annonces - int nbrAnounces; // nombre d'annonces - int stock; // 0:rien, 1:stöck, 2: joué un, 3:joué les deux - int plieNbr; // numéro de la plie - - /** Creates new FlatJassClientSystem */ - public FlatJassClientSystem() { - for (int i=0; i<4; i++) // construire les objets player - players[i] = new Player(); - for (int i=0; i<3; i++) // construire les objets Anounce - myAnounces[i] = new Anounce(); - frame.show(); - } - - /** - * @param args the command line arguments - */ - public static void main (String args[]) { - new FlatJassClientSystem(); - } - - public int connect(String firstName, String lastName, String IP) { - // renvoie -1 en cas d'échec et 0 si réussi - System.out.println("Connected to " + IP); - Socket cs=network.connect(IP); - if (cs != null) { // connexion réussie - players[0].setFirstName(firstName); - players[0].setLastName(lastName); - if (listener == null) { - listener = new ClientListener(this,cs); - System.out.println("Création d'un nouveau listener"); // débuggage - } - else { - // listener.setSocket(cs); - // listener.stop = false; - listener = new ClientListener(this,cs); - } - listener.start(); - } - else { - return -1; - } - - //players[0].setFirstName(firstName); - //players[0].setLastName(lastName); - // listener = new ClientListener(this); - // listener.start(); - return 0; - } - - // Procédure de décodage des instructions - private String[] decode(String instr) { - int cmpt = 0; - int cursor = 0; - String[] table = new String[10]; - for (int i=1; i demande d'envoi d'informations sur le joueur - // Syntaxe : 1 + id du joueur - temp = Integer.valueOf(tableInstr[1]); - myPlayer = temp.intValue(); - if (myPlayer != 0) { - players[myPlayer].setFirstName(players[0].getFirstName()); - players[myPlayer].setLastName(players[0].getLastName()); - } - players[myPlayer].setID(myPlayer); - frame.setName(myPlayer, players[myPlayer].getFirstName()); - frame.setStatusBar("Connexion réussie"); - answer = tableInstr[1] + " " + players[myPlayer].getFirstName() + " " + players[myPlayer].getLastName(); - break; - case 2 : // envoie les infos des autres joueurs - // Syntaxe : 2 + id du joueur + prenom du joueur + nom du joueur - temp = Integer.valueOf(tableInstr[1]); - int i = temp.intValue(); - players[i].setFirstName(tableInstr[2]); - players[i].setLastName(tableInstr[3]); - players[i].setID(i); - frame.setStatusBar(tableInstr[2] + " " + tableInstr[3] + " s'est connecté"); - frame.setName(i, tableInstr[2]); - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 3 : // demande de choisir le mode de choix des équipes - // Syntaxe : 3 - DialogTeamChoice dtc = new DialogTeamChoice(frame, true); - dtc.show(); - if (dtc.hasard) { - answer = String.valueOf(myPlayer) + " 1"; // choisir au hasard - } - else { - answer = String.valueOf(myPlayer) + " 0"; // choisir manuellement - } - break; - case 4 : // demande de préparer le mode de tirage des équipes - // Syntaxe : 4 - frame.prepareTeamChoice(); - frame.setStatusBar("Tirage des équipes..."); - answer = String.valueOf(myPlayer) + " 1"; - break; - case 5 : // demande de choisir une carte - // Syntaxe : 5 - frame.centerCanvas.mode = 2; - frame.setStatusBar("Veuillez choisir une carte"); - break; - case 6 : // donne la carte choisie par un joueur - // Syntaxe : 6 + id joueur + position de la carte + numéro de la carte - temp = Integer.valueOf(tableInstr[1]); - int id = temp.intValue(); - temp = Integer.valueOf(tableInstr[2]); - int pos = temp.intValue(); - temp = Integer.valueOf(tableInstr[3]); - int nbr = temp.intValue(); - frame.teamChoiceShowCard(id, pos, nbr); - frame.setStatusBar(players[id].getFirstName() + " a tiré une carte"); - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 7 : // le tirage n'est pas bon, on recommence - // Syntaxe : 7 - frame.prepareTeamChoice(); - frame.setStatusBar("Le tirage n'est pas bon..."); - answer = String.valueOf(myPlayer) + " 1"; - break; - case 8 : // transmet le nouvel ordre des joueurs - // Syntaxe : 9 + id1 + id2 + id3 + id4 - temp = Integer.valueOf(tableInstr[1]); - int id1 = temp.intValue(); - temp = Integer.valueOf(tableInstr[2]); - int id2 = temp.intValue(); - temp = Integer.valueOf(tableInstr[3]); - int id3 = temp.intValue(); - temp = Integer.valueOf(tableInstr[4]); - int id4 = temp.intValue(); - organisePlayers(id1, id2, id3, id4); - frame.setScore(0, 0); // initialize scores - frame.setStatusBar("Equipes réorganisées"); - for (i=0; i<4; i++) - frame.setName(i, players[i].getFirstName()); - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 9 : // demande de choisir son partenaire - //Syntaxe : 9 - DialogPartnerChoice dpc = new DialogPartnerChoice(frame, true); - for (i=0; i<4; i++) - if (i != myPlayer) - dpc.addPlayer(players[i].getFirstName()); - dpc.show(); - answer = String.valueOf(myPlayer) + " " + String.valueOf(dpc.number + 1); - break; - case 10 : // donne les cartes - // Syntaxe : 10 + carte1 + ... + carte9 - for (i=1; i<10; i++) { - temp = Integer.valueOf(tableInstr[i]); - cards[i-1] = temp.intValue(); - } - quickSort(cards, 0, 8); - for (i=0; i<4; i++) - if (i == myPlayer) - frame.setPlayerCards(cards); - else - frame.setOpponentCards(i, 9); - frame.prepareMatch(); // prépare l'écran pour une nouvelle partie - nbrAnounces = 0; - plieNbr = 0; - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 11 : // demande de faire atout en premier - // Syntaxe : 11 - DialogAtout da = new DialogAtout(frame, true, false); - da.show(); - if (da.number == 4) - answer = String.valueOf(myPlayer) + " 4"; - else - answer = String.valueOf(myPlayer) + " " + String.valueOf(da.number); - break; - case 12 : // demande de faire atout en second - // Syntaxe : 12 - da = new DialogAtout(frame, true, true); - da.show(); - answer = String.valueOf(myPlayer) + " " + String.valueOf(da.number); - break; - case 13 : // communique l'atout - // Syntaxe : 13 + numéro de l'atout + numero du joueur a faire - // atout - temp = Integer.valueOf(tableInstr[1]); - atout = temp.intValue(); - stock = findStock(); - frame.lastPlieCanvas.atout = atout; - frame.lastPlieCanvas.repaint(); - temp = Integer.valueOf(tableInstr[2]); - frame.setAtout(temp.intValue()); - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 14 : // demande de jouer en premier - // Syntaxe : 14 - frame.setStatusBar("A vous de jouer ..."); - frame.setAnounceEnabled(true); - frame.playerCanvas.setMode(1); - plieNbr++; - break; - case 15 : // communique la carte jouée - // Syntaxe : 15 + id du joueur + numéro de la carte - temp = Integer.valueOf(tableInstr[1]); - id = temp.intValue(); - temp = Integer.valueOf(tableInstr[2]); - frame.showPlayedCard(id, temp.intValue()); // affiche la carte jouée - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 16 : // demande de jouer ensuite - // Syntaxe : 16 + highest + color + coupe (coupe : 1 = true, 0 = false) - temp = Integer.valueOf(tableInstr[1]); - currentPlie.highest = temp.intValue(); - temp = Integer.valueOf(tableInstr[2]); - currentPlie.color = temp.intValue(); - temp = Integer.valueOf(tableInstr[3]); - if (temp.intValue() == 0) - currentPlie.coupe = false; - else - currentPlie.coupe = true; - frame.setStatusBar("A vous de jouer ..."); - frame.setAnounceEnabled(true); - plieNbr++; - frame.playerCanvas.setMode(2); // let the player play - break; - case 17 : // communique par qui la plie a été prise - // Syntaxe : 17 + id du joueur - temp = Integer.valueOf(tableInstr[1]); - id = temp.intValue(); - frame.pickUpPlie(players[id].getFirstName()); - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 18 : // communique le résultat de la partie - // Syntaxe : 18 + points de l'équipe + points de l'équipe adverse - Integer sc1 = Integer.valueOf(tableInstr[1]); - Integer sc2 = Integer.valueOf(tableInstr[2]); - frame.setScore(sc1.intValue(), sc2.intValue()); - answer = String.valueOf(myPlayer) + " 1"; // signifie que l'opération s'est bien déroulée - break; - case 19 : // demande de déclarer ses annonces - // Syntaxe : 19 - answer = String.valueOf(myPlayer) + " " + String.valueOf(nbrAnounces); - System.out.println("nbrAnounces : " + nbrAnounces); - - for (i=0; i 0)) { - sendAnounces = 2; // annonce le stöck lorsqu'on pose la dernière carte - stock = 0; - System.out.println("Annonce : stock"); - nbrAnounces = 0; - } - } - if ((nbrAnounces > 0) && (plieNbr == 1)) { // on annonce à la première plie - if ((stock > 0) && (nbrAnounces > 1)) { - sendAnounces = 3; - stock = 0; - System.out.println("Annonce : annonce + stock"); - nbrAnounces--; // le stöck peut être décomptabilisé - } - else if ((nbrAnounces > 0) && (stock == 0)) { - sendAnounces = 1; - System.out.println("Annonce : annonce"); - } - } - - network.sendTo(String.valueOf(myPlayer) + " " + String.valueOf(cardNumber) + " " + String.valueOf(score) + " " + String.valueOf(sendAnounces)); - nbrAnounces = 0; // reset anounces number - } - - - // détermine si on peut jouer la carte choisie - public int playCard(int mode, int cardChoosen) { - int answer = 0; // joue - if (mode == 2) { - if (Card.getColor(cardChoosen) != currentPlie.color) { - if (Card.getColor(cardChoosen) == atout) { - if (currentPlie.coupe) - switch (Card.getHeight(cardChoosen)) { - case 5 : answer = 0; // bourg : ok! - break; - case 3 : if (currentPlie.highest != 5) - answer = 0; // nell sans bourg : ok! - else - answer = -2; // on ne peut pas sous-couper - break; - default : if (((currentPlie.highest == 5) || (currentPlie.highest == 3)) || - (currentPlie.highest > Card.getHeight(cardChoosen))) - answer = -2; // on ne peut pas sous-couper - else - answer = 0; // sur-coupe : ok ! - } - else - answer = 0; // coupe : ok! - } - else { // carte jouée pas d'atout - if (checkColor(currentPlie.color)) { - // The player owns cards from the required color - if ((currentPlie.color == atout) && (bourgSec())) - answer = 0; // bourg sec -> ok - else - answer = -1; // il faut suivre - } - else - answer = 0; // pas de cette couleur : ok! - } - } - else - answer = 0; // suivi : ok! - } - return answer; - } - - - // vérifie si le joueur possède la couleur demandée - boolean checkColor(int colorChecked) { - boolean present = false; - for (int i=0; i<9; i++) - if (Card.getColor(cards[i]) == colorChecked) - present = true; - return present; - } - - // cherche si on a le stöck - int findStock() { - int queen = atout * 9 + 6; - int king = atout * 9 + 7; - int stock = 0; - for (int i=0; i<9; i++) - if (cards[i] == queen) - for (int j=0; j<9; j++) - if (cards[j] == king) - stock = 1; - if (stock == 1) - System.out.println("Stock !!"); - return stock; - } - - void findAnounce() { - // type : 0: stock, 1: 3cartes, 2: cinquante, 3: cent, 4: cent(carré), 5: centcinquante, 6: deux cent - nbrAnounces = 0; - // cherche les carrés - int i=0; - int nbrCards; - while ((i<9) && ((cards[i] / 9) == 0)) { // tant que c'est du pique (couleur la + à gauche) - nbrCards = 1; - for (int j=i+1; j<9; j++) { - if ((cards[j] % 9) == (cards[i] % 9)) - nbrCards++; - } - if ((nbrCards == 4) && ((cards[i] % 9) > 2)) { // carré trouvé - if ((cards[i] % 9) == 3) // cent-cinquante - myAnounces[nbrAnounces].type = 5; - else if ((cards[i] % 9) == 5) // deux cents - myAnounces[nbrAnounces].type = 6; - else // cent - myAnounces[nbrAnounces].type = 4; - myAnounces[nbrAnounces].height = cards[i] % 9; - nbrAnounces++; - System.out.println("Carré trouvé : " + cards[i] % 9); - } - i++; - } - - // cherche les suites - for (i=0; i<7; i++) { - int color = Card.getColor(cards[i]); - int j = i + 1; - nbrCards = 1; - while ((j < 9) && ((cards[j] / 9) == color)) { - if (cards[j] == (cards[i] + j - i)) // si les cartes se suivent - nbrCards++; - j++; - } - if (nbrCards > 2) { // on a trouvé une suite - if (nbrCards > 5) - nbrCards = 5; - myAnounces[nbrAnounces].type = nbrCards - 2; - myAnounces[nbrAnounces].height = cards[i + nbrCards - 1]; - nbrAnounces++; - System.out.println("Suite trouvée : " + cards[i + nbrCards - 1] + " type : " + (nbrCards - 2)); - i = j-1; - } - } - - // Stöck - if (stock > 0) - nbrAnounces++; - } - - - /** - * Checks if we have "bourg sec" - */ - boolean bourgSec() { - boolean bourg = false; - int atoutNbr = 0; - for (int i=0; i<9; i++) - if (Card.getColor(cards[i]) == atout) { - atoutNbr++; - if (Card.getHeight(cards[i]) == 5) // bourg - bourg = true; - } - if (bourg && (atoutNbr == 1)) - return true; - else - return false; - } - - /** - * Disconect from the server - */ - public void disconnect() { - listener.stop = true; - network.disconnect(); - } -} - -// ********************** CLASS TMember **************************************** -class TMember { - // Variables - private String firstName; - private String lastName; - private String function; - - // Constructeur - public TMember() { - } - - public TMember(String firstName, String lastName, String function) { - this(); - this.firstName = firstName; - this.lastName = lastName; - this.function = function; - } - - // Getters - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } - - public String getFunction() { - return function; - } - - // Setters - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public void setFunction(String function) { - this.function = function; - } -} - -// **************************** CLASS Player *********************************** -class Player extends TMember { - // Variables - private int iD; // numéro d'identification du joueur - - public Player() { - super(); - } - - public Player(Player copyPlayer) { - super(copyPlayer.getFirstName(), copyPlayer.getLastName(), - copyPlayer.getFunction()); - this.iD = copyPlayer.getID(); - } - - // Getter - public int getID() { - return iD; - } - - // Setter - public void setID(int iD) { - this.iD = iD; - } -} - - -// **************************** CLASS Card ************************************* -abstract class Card { - static final int[] value = {0,0,0,0,10,2,3,4,11}; // valeurs des cartes - static final int[] valueAtout = {0,0,0,14,10,20,3,4,11}; - static final String[] color = {"pique", "coeur", "carreau", "trèfle"}; - static final String[] name = {"six", "sept", "huit", "neuf", "dix", "bourg", "dame", "roi", "as"}; - static final String[] anounce = {"stöck", "3 cartes", "cinquante", "cent", "cent", "cent cinquante", "deux cents"}; - - public static int getColor(int card) { - return card / 9; - } - - public static int getHeight(int card) { - return card % 9; - } -} - - -// **************************** CLASS Plie ************************************* -class Plie { - public int highest; // plus haute carte (si coupé, plus haut atout) - public int color; // couleur demandée - public boolean coupe; // coupé ou pas -} - - -// **************************** CLASS Anounce ********************************** -class Anounce { - int type; // 0: stöck, 1: 3 cartes, 2: cinquante, 3: cent, 4: carré - int height; // hauteur de l'annonce -} diff --git a/client/JassCanvas.java b/client/JassCanvas.java deleted file mode 100644 index 98843be..0000000 --- a/client/JassCanvas.java +++ /dev/null @@ -1,24 +0,0 @@ -import java.awt.*; - -public class JassCanvas extends Canvas{ - int mode; // 0 : rien, 1 : jouer - String name; - boolean atout; - - public void setMode(int mode) { - this.mode = mode; - } - - public void setAtout(boolean atout) { - this.atout = atout; - } - - public void setName(String name) { - this.name = name; - } - - public int getMode() { - return mode; - } - -} diff --git a/client/Makefile b/client/Makefile deleted file mode 100644 index e6d116d..0000000 --- a/client/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -SOURCES = AbsoluteConstraints.java CanvasPlayer.java DialogConnect.java \ - AbsoluteLayout.java CanvasTop.java DialogInfo.java \ - CanvasBorder.java ClientFrame.java \ - DialogPartnerChoice.java DialogNewPart.java ClientListener.java \ - DialogTeamChoice.java CanvasCenter.java ClientNetwork.java \ - FlatJassClientSystem.java CanvasLastPlie.java DialogAtout.java \ - JassCanvas.java - -JAVA = java -JAVAC = javac - -all: $(SOURCES:.java=.class) - -%.class: %.java - $(JAVAC) $< - -run: $(SOURCES:.java=.class) - $(JAVA) FlatJassClientSystem - -clean: - $(RM) *.class *~ diff --git a/client/pics/0.gif b/client/pics/0.gif deleted file mode 100644 index 2a7dcaf..0000000 Binary files a/client/pics/0.gif and /dev/null differ diff --git a/client/pics/1.gif b/client/pics/1.gif deleted file mode 100644 index 1c534ab..0000000 Binary files a/client/pics/1.gif and /dev/null differ diff --git a/client/pics/10.gif b/client/pics/10.gif deleted file mode 100644 index 6df8add..0000000 Binary files a/client/pics/10.gif and /dev/null differ diff --git a/client/pics/11.gif b/client/pics/11.gif deleted file mode 100644 index ca32442..0000000 Binary files a/client/pics/11.gif and /dev/null differ diff --git a/client/pics/12.gif b/client/pics/12.gif deleted file mode 100644 index 30939b5..0000000 Binary files a/client/pics/12.gif and /dev/null differ diff --git a/client/pics/13.gif b/client/pics/13.gif deleted file mode 100644 index 8415530..0000000 Binary files a/client/pics/13.gif and /dev/null differ diff --git a/client/pics/14.gif b/client/pics/14.gif deleted file mode 100644 index 2d40d52..0000000 Binary files a/client/pics/14.gif and /dev/null differ diff --git a/client/pics/15.gif b/client/pics/15.gif deleted file mode 100644 index 3740c0e..0000000 Binary files a/client/pics/15.gif and /dev/null differ diff --git a/client/pics/16.gif b/client/pics/16.gif deleted file mode 100644 index aec8685..0000000 Binary files a/client/pics/16.gif and /dev/null differ diff --git a/client/pics/17.gif b/client/pics/17.gif deleted file mode 100644 index de3839c..0000000 Binary files a/client/pics/17.gif and /dev/null differ diff --git a/client/pics/18.gif b/client/pics/18.gif deleted file mode 100644 index e627ef5..0000000 Binary files a/client/pics/18.gif and /dev/null differ diff --git a/client/pics/19.gif b/client/pics/19.gif deleted file mode 100644 index febc412..0000000 Binary files a/client/pics/19.gif and /dev/null differ diff --git a/client/pics/2.gif b/client/pics/2.gif deleted file mode 100644 index b7930a0..0000000 Binary files a/client/pics/2.gif and /dev/null differ diff --git a/client/pics/20.gif b/client/pics/20.gif deleted file mode 100644 index e991341..0000000 Binary files a/client/pics/20.gif and /dev/null differ diff --git a/client/pics/21.gif b/client/pics/21.gif deleted file mode 100644 index f0dd016..0000000 Binary files a/client/pics/21.gif and /dev/null differ diff --git a/client/pics/22.gif b/client/pics/22.gif deleted file mode 100644 index b673426..0000000 Binary files a/client/pics/22.gif and /dev/null differ diff --git a/client/pics/23.gif b/client/pics/23.gif deleted file mode 100644 index 35210fb..0000000 Binary files a/client/pics/23.gif and /dev/null differ diff --git a/client/pics/24.gif b/client/pics/24.gif deleted file mode 100644 index f2e927f..0000000 Binary files a/client/pics/24.gif and /dev/null differ diff --git a/client/pics/25.gif b/client/pics/25.gif deleted file mode 100644 index 79823c9..0000000 Binary files a/client/pics/25.gif and /dev/null differ diff --git a/client/pics/26.gif b/client/pics/26.gif deleted file mode 100644 index 10ff63b..0000000 Binary files a/client/pics/26.gif and /dev/null differ diff --git a/client/pics/27.gif b/client/pics/27.gif deleted file mode 100644 index ae144a4..0000000 Binary files a/client/pics/27.gif and /dev/null differ diff --git a/client/pics/28.gif b/client/pics/28.gif deleted file mode 100644 index c0bf665..0000000 Binary files a/client/pics/28.gif and /dev/null differ diff --git a/client/pics/29.gif b/client/pics/29.gif deleted file mode 100644 index 15fb493..0000000 Binary files a/client/pics/29.gif and /dev/null differ diff --git a/client/pics/3.gif b/client/pics/3.gif deleted file mode 100644 index 9751464..0000000 Binary files a/client/pics/3.gif and /dev/null differ diff --git a/client/pics/30.gif b/client/pics/30.gif deleted file mode 100644 index 00ca35d..0000000 Binary files a/client/pics/30.gif and /dev/null differ diff --git a/client/pics/31.gif b/client/pics/31.gif deleted file mode 100644 index 8d7ee17..0000000 Binary files a/client/pics/31.gif and /dev/null differ diff --git a/client/pics/32.gif b/client/pics/32.gif deleted file mode 100644 index 2ea3293..0000000 Binary files a/client/pics/32.gif and /dev/null differ diff --git a/client/pics/33.gif b/client/pics/33.gif deleted file mode 100644 index f4a7483..0000000 Binary files a/client/pics/33.gif and /dev/null differ diff --git a/client/pics/34.gif b/client/pics/34.gif deleted file mode 100644 index 30bf9ad..0000000 Binary files a/client/pics/34.gif and /dev/null differ diff --git a/client/pics/35.gif b/client/pics/35.gif deleted file mode 100644 index 848e4c4..0000000 Binary files a/client/pics/35.gif and /dev/null differ diff --git a/client/pics/4.gif b/client/pics/4.gif deleted file mode 100644 index 3c16014..0000000 Binary files a/client/pics/4.gif and /dev/null differ diff --git a/client/pics/5.gif b/client/pics/5.gif deleted file mode 100644 index fd2057f..0000000 Binary files a/client/pics/5.gif and /dev/null differ diff --git a/client/pics/6.gif b/client/pics/6.gif deleted file mode 100644 index 0d14b17..0000000 Binary files a/client/pics/6.gif and /dev/null differ diff --git a/client/pics/7.gif b/client/pics/7.gif deleted file mode 100644 index 9eb02fd..0000000 Binary files a/client/pics/7.gif and /dev/null differ diff --git a/client/pics/8.gif b/client/pics/8.gif deleted file mode 100644 index 33b3fd6..0000000 Binary files a/client/pics/8.gif and /dev/null differ diff --git a/client/pics/9.gif b/client/pics/9.gif deleted file mode 100644 index ab45c7c..0000000 Binary files a/client/pics/9.gif and /dev/null differ diff --git a/client/pics/c0.gif b/client/pics/c0.gif deleted file mode 100644 index 8135304..0000000 Binary files a/client/pics/c0.gif and /dev/null differ diff --git a/client/pics/c1.gif b/client/pics/c1.gif deleted file mode 100644 index 27e4990..0000000 Binary files a/client/pics/c1.gif and /dev/null differ diff --git a/client/pics/c2.gif b/client/pics/c2.gif deleted file mode 100644 index 499a0cd..0000000 Binary files a/client/pics/c2.gif and /dev/null differ diff --git a/client/pics/c3.gif b/client/pics/c3.gif deleted file mode 100644 index 636ba46..0000000 Binary files a/client/pics/c3.gif and /dev/null differ diff --git a/client/pics/dos.gif b/client/pics/dos.gif deleted file mode 100644 index e6dcc48..0000000 Binary files a/client/pics/dos.gif and /dev/null differ diff --git a/doc/class_diagram.xmi b/doc/class_diagram.xmi new file mode 100644 index 0000000..2f7470a --- /dev/null +++ b/doc/class_diagram.xmi @@ -0,0 +1,436 @@ + + + + + umbrello uml modeller http://umbrello.kde.org + 1.6.13 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jass.iml b/jass.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/jass.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..573e1a3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + com.leflat + jass + 2.0-SNAPSHOT + + + + org.junit.jupiter + junit-jupiter-api + 5.4.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.4.2 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + + + org.apache.maven.plugins + maven-jar-plugin + + + + **/log4j.properties + + + + + com.leflat.jass.client.JassClient + + + + + + + + + \ No newline at end of file diff --git a/server/ClientLeftException.java b/server/ClientLeftException.java deleted file mode 100644 index 7eb3407..0000000 --- a/server/ClientLeftException.java +++ /dev/null @@ -1,13 +0,0 @@ - - -class ClientLeftException extends Exception { - int clientID; - - public ClientLeftException(int clientID) { - this.clientID = clientID; - } - - public int getClientId() { - return clientID; - } -} diff --git a/server/FlatJassServerSystem.java b/server/FlatJassServerSystem.java deleted file mode 100644 index f44187b..0000000 --- a/server/FlatJassServerSystem.java +++ /dev/null @@ -1,821 +0,0 @@ -//Title: FlatJassServer -//Version: 1.2 -//Copyright: Copyright (c) 1998 -//Author: Pierre Métrailler & Jérome Berclaz -//Company: Flat(r) -//Description: This is the server for the Jass Card Game made by and -// for the proud members of the FLAT(r) -// -// Long life to the FLAT(r)! - - -// package FlatJassServerProject; -import java.net.*; -import java.io.*; -import java.util.*; - -public class FlatJassServerSystem { - private int atout; - private int firstToPlay; // celui qui commence la partie et fait atout - private int playersConnected; // nombre de joueurs connectés - private Plie currentPlie; // plie en cours - private Player[] players = new Player[4]; // les 4 joueurs - private Team[] teams = new Team[2]; // les 2 équipes - - // ***************** PROVISOIRE **************************************** - // static final int[] cards = {0,1,2,3,8,10,15,16,18, 11,12,13,17,19,20,21,30,34, - // 14,22,23,25,28,29,31,35,32, 4,5,6,7,33,9,24,26,27}; - //********************************************************************** - - int port_num; - ServerSocket myServerSocket=null; - ServerNetwork[] myServerNetwork = new ServerNetwork[4]; - - - public FlatJassServerSystem() { - this(32107); - } - - public FlatJassServerSystem(int port) { - port_num = port; - - for (int i=0; i<4; i++) // création des joueurs - players[i] = new Player(); - for (int i=0; i<2; i++) // création des équipes - teams[i] = new Team(); - currentPlie = new Plie(); - - System.out.println("Flat Jass System Server"); - System.out.println("Version 1.2"); - System.out.println("(c) 2000-2002 by FLAT(r)");System.out.println(); - playersConnected = 0; - - // Create server socket - try { - myServerSocket = new ServerSocket(port_num); - - System.out.println("Server socket created on port "+ port_num); - } - catch (IOException e) { - System.out.println("ERROR: cannot create server socket"); - System.exit(1); - } - - do { - - try { - while (playersConnected < 4) { // attend 4 connexions - playersConnected = waitConnect(); - } - - Integer temp; - String[] instr = new String[10]; - - do { - chooseTeam(); // détermine les équipes - - // Play one game (until 1500) - playPart(); - - // ask whether they want to play another part - myServerNetwork[0].sendStr("22"); - - instr = decode(myServerNetwork[0].rcvStr()); // réponse - temp = Integer.valueOf(instr[1]); - - teams[0].resetScore(); - teams[1].resetScore(); - } while (temp.intValue() != 0); - - } catch (ClientLeftException e) { - int id = e.getClientId(); - for (int i=0; (i<=playersConnected) && (i!=4); i++) - if (i != id) - myServerNetwork[i].sendStr("23 "+String.valueOf(id)); - - System.out.println("sleep..."); - try { - Thread.sleep(2000); - } catch (InterruptedException ex) { - } - System.out.println("Wakeup..."); - } - - // close sockets and remove players - for(int i=0; (i<=playersConnected) && (i!=4); i++) - myServerNetwork[i].close(); - playersConnected = 0; - } while(true); // loop forever - } - - // attend la connexion d'un joueur - public int waitConnect() throws ClientLeftException{ - int newPlayers = playersConnected; - if (myServerNetwork[playersConnected] == null) - myServerNetwork[playersConnected]=new ServerNetwork(); - if (myServerNetwork[playersConnected].connect(myServerSocket)) { - // la connexion a réussi - - myServerNetwork[playersConnected].setClientId(playersConnected); - myServerNetwork[playersConnected].sendStr("1 " + String.valueOf(playersConnected)); // donne son id et demande des infos - String[] instr = new String[10]; - instr = decode(myServerNetwork[playersConnected].rcvStr()); // attend les infos - - players[playersConnected].firstName = instr[1]; - players[playersConnected].lastName = instr[2]; - players[playersConnected].iD = playersConnected; - - System.out.println(instr[1] + " " +instr[2] + " is connected"); - - for (int i=0; i 1) - if (args[0].compareTo("-p") == 0) - temp = Integer.valueOf(args[1]); - else { - System.out.println("Syntax : java FlatJassServerSystem -p "); - System.exit(-1); - } - FlatJassServerSystem flatJassServerSystem; - if (temp == null) - flatJassServerSystem = new FlatJassServerSystem(); - else - flatJassServerSystem = new FlatJassServerSystem(temp.intValue()); -// flatJassServerSystem.invokedStandalone = true; - } - private boolean invokedStandalone = false; - - - // Procédure de décodage des instructions - private String[] decode(String instr) { - int cmpt = 0; - int cursor = 0; - String[] table = new String[10]; - for (int i=1; i (choosenCards[highest] % 9)) - highest = i; - } - for (int i=0; i<4; i++) { - if (i != lowest) - if ((choosenCards[i] % 9) == (choosenCards[lowest] % 9)) - ok = false; - if (i != highest) - if ((choosenCards[i] % 9) == (choosenCards[highest] % 9)) - ok = false; - } - if (ok) { - int j = 0; - for (int k=0; k<4; k++) - if (k == lowest) { - teams[0].players[0] = players[lowest]; - players[lowest].myTeam = 0; - } - else - if (k == highest) { - teams[0].players[1] = players[highest]; - players[highest].myTeam = 0; - } - else { - teams[1].players[j] = players[k]; - players[k].myTeam = 1; - j++; - } - - } - return ok; - } - - - // distribue les cartes - int[] chooseCards() { - final int[] cards = new int[36]; - boolean[] usedCards = new boolean[36]; - Random rand = new Random(); - for (int i=0; i<36; i++) - usedCards[i] = false; - int j; - for (int i=0; i<35; i++) { - do { - j = (int)(rand.nextDouble() * 36); - } while (usedCards[j]); - cards[i] = j; - usedCards[j] = true; - } - j = 0; - while (usedCards[j]) - j++; - cards[35] = j; - return cards; - } - - - void playPart() throws ClientLeftException{ - /* randomly choose the cards and send them */ - firstToPlay = distribute(); - String answer; - int nextPlayer; - do { - chooseAtout(); // choisit l'atout - nextPlayer = firstToPlay; - - /* for (int i=0; i<9; i++) // fait jouer les 9 plies - nextPlayer = playPlie(nextPlayer); */ - - int j=0; - while ((j<9) && (nextPlayer != -1)) { // fait jouer les 9 plies - nextPlayer = playPlie(nextPlayer); - j++; - } - - if (nextPlayer != -1) { // si personne n'a gagné : on continue normalement - // 5 de der - if (atout == 0) - teams[players[currentPlie.owner].myTeam].addScore(10); - else - teams[players[currentPlie.owner].myTeam].addScore(5); - - for (int i=0; i<4; i++) { // envoie le score - myServerNetwork[i].sendStr("18 " + String.valueOf(teams[players[i].myTeam].getScore()) - + " " + String.valueOf(teams[(players[i].myTeam + 1)%2].getScore())); - answer = myServerNetwork[i].rcvStr(); // réponse - } - - /* waits a few seconds so that the players can see the last - * cards and the score */ - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - } - - firstToPlay = (firstToPlay + 1) % 4; - distribute(); - } - else { // si une équipe a gagné - for (int i=0; i<4; i++) { // envoie le score - myServerNetwork[i].sendStr("18 " + String.valueOf(teams[players[i].myTeam].getScore()) - + " " + String.valueOf(teams[(players[i].myTeam + 1)%2].getScore())); - answer = myServerNetwork[i].rcvStr(); // réponse - } - } - - // répète jusqu'à ce qu'on gagne - } while ((!teams[0].won) && (!teams[1].won)); - - // Sends the winner to all player - int winner = teams[0].won ? 0 : 1; - for (int i=0; i<4; i++) { - myServerNetwork[i].sendStr("21 " + String.valueOf(winner) + " " + - String.valueOf(teams[winner].players[0].iD) + " " + - String.valueOf(teams[winner].players[1].iD)); - answer = myServerNetwork[i].rcvStr(); - } - - /* waits a few seconds so that the players can see all the cards */ - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - } - - } - - - void chooseAtout() throws ClientLeftException { - myServerNetwork[firstToPlay].sendStr("11"); // demande de faire atout en premier - String[] instr = new String[10]; - instr = decode(myServerNetwork[firstToPlay].rcvStr()); // réponse - Integer temp = Integer.valueOf(instr[1]); - if (temp.intValue() == 4) { // si on passe - int second = (firstToPlay + 2) % 4; - myServerNetwork[second].sendStr("12"); // demande de faire atout en second - instr = decode(myServerNetwork[second].rcvStr()); // réponse - } - temp = Integer.valueOf(instr[1]); - atout = temp.intValue(); - for (int i=0; i<4; i++) { - // envoie l'atout choisi - myServerNetwork[i].sendStr("13 " + instr[1] + " " + firstToPlay); - instr[2] = myServerNetwork[i].rcvStr(); // réponse - } - } - - - - int distribute() throws ClientLeftException { - int seven = 0; // 7 de carreau - int[] cards = new int[36]; - cards = chooseCards(); // choisir les cartes au hasard - String s; // chaîne à envoyer - for (int i=0; i<4; i++) { - s = "10"; - for (int j=0; j<9; j++) { - s += " " + String.valueOf(cards[i*9+j]); - if (cards[i*9+j] == 19) // 7 de carreau - seven = i; - } - myServerNetwork[i].sendStr(s); - s = myServerNetwork[i].rcvStr(); - } - return seven; - } - - - int playPlie(int player) throws ClientLeftException { - currentPlie.owner = player; - currentPlie.coupe = 0; - myServerNetwork[player].sendStr("14"); // demande de jouer en premier - String[] instr = new String[10]; - instr = decode(myServerNetwork[player].rcvStr()); //réponse - Integer temp = Integer.valueOf(instr[1]); - currentPlie.color = temp.intValue() / 9; - currentPlie.highest = temp.intValue() % 9; - temp = Integer.valueOf(instr[2]); - currentPlie.score = temp.intValue(); - - temp = Integer.valueOf(instr[3]); // Annonces ? - int[] instr2 = new int[10]; // tableau d'instructions en integer - switch (temp.intValue()) { - case 1 : // Annonces - System.out.println("Annonces"); - myServerNetwork[player].sendStr("19"); // demande des précisions sur l'annonce - instr2 = decodint(myServerNetwork[player].rcvStr()); //réponse - for (int i=0; i currentPlie.highest)) { - currentPlie.highest = playedCard % 9; - currentPlie.owner = (player + i + 1) % 4; - } - } - // else souscoupe => nothing to do - } - else { // first to cut - currentPlie.coupe = 1; - currentPlie.highest = playedCard % 9; - currentPlie.owner = (player + i + 1) % 4; - } - } - else // si c'est joué atout - switch (playedCard % 9) { - case 3 : if (currentPlie.highest != 5) { // si on joue le nell - currentPlie.highest = playedCard % 9; - currentPlie.owner = (player + i + 1) % 4; - } - break; - case 5 : // si on joue le bourg - currentPlie.highest = playedCard % 9; - currentPlie.owner = (player + i + 1) % 4; - break; - default : // sinon - if (((currentPlie.highest!=5) && (currentPlie.highest!=3)) && ((playedCard % 9) > currentPlie.highest)) { - currentPlie.highest = playedCard % 9; - currentPlie.owner = (player + i + 1) % 4; - } - } - } - else if ((playedCard / 9) == currentPlie.color) - if (((playedCard % 9) > currentPlie.highest) && (currentPlie.coupe == 0)) { - currentPlie.owner = (player + i + 1) % 4; - currentPlie.highest = playedCard % 9; - } - temp = Integer.valueOf(instr[2]); - currentPlie.score = currentPlie.score + temp.intValue(); // augmente le score de la plie - } - - /* now everybody has played ... */ - - /* waits a few seconds so that the players can see all the cards */ - try { - Thread.sleep(1500); - } catch (InterruptedException e) { - } - - // communique qui a pris la plie - for (int i=0; i<4; i++) { - myServerNetwork[i].sendStr("17 " + String.valueOf(currentPlie.owner)); - instr[9] = myServerNetwork[i].rcvStr(); // réponse - } - - // choix et comptabilisation des annonces - int stock = -1; - int maxAnounce = 1; - int maxHeight = 0; - int anouncingTeam = -1; // joueur qui a la plus grosse annonce - for (int j=0; j<4; j++) - for (int i=0; i maxAnounce) { - // plus grosse annonce - anouncingTeam = j; - maxAnounce = players[j].anounces[i].type; - maxHeight = Card.getHeight(players[j].anounces[i].card); - } - else if ((players[j].anounces[i].type == maxAnounce) && - (Card.getHeight(players[j].anounces[i].card) > - maxHeight)) { - // même annonce plus haute - anouncingTeam = j; - maxHeight = Card.getHeight(players[j].anounces[i].card); - } - else if ((players[j].anounces[i].type == maxAnounce) && - (Card.getHeight(players[j].anounces[i].card) - == maxHeight)) { - // meme annonce, meme hauteur - } - if (players[j].anounces[i].type == 0) - stock = j; - } - String info; - System.out.println("Bigger 'annonce' : "+ anouncingTeam); - - if (anouncingTeam != -1) { // there are announces - for (int i=0; i<4; i++) { - if (((i == anouncingTeam) || (i == ((anouncingTeam + 2) % 4))) - && (players[i].nbrAnounces > 0)){ - // annonceur - - info = "20 " + i + " " + players[i].nbrAnounces; - for (int j=0; j 1499) - won = true; - } - - public int getScore() { - return currentScore; - } -} - -class Plie { - public int highest; // la plus haute carte de la plie (celle qui tient la plie) - public int color; // la couleur demandée - public int score; // la valeur de la plie - public int coupe; // 0 : pas coupé, 1 : coupé - public int owner; // iD de celui qui tient la plie -} - -/* ************************** REMARQUE ****************************** - Les cartes sont en fait représentées par des int de 0 à 35 - où "carte div 9" donne sa couleur et "carte mod 9" sa - hauteur. La classe Card est donc utilisée ici que pour - les méthodes statiques getColor et getHeight. - *************************************************************** */ - -abstract class Card { - static final int[] anounceValue = {20, 20, 50, 100, 100, 150, 200}; - - public static int getColor(int card) { - return card / 9; - } - - public static int getHeight(int card) { - return card % 9; - } -} - -class Anounce { - int type; // 0: stöck, 1: 3 cartes, 2: cinquante, 3: cent, 4: carré - int card; // plus haute carte de l'annonce - int player; -} diff --git a/server/Makefile b/server/Makefile deleted file mode 100644 index 07c7d86..0000000 --- a/server/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -SOURCES = FlatJassServerSystem.java ServerNetwork.java \ - ClientLeftException.java - -JAVA = java -JAVAC = javac - -all: $(SOURCES:.java=.class) - -%.class: %.java - $(JAVAC) $< - -run: $(SOURCES:.java=.class) - $(JAVA) FlatJassServerSystem - -clean: - $(RM) *.class *~ diff --git a/server/ServerNetwork.java b/server/ServerNetwork.java deleted file mode 100644 index 06cd50b..0000000 --- a/server/ServerNetwork.java +++ /dev/null @@ -1,98 +0,0 @@ -//Title: FlatJassServer -//Version: -//Copyright: Copyright (c) 1998 -//Author: Pierre Métrailler & Jérome Berclaz -//Company: Flat -//Description: Your description - - -//package FlatJassServerProject; - -import java.net.*; -import java.io.*; - -public class ServerNetwork { - - public static final int PORT_NUM = 1500; - - //ServerSocket myServerSocket; - Socket myClientSocket = null; - InputStreamReader isr; - BufferedReader is; - PrintWriter os; - int clientId; - - - public ServerNetwork() { - } - - public boolean connect(ServerSocket myServerSocket) { - // waiting and bind - - System.out.println("Waiting for connections"); - try { - - myClientSocket=myServerSocket.accept(); - - //streams - // a verifier le autoflush - isr = new InputStreamReader(myClientSocket.getInputStream()); - is = new BufferedReader(isr); - os = new PrintWriter(new BufferedOutputStream(myClientSocket.getOutputStream()),false); - - - } - catch (IOException e) { - System.out.println("Error unable to bind socket"); - //System.exit(1); - } - System.out.println("Connection successful."); - return true; - - } - - public void setClientId(int clientId) { - this.clientId = clientId; - } - - public boolean sendStr(String strToSend) { - - os.println(strToSend); - os.flush(); - System.out.println("SERVER sent : "+strToSend); - return true; - } - - public String rcvStr() throws ClientLeftException{ - String rcvTemp = null; - - //implementer timeout + exc - - try { - rcvTemp=is.readLine(); - } - catch (IOException e) { - System.out.println("Error during reception"); - //System.exit(1); - } - if (rcvTemp != null) - System.out.println("Received : " + rcvTemp); - else { - System.out.println("Client has left unexpectedly"); - throw new ClientLeftException(clientId); - } - - return rcvTemp; - - } - - public void close() { - try { - myClientSocket.close(); - } - catch (IOException e) { - System.out.println("Error while closing socket"); - System.exit(1); - } - } -} diff --git a/client/AbsoluteConstraints.java b/src/main/java/com/leflat/jass/client/AbsoluteConstraints.java similarity index 99% rename from client/AbsoluteConstraints.java rename to src/main/java/com/leflat/jass/client/AbsoluteConstraints.java index bc8c7f9..c00c163 100644 --- a/client/AbsoluteConstraints.java +++ b/src/main/java/com/leflat/jass/client/AbsoluteConstraints.java @@ -13,6 +13,9 @@ //package org.netbeans.lib.awtextra; +package com.leflat.jass.client; + + import java.awt.Dimension; import java.awt.Point; diff --git a/client/AbsoluteLayout.java b/src/main/java/com/leflat/jass/client/AbsoluteLayout.java similarity index 99% rename from client/AbsoluteLayout.java rename to src/main/java/com/leflat/jass/client/AbsoluteLayout.java index 83a9434..3fc0fd1 100644 --- a/client/AbsoluteLayout.java +++ b/src/main/java/com/leflat/jass/client/AbsoluteLayout.java @@ -13,6 +13,9 @@ //package org.netbeans.lib.awtextra; +package com.leflat.jass.client; + + import java.awt.*; /** AbsoluteLayout is a LayoutManager that works as a replacement for "null" layout to diff --git a/src/main/java/com/leflat/jass/client/CanvasBorder.java b/src/main/java/com/leflat/jass/client/CanvasBorder.java new file mode 100644 index 0000000..47e5bf1 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/CanvasBorder.java @@ -0,0 +1,37 @@ +/* + * CanvasBorder.java + * + * Created on 18. avril 2000, 16:49 + */ + + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + +import java.awt.*; + +public class CanvasBorder extends JassCanvas { + public static final int Y_STEP = 30; + + public CanvasBorder() { + } + + public void paint(Graphics g) { + Dimension d = getSize(); + + int w = (d.width - CardImages.IMG_WIDTH) / 2; + int h = (d.height - hand.size() * Y_STEP - 66) / 2 + 20; + for (int i = 0; i < hand.size(); i++) { + g.drawImage(CardImages.getInstance().getImage(hand.get(i)), w, h + i * 30, this); + } + + g.drawString(name, 20, 30); + if (atout) { + g.drawString("atout", 20, 60); + } + } +} diff --git a/src/main/java/com/leflat/jass/client/CanvasCenter.java b/src/main/java/com/leflat/jass/client/CanvasCenter.java new file mode 100644 index 0000000..a162ba2 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/CanvasCenter.java @@ -0,0 +1,112 @@ +/* + * CanvasCenter.java + * + * Created on 18. avril 2000, 18:04 + */ + + +/** + * @author Berclaz Jérôme + * @version 1.1 + */ + +package com.leflat.jass.client; + +import com.leflat.jass.common.Card; + +import java.awt.*; +import java.util.*; +import java.util.List; + +import static java.lang.Integer.min; + +public class CanvasCenter extends Canvas { + private static final int X_OFFSET = 10; + private static final int Y_OFFSET = 40; + private static final int X_STEP = 8; + private static final int[] CARD_POS_X = {-35, 25, -35, -95}; + private static final int[] CARD_POS_Y = {2, -48, -98, -48}; + public static final int MODE_PASSIVE = 0; + public static final int MODE_DRAW_TEAMS = 1; + public static final int MODE_PICK_CARD = 2; + public static final int MODE_GAME = 3; + + + private int mode; // 0 : rien, 1 : tirer les équipes + // 2 : tirer les équipes et choisir une carte + // 3 : jouer + private List drawnCards = new ArrayList<>(); + private Map shownCards = new HashMap<>(); + + public CanvasCenter() { + mode = MODE_PASSIVE; + } + + public void setMode(int mode) { + this.mode = mode; + repaint(); + } + + public void drawCard(int i) { + drawnCards.add(i); + repaint(); + } + + public void resetCards() { + drawnCards.clear(); + shownCards.clear(); + repaint(); + } + + public void showCard(Card card, int player) { + shownCards.put(player, card); + repaint(); + } + + public Collection getShownCards() { + return shownCards.values(); + } + + public void paint(Graphics g) { + System.out.println("Repaint"); + Dimension d = getSize(); + switch (mode) { + case MODE_DRAW_TEAMS: + case MODE_PICK_CARD: + for (int i = 0; i < 36; i++) { + if (!drawnCards.contains(i)) { + g.drawImage(CardImages.getInstance().getBackImage(), X_OFFSET + i * X_STEP, Y_OFFSET, this); + } + } + break; + case MODE_GAME: + int w = d.width / 2; + int h = d.height / 2; + for (int i = 0; i < 4; i++) { + if (shownCards.containsKey(i)) { + g.drawImage(CardImages.getInstance().getImage(shownCards.get(i)), w + CARD_POS_X[i], h + CARD_POS_Y[i], this); + } + } + } + } + + public int getCard(int x, int y) { + if (mode != MODE_PICK_CARD) { + return -1; + } + if (y < Y_OFFSET || y > Y_OFFSET + CardImages.IMG_HEIGHT) { + return -1; + } + int highCardNbr = (x - X_OFFSET) / X_STEP; + int lowCardNbr = (x - X_OFFSET - CardImages.IMG_WIDTH) / X_STEP; + if (highCardNbr < 0 || lowCardNbr > 35) { + return -1; + } + for (int nbr = min(highCardNbr, 35); nbr >= lowCardNbr; nbr--) { + if (!drawnCards.contains(nbr)) { + return nbr; + } + } + return -1; + } +} diff --git a/src/main/java/com/leflat/jass/client/CanvasLastPlie.java b/src/main/java/com/leflat/jass/client/CanvasLastPlie.java new file mode 100644 index 0000000..447cc0d --- /dev/null +++ b/src/main/java/com/leflat/jass/client/CanvasLastPlie.java @@ -0,0 +1,69 @@ +/* + * CanvasLastPlie.java + * + * Created on 19. avril 2000, 11:23 + */ + + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + +import com.leflat.jass.common.Card; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class CanvasLastPlie extends Canvas { + private List lastPlie = new ArrayList<>(); + private int atout; + private int ourScore, theirScore; + + public CanvasLastPlie() { + ourScore = 0; + theirScore = 0; + atout = 4; // ne rien afficher + } + + public void setLastPlie(Collection plie) { + lastPlie.clear(); + lastPlie.addAll(plie); + repaint(); + } + + public void setScores(int ourScore, int theirScore) { + this.ourScore = ourScore; + this.theirScore = theirScore; + repaint(); + } + + public void setAtout(int atout) { + this.atout = atout; + repaint(); + } + + public void hideAtout() { + this.atout = 4; + repaint(); + } + + public void paint(Graphics g) { + for (int i = 0; i < lastPlie.size(); i++) { + g.drawImage(CardImages.getInstance().getImage(lastPlie.get(i)), 120 + 30 * i, 5, this); + } + + if (atout < 4) { + g.drawImage(CardImages.getInstance().getColorImage(atout), 380, 8, this); + } + + g.drawString("Dernière plie:", 20, 20); + g.drawString("Atout:", 340, 20); + g.drawString("Nous: " + String.valueOf(ourScore), 420, 13); + g.drawString("Eux : " + String.valueOf(theirScore), 420, 27); + } +} diff --git a/src/main/java/com/leflat/jass/client/CanvasPlayer.java b/src/main/java/com/leflat/jass/client/CanvasPlayer.java new file mode 100644 index 0000000..61b5492 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/CanvasPlayer.java @@ -0,0 +1,67 @@ +/* + * CanvasPlayer.java + * + * Created on 18. avril 2000, 17:31 + */ + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + +import com.leflat.jass.common.Card; + +import java.awt.*; + +import java.util.List; + +public class CanvasPlayer extends JassCanvas { + private static final int X_STEP = 35; + + public CanvasPlayer() { + } + + public void paint(Graphics g) { + if (!hand.isEmpty()) { + Dimension d = getSize(); + int cardsWidth = getCardsWidth(); + int xOffset = (d.width - cardsWidth) / 2; + for (int i = 0; i < hand.size(); i++) { + g.drawImage(CardImages.getInstance().getImage(hand.get(i)), + xOffset + i * X_STEP, 20, this); + } + } + g.drawString(name, 30, 15); + if (atout) { + g.drawString("atout", name.length() * 7 + 60, 15); + } + } + + public Card getCard(int x, int y) { + if (mode != JassCanvas.MODE_PLAY) { + return null; + } + if (y < 20) { + return null; + } + Dimension d = getSize(); + int cardsWidth = getCardsWidth(); + int xOffset = (d.width - cardsWidth) / 2; + for (int i = hand.size() - 1; i >= 0; i--) { + if (x >= xOffset + i * X_STEP && x < xOffset + i * X_STEP + CardImages.IMG_WIDTH) { + return hand.get(i); + } + } + return null; + } + + private int getCardsWidth() { + return CardImages.IMG_WIDTH + (hand.size() - 1) * X_STEP; + } + + public List getHand() { + return hand; + } +} diff --git a/src/main/java/com/leflat/jass/client/CanvasTop.java b/src/main/java/com/leflat/jass/client/CanvasTop.java new file mode 100644 index 0000000..685fe76 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/CanvasTop.java @@ -0,0 +1,37 @@ +/* + * CanvasTop.java + * + * Created on 18. avril 2000, 17:31 + */ + + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + +import java.awt.*; + +public class CanvasTop extends JassCanvas { + private static final int X_STEP = 35; + + // Constructeur + public CanvasTop() { + } + + public void paint(Graphics g) { + Dimension d = getSize(); + + int w = (d.width - 36 - hand.size() * X_STEP) / 2; + for (int i = 0; i < hand.size(); i++) { + g.drawImage(CardImages.getInstance().getImage(hand.get(i)), w + X_STEP * i, 20, this); + } + + g.drawString(name, 30, 15); + if (atout) { + g.drawString("atout", name.length() * 7 + 60, 15); + } + } +} diff --git a/src/main/java/com/leflat/jass/client/CardImages.java b/src/main/java/com/leflat/jass/client/CardImages.java new file mode 100644 index 0000000..2290b84 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/CardImages.java @@ -0,0 +1,48 @@ +package com.leflat.jass.client; + +import com.leflat.jass.common.Card; + +import java.awt.*; + +public class CardImages { + public static final int IMG_WIDTH = 71; + public static final int IMG_HEIGHT = 96; + private static final String IMG_PATH = "pics/"; + private static final CardImages singleton = new CardImages(); + private Image[] images = new Image[36]; + private Image backImage; + private Image[] colorImages = new Image[4]; + + private CardImages() { + Toolkit tk = Toolkit.getDefaultToolkit(); + for (int i = 0; i < 36; i++) { + var imagePath = getClass().getClassLoader().getResource(IMG_PATH + i + ".png"); + images[i] = tk.getImage(imagePath); + } + var backImagePath = getClass().getClassLoader().getResource(IMG_PATH + "dos.png"); + backImage = tk.getImage(backImagePath); + for (int i = 0; i < 4; i++) { + var colorImagePath = getClass().getClassLoader().getResource(IMG_PATH + "c" + i + ".png"); + colorImages[i] = tk.getImage(colorImagePath); + } + } + + public static CardImages getInstance() { + return singleton; + } + + public Image getImage(Card card) { + if (!card.isBack()) { + return images[card.getNumber()]; + } + return backImage; + } + + public Image getBackImage() { + return backImage; + } + + public Image getColorImage(int color) { + return colorImages[color]; + } +} diff --git a/src/main/java/com/leflat/jass/client/ClientPlayer.java b/src/main/java/com/leflat/jass/client/ClientPlayer.java new file mode 100644 index 0000000..b8c72de --- /dev/null +++ b/src/main/java/com/leflat/jass/client/ClientPlayer.java @@ -0,0 +1,14 @@ +package com.leflat.jass.client; + +import com.leflat.jass.common.BasePlayer; + +public class ClientPlayer extends BasePlayer { + public ClientPlayer(int id, String name) { + super(id); + this.name = name; + } + + public ClientPlayer(int id) { + super(id); + } +} diff --git a/src/main/java/com/leflat/jass/client/DialogAtout.java b/src/main/java/com/leflat/jass/client/DialogAtout.java new file mode 100644 index 0000000..eca19a7 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/DialogAtout.java @@ -0,0 +1,119 @@ +/* + * DialogAtout.java + * + * Created on 19. avril 2000, 11:52 + */ + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + + +public class DialogAtout extends javax.swing.JDialog { + private boolean pass = false; + + /** + * Creates new form DialogAtout + */ + public DialogAtout(java.awt.Frame parent, boolean modal, boolean allowedToPass) { + super(parent, modal); + initComponents(); + pack(); + jButtonPass.setEnabled(allowedToPass); + jComboBoxAtout.addItem("Pique"); + jComboBoxAtout.addItem("Cœur"); + jComboBoxAtout.addItem("Carreau"); + jComboBoxAtout.addItem("Trèfle"); + } + + /** + * This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the FormEditor. + */ + private void initComponents() {//GEN-BEGIN:initComponents + jLabel1 = new javax.swing.JLabel(); + jComboBoxAtout = new javax.swing.JComboBox(); + jButtonOk = new javax.swing.JButton(); + jButtonPass = new javax.swing.JButton(); + getContentPane().setLayout(new AbsoluteLayout()); + setSize(300, 180); + setResizable(false); + setTitle("Choix de l'atout"); + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + closeDialog(evt); + } + } + ); + + jLabel1.setText("Veuillez choisir l'atout"); + + + getContentPane().add(jLabel1, new AbsoluteConstraints(20, 20, -1, -1)); + + + getContentPane().add(jComboBoxAtout, new AbsoluteConstraints(120, 60, -1, -1)); + + jButtonOk.setText("Ok"); + jButtonOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonOkActionPerformed(evt); + } + } + ); + + + getContentPane().add(jButtonOk, new AbsoluteConstraints(40, 110, -1, -1)); + + jButtonPass.setText("Passer"); + jButtonPass.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonPassActionPerformed(evt); + } + } + ); + + + getContentPane().add(jButtonPass, new AbsoluteConstraints(180, 110, -1, -1)); + + }//GEN-END:initComponents + + private void jButtonPassActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPassActionPerformed +// Add your handling code here: + pass = true; + this.dispose(); + }//GEN-LAST:event_jButtonPassActionPerformed + + private void jButtonOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOkActionPerformed +// Add your handling code here: + this.dispose(); + }//GEN-LAST:event_jButtonOkActionPerformed + + /** + * Closes the dialog + */ + private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + setVisible(false); + dispose(); + }//GEN-LAST:event_closeDialog + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + private javax.swing.JComboBox jComboBoxAtout; + private javax.swing.JButton jButtonOk; + private javax.swing.JButton jButtonPass; + // End of variables declaration//GEN-END:variables + + public int getSelectedColor() { + if (pass) { + return 4; + } + return jComboBoxAtout.getSelectedIndex(); + } +} diff --git a/client/DialogConnect.java b/src/main/java/com/leflat/jass/client/DialogConnect.java similarity index 84% rename from client/DialogConnect.java rename to src/main/java/com/leflat/jass/client/DialogConnect.java index 1fb7e86..aaf4f4b 100644 --- a/client/DialogConnect.java +++ b/src/main/java/com/leflat/jass/client/DialogConnect.java @@ -4,16 +4,19 @@ * Created on 18. avril 2000, 21:34 */ - - -/** +/* * * @author Berclaz Jérôme * @version */ + +package com.leflat.jass.client; + + public class DialogConnect extends javax.swing.JDialog { boolean ok = false; - String lastName, firstName, iP; + String name, host; + int gameId; /** Creates new form DialogConnect */ public DialogConnect(java.awt.Frame parent,boolean modal) { @@ -30,12 +33,12 @@ public DialogConnect(java.awt.Frame parent,boolean modal) { */ private void initComponents () {//GEN-BEGIN:initComponents jPanel1 = new javax.swing.JPanel (); - jLabelFirstName = new javax.swing.JLabel (); - jLabelLastName = new javax.swing.JLabel (); + jLabelName = new javax.swing.JLabel (); + jLabelGame = new javax.swing.JLabel (); jLabel3 = new javax.swing.JLabel (); - jTextFieldFirstName = new javax.swing.JTextField (); - jTextFieldLastName = new javax.swing.JTextField (); - jTextFieldIP = new javax.swing.JTextField (); + jTextFieldName = new javax.swing.JTextField (); + jTextFieldGame = new javax.swing.JTextField (); + jTextFieldHost = new javax.swing.JTextField (); jButtonOk = new javax.swing.JButton (); jButtonCancel = new javax.swing.JButton (); getContentPane ().setLayout (new java.awt.GridBagLayout ()); @@ -54,16 +57,16 @@ public void windowClosing (java.awt.event.WindowEvent evt) { jPanel1.setBorder (new javax.swing.border.TitledBorder("Paramètres de connexion")); jPanel1.setName (""); - jLabelFirstName.setText ("Nom"); + jLabelName.setText ("Nom"); gridBagConstraints2 = new java.awt.GridBagConstraints (); gridBagConstraints2.gridx = 0; gridBagConstraints2.gridy = 0; gridBagConstraints2.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints2.insets = new java.awt.Insets (14, 20, 0, 0); - jPanel1.add (jLabelFirstName, gridBagConstraints2); + jPanel1.add (jLabelName, gridBagConstraints2); - jLabelLastName.setText ("Prénom"); + jLabelGame.setText ("Jeu"); gridBagConstraints2 = new java.awt.GridBagConstraints (); gridBagConstraints2.gridx = 0; @@ -71,7 +74,7 @@ public void windowClosing (java.awt.event.WindowEvent evt) { gridBagConstraints2.gridwidth = 2; gridBagConstraints2.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints2.insets = new java.awt.Insets (10, 20, 0, 0); - jPanel1.add (jLabelLastName, gridBagConstraints2); + jPanel1.add (jLabelGame, gridBagConstraints2); jLabel3.setText ("Serveur"); @@ -83,6 +86,7 @@ public void windowClosing (java.awt.event.WindowEvent evt) { gridBagConstraints2.insets = new java.awt.Insets (10, 21, 0, 0); jPanel1.add (jLabel3, gridBagConstraints2); + jTextFieldName.setText("Joueur"); gridBagConstraints2 = new java.awt.GridBagConstraints (); gridBagConstraints2.gridx = 3; @@ -91,8 +95,7 @@ public void windowClosing (java.awt.event.WindowEvent evt) { gridBagConstraints2.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints2.ipadx = 146; gridBagConstraints2.insets = new java.awt.Insets (11, 61, 8, 0); - jPanel1.add (jTextFieldFirstName, gridBagConstraints2); - + jPanel1.add (jTextFieldName, gridBagConstraints2); gridBagConstraints2 = new java.awt.GridBagConstraints (); gridBagConstraints2.gridx = 3; @@ -101,9 +104,9 @@ public void windowClosing (java.awt.event.WindowEvent evt) { gridBagConstraints2.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints2.ipadx = 146; gridBagConstraints2.insets = new java.awt.Insets (9, 61, 8, 0); - jPanel1.add (jTextFieldLastName, gridBagConstraints2); + jPanel1.add (jTextFieldGame, gridBagConstraints2); - jTextFieldIP.setText ("localhost"); + jTextFieldHost.setText ("localhost"); gridBagConstraints2 = new java.awt.GridBagConstraints (); gridBagConstraints2.gridx = 3; @@ -112,7 +115,7 @@ public void windowClosing (java.awt.event.WindowEvent evt) { gridBagConstraints2.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints2.ipadx = 77; gridBagConstraints2.insets = new java.awt.Insets (9, 61, 8, 0); - jPanel1.add (jTextFieldIP, gridBagConstraints2); + jPanel1.add (jTextFieldHost, gridBagConstraints2); gridBagConstraints1 = new java.awt.GridBagConstraints (); @@ -167,9 +170,9 @@ private void jButtonCancelActionPerformed (java.awt.event.ActionEvent evt) {//GE private void jButtonOkActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOkActionPerformed // Add your handling code here: ok = true; - lastName = jTextFieldLastName.getText(); - firstName = jTextFieldFirstName.getText(); - iP = jTextFieldIP.getText(); + gameId = jTextFieldGame.getText().isEmpty() ? -1 : Integer.parseInt(jTextFieldGame.getText()); + name = jTextFieldName.getText(); + host = jTextFieldHost.getText(); this.dispose(); }//GEN-LAST:event_jButtonOkActionPerformed @@ -183,12 +186,12 @@ private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_clos // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel jPanel1; - private javax.swing.JLabel jLabelFirstName; - private javax.swing.JLabel jLabelLastName; + private javax.swing.JLabel jLabelName; + private javax.swing.JLabel jLabelGame; private javax.swing.JLabel jLabel3; - private javax.swing.JTextField jTextFieldFirstName; - private javax.swing.JTextField jTextFieldLastName; - private javax.swing.JTextField jTextFieldIP; + private javax.swing.JTextField jTextFieldName; + private javax.swing.JTextField jTextFieldGame; + private javax.swing.JTextField jTextFieldHost; private javax.swing.JButton jButtonOk; private javax.swing.JButton jButtonCancel; // End of variables declaration//GEN-END:variables diff --git a/client/DialogInfo.java b/src/main/java/com/leflat/jass/client/DialogInfo.java similarity index 97% rename from client/DialogInfo.java rename to src/main/java/com/leflat/jass/client/DialogInfo.java index ba9fed6..12040f4 100644 --- a/client/DialogInfo.java +++ b/src/main/java/com/leflat/jass/client/DialogInfo.java @@ -11,7 +11,10 @@ * @author Berclaz Jérôme * @version */ - import javax.swing.JLabel; + +package com.leflat.jass.client; + +import javax.swing.JLabel; public class DialogInfo extends javax.swing.JDialog { JLabel[] labelLine = new javax.swing.JLabel[5]; diff --git a/src/main/java/com/leflat/jass/client/DialogNewPart.java b/src/main/java/com/leflat/jass/client/DialogNewPart.java new file mode 100644 index 0000000..90bf446 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/DialogNewPart.java @@ -0,0 +1,101 @@ +/* + * DialogNewPart.java + * + * Created on 11. avril 2002, 22:17 + */ + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + +public class DialogNewPart extends javax.swing.JDialog { + private boolean newPart = false; + + /** Creates new form DialogNewPart */ + public DialogNewPart(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + pack(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the FormEditor. + */ + private void initComponents() {//GEN-BEGIN:initComponents + jLabel1 = new javax.swing.JLabel(); + jButtonYes = new javax.swing.JButton(); + jButtonNo = new javax.swing.JButton(); + + getContentPane().setLayout(new AbsoluteLayout()); + setSize(320, 180); + setResizable(false); + setTitle("Nouvelle partie"); + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + closeDialog(evt); + } + } + ); + + jLabel1.setText("Voulez vous faire une nouvelle partie?"); + + + getContentPane().add(jLabel1, new AbsoluteConstraints(30, 20, -1, -1)); + + jButtonYes.setText("Oui"); + jButtonYes.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonYesActionPerformed(evt); + } + } + ); + + + getContentPane().add(jButtonYes, new AbsoluteConstraints(40, 100, -1, -1)); + + jButtonNo.setText("Non"); + jButtonNo.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonNoActionPerformed(evt); + } + } + ); + + + getContentPane().add(jButtonNo, new AbsoluteConstraints(180, 100, -1, -1)); + + + }//GEN-END:initComponents + + private void jButtonNoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonManualActionPerformed +// Add your handling code here: + newPart = false; + this.dispose(); + }//GEN-LAST:event_jButtonManualActionPerformed + + private void jButtonYesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonHasardActionPerformed +// Add your handling code here: + newPart = true; + this.dispose(); + }//GEN-LAST:event_jButtonHasardActionPerformed + + /** Closes the dialog */ + private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + setVisible(false); + dispose(); + }//GEN-LAST:event_closeDialog + + public boolean getNewPart() { return newPart; } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + private javax.swing.JButton jButtonYes; + private javax.swing.JButton jButtonNo; + // End of variables declaration//GEN-END:variables + +} diff --git a/src/main/java/com/leflat/jass/client/DialogPartnerChoice.java b/src/main/java/com/leflat/jass/client/DialogPartnerChoice.java new file mode 100644 index 0000000..12aa34d --- /dev/null +++ b/src/main/java/com/leflat/jass/client/DialogPartnerChoice.java @@ -0,0 +1,93 @@ +/* + * DialogPartnerChoice.java + * + * Created on 19. avril 2000, 11:44 + */ + +/** + * @author Berclaz Jérôme + * @version + */ + +package com.leflat.jass.client; + + +import com.leflat.jass.common.BasePlayer; + +public class DialogPartnerChoice extends javax.swing.JDialog { + + /** + * Creates new form DialogPartnerChoice + */ + public DialogPartnerChoice(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + pack(); + } + + /** + * This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the FormEditor. + */ + private void initComponents() {//GEN-BEGIN:initComponents + jComboBoxPartner = new javax.swing.JComboBox(); + jButtonOk = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + getContentPane().setLayout(new AbsoluteLayout()); + setSize(300, 200); + setResizable(false); + setTitle("Choix du partenaire"); + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + closeDialog(evt); + } + } + ); + + getContentPane().add(jComboBoxPartner, new AbsoluteConstraints(100, 50, -1, -1)); + + jButtonOk.setText("Ok"); + jButtonOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonOkActionPerformed(evt); + } + } + ); + + getContentPane().add(jButtonOk, new AbsoluteConstraints(120, 120, -1, -1)); + + jLabel1.setText("Veuillez choisir votre partenaire"); + + + getContentPane().add(jLabel1, new AbsoluteConstraints(20, 20, -1, -1)); + + }//GEN-END:initComponents + + private void jButtonOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOkActionPerformed +// Add your handling code here: + this.dispose(); + }//GEN-LAST:event_jButtonOkActionPerformed + + /** + * Closes the dialog + */ + private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + setVisible(false); + dispose(); + }//GEN-LAST:event_closeDialog + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JComboBox jComboBoxPartner; + private javax.swing.JButton jButtonOk; + private javax.swing.JLabel jLabel1; + // End of variables declaration//GEN-END:variables + + public void addPlayer(BasePlayer player) { + jComboBoxPartner.addItem(player); + } + + public BasePlayer getSelectedPlayer() { return (BasePlayer) jComboBoxPartner.getSelectedItem(); } +} diff --git a/client/DialogTeamChoice.java b/src/main/java/com/leflat/jass/client/DialogTeamChoice.java similarity index 98% rename from client/DialogTeamChoice.java rename to src/main/java/com/leflat/jass/client/DialogTeamChoice.java index e6a4c0a..72424b4 100644 --- a/client/DialogTeamChoice.java +++ b/src/main/java/com/leflat/jass/client/DialogTeamChoice.java @@ -4,13 +4,15 @@ * Created on 19. avril 2000, 11:37 */ - - /** * * @author Berclaz Jérôme * @version */ + + +package com.leflat.jass.client; + public class DialogTeamChoice extends javax.swing.JDialog { boolean hasard = true; diff --git a/src/main/java/com/leflat/jass/client/JassCanvas.java b/src/main/java/com/leflat/jass/client/JassCanvas.java new file mode 100644 index 0000000..f07fc91 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/JassCanvas.java @@ -0,0 +1,69 @@ +package com.leflat.jass.client; + +import com.leflat.jass.common.Card; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public abstract class JassCanvas extends Canvas { + public static final int MODE_STATIC = 0; + public static final int MODE_PLAY = 1; + + protected int mode; // 0 : rien, 1 : jouer + protected String name = ""; + protected boolean atout = false; + protected List hand = new ArrayList<>(); + + protected JassCanvas() { + mode = MODE_STATIC; + } + + public void setMode(int mode) { + this.mode = mode; + } + + public void setAtout(boolean atout) { + this.atout = atout; + repaint(); + } + + public void setName(String name) { + this.name = name; + } + + public void setHand(List hand) { + clearHand(); + this.hand.addAll(hand); + repaint(); + } + + public void clearHand() { + hand.clear(); + } + + public void setBackCards(int number) { + clearHand(); + for (int i=0; i jButtonConnectActionPerformed()); + + getContentPane().add(jButtonConnect, new AbsoluteConstraints(410, 500, -1, -1)); + + }//GEN-END:initComponents + + private void jButtonConnectActionPerformed() { + //GEN-FIRST:event_jButtonConnectActionPerformed + if (!myself.isConnected()) { + var dc = new DialogConnect(this, true); + dc.setLocationRelativeTo(this); + dc.setVisible(true); + if (!dc.ok) { + return; + } + int gameId = myself.connect(dc.name, dc.host, dc.gameId); + if (gameId >= 0) { + jButtonConnect.setText("Déconnexion"); + setGameId(gameId); + } else { + // TODO: error message + } + } else { + // TODO: DISPLAY A CONFIRMATION MSG + if (myself.disconnect()) { + disconnect(); + } + } + }//GEN-LAST:event_jButtonConnectActionPerformed + + + private void jButtonAnounceActionPerformed(java.awt.event.ActionEvent evt) { +//GEN-FIRST:event_jButtonAnounceActionPerformed +// Add your handling code here: + anoucementPressed = true; + setAnouncementEnabled(false); + }//GEN-LAST:event_jButtonAnounceActionPerformed + + /** + * Exit the Application + */ + private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm + System.exit(0); + }//GEN-LAST:event_exitForm + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel rightPanel; + private javax.swing.JPanel leftPanel; + private javax.swing.JPanel playerPanel; + private javax.swing.JPanel topPanel; + private javax.swing.JPanel centerPanel; + private javax.swing.JPanel lastPliePanel; + private javax.swing.JPanel jPanel1; + private javax.swing.JLabel statusBar; + private javax.swing.JLabel infoBar; + private javax.swing.JButton jButtonAnounce; + private javax.swing.JButton jButtonConnect; + // End of variables declaration//GEN-END:variables + + + void playerCanvas_mouseClicked(MouseEvent e) { + playedCard = playerCanvas.getCard(e.getX(), e.getY()); + if (playedCard == null) { + return; + } + + int decision = Rules.canPlay(playedCard, currentPlie, playerCanvas.getHand(), atoutColor); + switch (decision) { + case Rules.RULES_MUST_FOLLOW: + playedCard = null; + statusBar.setText("Il faut suivre!"); + return; + case Rules.RULES_CANNOT_UNDERCUT: + playedCard = null; + statusBar.setText("Vous ne pouvez pas sous-couper!"); + return; + } + + jButtonAnounce.setEnabled(false); + setStatusBar(""); + centerCanvas.showCard(playedCard, 0); + playerCanvas.setMode(JassCanvas.MODE_STATIC); + playerCanvas.removeCard(playedCard); + assert threadToSignal != null; + synchronized (threadToSignal) { + threadToSignal.notify(); + } + } + + void centerCanvas_mouseClicked(MouseEvent e) { + System.out.println("Center click: " + e.getX() + " " + e.getY()); + drawnCardPosition = centerCanvas.getCard(e.getX(), e.getY()); + if (drawnCardPosition < 0) { + return; + } + centerCanvas.setMode(CanvasCenter.MODE_DRAW_TEAMS); // on ne peut plus choisir une carte + setStatusBar(""); // remove "veuillez tirer..." + assert threadToSignal != null; + synchronized (threadToSignal) { + threadToSignal.notify(); + } + } + + //Fait un repaint des différents canvas + public void repaint(int nbr) { + if ((nbr & 1) == 1) + playerCanvas.repaint(); + if ((nbr & 2) == 2) + leftCanvas.repaint(); + if ((nbr & 4) == 4) + topCanvas.repaint(); + if ((nbr & 8) == 8) + rightCanvas.repaint(); + if ((nbr & 16) == 16) + centerCanvas.repaint(); + } + + public void disconnect() { + for (int i = 0; i < 4; i++) { + var canvas = getPlayerCanvas(i); + canvas.clearHand(); + canvas.setName(""); + canvas.setAtout(false); + canvas.setMode(JassCanvas.MODE_STATIC); + } + centerCanvas.resetCards(); + centerCanvas.setMode(CanvasCenter.MODE_PASSIVE); + removeLastPlie(); + lastPlieCanvas.hideAtout(); + setScore(0, 0); + + statusBar.setText("Déconnexion"); + jButtonConnect.setText("Connexion"); + } + + // attribue ses cartes aux joueur + public void setPlayerHand(List hand) { + playerCanvas.setHand(hand); + } + + @Override + public int chooseAtout(boolean allowedToPass) { + DialogAtout da = new DialogAtout(this, true, allowedToPass); + da.setLocationRelativeTo(this); + da.setVisible(true); + return da.getSelectedColor(); + } + + @Override + public void setAtout(int atout, int positionOfPlayerToChooseAtout) { + atoutColor = atout; + lastPlieCanvas.setAtout(atout); + for (int i = 0; i < 4; i++) { + var canvas = getPlayerCanvas(i); + canvas.setAtout(i == positionOfPlayerToChooseAtout); + } + } + + @Override + public void play(Plie currentPlie, Thread threadToSignal) { + this.currentPlie = currentPlie; + this.threadToSignal = threadToSignal; + setStatusBar("A vous de jouer ..."); + anoucementPressed = false; + setAnouncementEnabled(true); + playerCanvas.setMode(JassCanvas.MODE_PLAY); + } + + @Override + public Card getPlayedCard() { + return playedCard; + } + + @Override + public void setPlayedCard(Card card, int playerPosition) { + var canvas = getPlayerCanvas(playerPosition); + canvas.removeCard(); + centerCanvas.showCard(card, playerPosition); + } + + @Override + public void setOtherPlayersHands(int numberOfCards) { + var hand = new ArrayList(); + for (int i = 0; i < numberOfCards; i++) { + hand.add(new Card(Card.BACK_NUMBER)); + } + leftCanvas.setHand(hand); + topCanvas.setHand(hand); + rightCanvas.setHand(hand); + } + + // prépare l'écran pour une nouvelle partie + @Override + public void prepareGame() { + centerCanvas.resetCards(); + centerCanvas.setMode(CanvasCenter.MODE_GAME); // mode de jeu + lastPlieCanvas.hideAtout(); + setStatusBar(""); + removeLastPlie(); + } + + // ramasse la plie + @Override + public void setPlieOwner(int playerPosition) { + if (playerPosition == 0) { + setStatusBar("Vous avez pris la plie"); + } else { + statusBar.setText(getPlayerCanvas(playerPosition).getName() + " a pris la plie"); + } + lastPlieCanvas.setLastPlie(centerCanvas.getShownCards()); + centerCanvas.resetCards(); + } + + void removeLastPlie() { + lastPlieCanvas.setLastPlie(Collections.emptyList()); + } + + public void setScore(int ourScore, int opponentScore) { + lastPlieCanvas.setScores(ourScore, opponentScore); + } + + @Override + public boolean hasPlayerAnounced() { + return anoucementPressed; + } + + @Override + public void displayStatusMessage(String message) { + setStatusBar(message); + } + + @Override + public void displayGameResult(Team winningTeam) { + centerCanvas.setMode(CanvasCenter.MODE_PASSIVE); + playerCanvas.setMode(JassCanvas.MODE_STATIC); + DialogInfo diw = new DialogInfo(this, false); + diw.setLocationRelativeTo(this); + diw.setText(0, "L'équipe de"); + diw.setText(1, winningTeam.getPlayer(0).getName() + " & " + winningTeam.getPlayer(1).getName()); + diw.setText(2, "a gagné la partie!"); + setStatusBar("Partie terminée"); + diw.setVisible(true); + } + + @Override + public boolean getNewGame() { + DialogNewPart dnp = new DialogNewPart(this, true); + dnp.setLocationRelativeTo(this); + dnp.setVisible(true); + return dnp.getNewPart(); + } + + @Override + public void canceledGame(int leavingPlayerPosition) { + var di = new DialogInfo(this, false); + di.setLocationRelativeTo(this); + var canvas = getPlayerCanvas(leavingPlayerPosition); + di.setText(0, canvas.getName() + " a quitté le jeu."); + di.setText(1, "La partie est interrompue."); + setStatusBar("Partie interrompue"); + disconnect(); + di.setVisible(true); + } + + void setStatusBar(String text) { + statusBar.setText(text); + } + + void setAnouncementEnabled(boolean b) { + jButtonAnounce.setEnabled(b); + } + + void setGameId(int gameId) { + String title = APP_TITLE + " - Jeu " + gameId; + setTitle(title); + } + + @Override + public void setPlayer(BasePlayer player, int relativePosition) { + JassCanvas canvas = getPlayerCanvas(relativePosition); + canvas.setName(player.getName()); + canvas.repaint(); + } + + @Override + public void showUi(boolean enable) { + setLocationRelativeTo(null); + setVisible(enable); + } + + @Override + public TeamSelectionMethod chooseTeamSelectionMethod() { + DialogTeamChoice dtc = new DialogTeamChoice(this, true); + dtc.setLocationRelativeTo(this); + dtc.setVisible(true); + return dtc.hasard ? TeamSelectionMethod.RANDOM : TeamSelectionMethod.MANUAL; + } + + @Override + public void prepareTeamDrawing(boolean firstAttempt) { + System.out.println("frame: prepare team drawing"); + playerCanvas.clearHand(); + leftCanvas.clearHand(); + rightCanvas.clearHand(); + topCanvas.clearHand(); + centerCanvas.resetCards(); + centerCanvas.setMode(CanvasCenter.MODE_DRAW_TEAMS); + removeLastPlie(); + lastPlieCanvas.setAtout(4); + setScore(0, 0); + repaint(31); + } + + @Override + public void drawCard(Thread thread) { + centerCanvas.setMode(CanvasCenter.MODE_PICK_CARD); + setStatusBar("Veuillez choisir une carte"); + this.threadToSignal = thread; + } + + @Override + public int getDrawnCardPosition() { + return drawnCardPosition; + } + + @Override + public void setDrawnCard(int playerPosition, int cardPosition, Card card) { + centerCanvas.drawCard(cardPosition); + var canvas = getPlayerCanvas(playerPosition); + canvas.setHand(Collections.singletonList(card)); + } + + @Override + public BasePlayer choosePartner(List partners) { + DialogPartnerChoice dpc = new DialogPartnerChoice(this, true); + dpc.setLocationRelativeTo(this); + partners.forEach(dpc::addPlayer); + dpc.setVisible(true); + return dpc.getSelectedPlayer(); + } + + private JassCanvas getPlayerCanvas(int relativePosition) { + switch (relativePosition) { + case 0: + return playerCanvas; + case 1: + return rightCanvas; + case 2: + return topCanvas; + case 3: + return leftCanvas; + default: + throw new IndexOutOfBoundsException("Unknown canvas " + relativePosition); + } + } +} diff --git a/src/main/java/com/leflat/jass/client/JassPlayer.java b/src/main/java/com/leflat/jass/client/JassPlayer.java new file mode 100644 index 0000000..84e5194 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/JassPlayer.java @@ -0,0 +1,223 @@ +/* + * Created for and by the FLAT(r) + */ +package com.leflat.jass.client; + +import com.leflat.jass.common.*; + +import java.util.*; +import java.util.stream.Collectors; + +public class JassPlayer implements IPlayer, IRemotePlayer { + private RemoteController controller; + private IJassUi frame; + private int id; + private Map playersPositions = new HashMap<>(); + private Map players = new HashMap<>(); + private List playerHand = new ArrayList<>(); + + + public JassPlayer() { + controller = new RemoteController(this); + frame = new JassFrame(this); + frame.showUi(true); + + // TODO: remove (DEBUG) + Random rnd = new Random(); + connect(String.valueOf(rnd.nextInt(100)), "localhost", 0); + } + + @Override + public void setPlayerInfo(BasePlayer player) { + try { + var relativePosition = getInitialRelativePosition(player); + playersPositions.put(player.getId(), relativePosition); + players.put(player.getId(), player); + frame.setPlayer(player, relativePosition); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public TeamSelectionMethod chooseTeamSelectionMethod() { + return frame.chooseTeamSelectionMethod(); + } + + @Override + public void prepareTeamDrawing(boolean firstAttempt) { + frame.prepareTeamDrawing(firstAttempt); + } + + @Override + public int drawCard() { + synchronized (controller) { + frame.drawCard(controller); + try { + controller.wait(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return frame.getDrawnCardPosition(); + } + + @Override + public void setCard(BasePlayer player, int cardPosition, Card card) { + try { + var relativePosition = playersPositions.get(player.getId()); + frame.setDrawnCard(relativePosition, cardPosition, card); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } + } + + @Override + public void setPlayersOrder(List playerIds) { + int ownPosition = playerIds.indexOf(id); + playersPositions.clear(); + for (int i = 0; i < playerIds.size(); i++) { + int playerId = playerIds.get(i); + playersPositions.put(playerId, (i - ownPosition + 4) % 4); + } + for (var player : players.values()) { + try { + frame.setPlayer(player, playersPositions.get(player.getId())); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public int choosePartner() { + var partners = players.values().stream().filter(p -> p.getId() != id).collect(Collectors.toList()); + return frame.choosePartner(partners).getId(); + } + + @Override + public void setHand(List cards) { + playerHand.clear(); + Card.sort(cards); + playerHand.addAll(cards); + frame.prepareGame(); + frame.setPlayerHand(cards); + frame.setOtherPlayersHands(9); + } + + @Override + public int chooseAtout(boolean first) { + return frame.chooseAtout(first); + } + + @Override + public void setAtout(int color, BasePlayer firstToPlay) { + frame.setAtout(color, playersPositions.get(firstToPlay.getId())); + } + + @Override + public Card play(int currentColor, int highestRank, boolean cut) { + synchronized (controller) { + frame.play(new Plie(currentColor, highestRank, cut), controller); + try { + controller.wait(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return frame.getPlayedCard(); + } + + @Override + public void setPlayedCard(BasePlayer player, Card card) { + frame.setPlayedCard(card, playersPositions.get(player.getId())); + } + + @Override + public void setPlieOwner(BasePlayer player) { + frame.setPlieOwner(playersPositions.get(player.getId())); + } + + @Override + public void setScores(int score, int opponentScore) { + frame.setScore(score, opponentScore); + } + + @Override + public List getAnoucement() { + if (!frame.hasPlayerAnounced()) { + return Collections.emptyList(); + } + // TODO: handle stoeck properly (only communicated when playing the second card) + return Anouncement.findAnouncements(playerHand); + } + + @Override + public void setAnouncement(BasePlayer player, List anouncements) { + StringBuilder sb; + if (player.getId() == id) { + sb = new StringBuilder("Vous annoncez "); + } else { + sb = new StringBuilder(players.get(player.getId()).getName()).append(" annonce "); + } + sb.append(anouncements.get(0)); + for (int i = 1; i < anouncements.size(); i++) { + sb.append(" et ").append(anouncements.get(i)); + } + frame.displayStatusMessage(sb.toString()); + } + + @Override + public void setGameResult(Team winningTeam) { + var p0 = winningTeam.getPlayer(0); + p0.setName(players.get(p0.getId()).getName()); + var p1 = winningTeam.getPlayer(1); + p1.setName(players.get(p1.getId()).getName()); + frame.displayGameResult(winningTeam); + } + + @Override + public boolean getNewGame() { + return frame.getNewGame(); + } + + @Override + public void playerLeft(BasePlayer player) { + frame.canceledGame(playersPositions.get(player.getId())); + controller.disconnect(); + } + + @Override + public int connect(String name, String host, int gameId) { + var connectionInfo = controller.connect(host, gameId, name); + if (connectionInfo.error != ConnectionError.CONNECTION_SUCCESSFUL) { + return connectionInfo.error; + } + id = connectionInfo.playerId; + playersPositions.put(id, 0); + controller.start(); + try { + frame.setPlayer(new ClientPlayer(id, name), 0); + } catch (Exception e) { + e.printStackTrace(); + } + return connectionInfo.gameId; + } + + @Override + public boolean disconnect() { + controller.disconnect(); + return true; + } + + @Override + public boolean isConnected() { + return controller.isConnected(); + } + + private int getInitialRelativePosition(BasePlayer player) { + return (player.getId() - id + 4) % 4; + } +} diff --git a/src/main/java/com/leflat/jass/client/RemoteController.java b/src/main/java/com/leflat/jass/client/RemoteController.java new file mode 100644 index 0000000..7af44a8 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/RemoteController.java @@ -0,0 +1,341 @@ +package com.leflat.jass.client; + +import com.leflat.jass.common.*; +import com.leflat.jass.server.PlayerLeftExpection; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class RemoteController extends Thread { + private static final int PORT_NUM = 23107; + private static final int CONNECTION_TIMEOUT_MS = 10000; + private boolean running = false; + private int playerId; + private IPlayer player; + private Socket clientSocket = new Socket(); + private PrintWriter os; + private BufferedReader is; + + public RemoteController(IPlayer player) { + this.player = player; + } + + public ClientConnectionInfo connect(String host, int requestedGameId, String name) { + try { + clientSocket.connect(new InetSocketAddress(host, PORT_NUM), CONNECTION_TIMEOUT_MS); + + os = new PrintWriter(clientSocket.getOutputStream(), false); + is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + System.out.println("Connection successful"); + } catch (SocketTimeoutException e) { + System.out.println("Server does not answer"); + return new ClientConnectionInfo(ConnectionError.SERVER_UNREACHABLE); + } catch (IOException e) { + System.out.println("Unable to create socket: " + e); + return new ClientConnectionInfo(ConnectionError.SERVER_UNREACHABLE); + } + + sendRawMessage(String.valueOf(requestedGameId)); + + try { + int receivedGameId = Integer.parseInt(receiveRawMessage()); + if (receivedGameId < 0) { + return new ClientConnectionInfo(receivedGameId); + } + playerId = Integer.parseInt(receiveRawMessage()); + sendMessage(Collections.singletonList(name)); + return new ClientConnectionInfo(playerId, receivedGameId, ConnectionError.CONNECTION_SUCCESSFUL); + } catch (ServerDisconnectedException e) { + e.printStackTrace(); + } + return new ClientConnectionInfo(ConnectionError.SERVER_UNREACHABLE); + } + + public boolean isConnected() { + return clientSocket != null && !clientSocket.isClosed(); + } + + public void sendRawMessage(String message) { + os.println(message); + os.flush(); + System.out.println("Envoi au serveur : " + message); + } + + public void sendMessage(List message) { + String stringMessage = playerId + " " + String.join(" ", message); + sendRawMessage(stringMessage); + } + + public String receiveRawMessage() throws ServerDisconnectedException { + String message = null; + + // TODO: implementer timeout + exc + try { + message = is.readLine(); + } catch (IOException e) { + System.out.println("Error during reception"); + } + if (message != null) + System.out.println("Received : " + message); + else { + System.out.println("Server has left unexpectedly"); + throw new ServerDisconnectedException(); + } + return message; + } + + public void disconnect() { + try { + running = false; + clientSocket.close(); + } catch (IOException e) { + System.out.println("Error while closing socket"); + //System.exit(1); + } + } + + @Override + public void run() { + running = true; + System.out.println("Starting Listener..."); + while (running) { + try { + String message = receiveRawMessage(); + handleControllerMessage(message.split(" ")); + } catch (ServerDisconnectedException e) { + e.printStackTrace(); + running = false; + // TODO: player.serverDisconnected + } + } + System.out.println("Exiting listener"); + } + + private void handleControllerMessage(String[] message) { + int command = Integer.parseInt(message[0]); + List answer = new ArrayList<>(); + switch (command) { + case RemoteCommand.SET_PLAYER_INFO: + int playerId = Integer.parseInt(message[1]); + String name = message[2]; + try { + player.setPlayerInfo(new ClientPlayer(playerId, name)); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.CHOOSE_TEAM_SELECTION_METHOD: + try { + var choice = player.chooseTeamSelectionMethod(); + answer = Collections.singletonList(String.valueOf(choice)); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.PREPARE_TEAM_DRAWING: + try { + player.prepareTeamDrawing(true); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.DRAW_CARD: + try { + int position = player.drawCard(); + answer = Collections.singletonList(String.valueOf(position)); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_CARD: + int pId = Integer.parseInt(message[1]); + int cardPosition = Integer.parseInt(message[2]); + int cardNumber = Integer.parseInt(message[3]); + try { + player.setCard(new ClientPlayer(pId), cardPosition, new Card(cardNumber)); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.RESTART_TEAM_DRAWING: + try { + player.prepareTeamDrawing(false); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.CHOOSE_PARTNER: + try { + int partnerId = player.choosePartner(); + answer = Collections.singletonList(String.valueOf(partnerId)); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_PLAYERS_ORDER: + var order = Arrays.stream(message).skip(1).map(Integer::parseInt).collect(Collectors.toList()); + try { + player.setPlayersOrder(order); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_HAND: + var hand = Arrays.stream(message).skip(1).map(Integer::parseInt).map(Card::new).collect(Collectors.toList()); + try { + player.setHand(hand); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.CHOOSE_ATOUT: + case RemoteCommand.CHOOSE_ATOUT_SECOND: + try { + int atout = player.chooseAtout(command == RemoteCommand.CHOOSE_ATOUT); + answer = Collections.singletonList(String.valueOf(atout)); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_ATOUT: + try { + int atout = Integer.parseInt(message[1]); + var firstToPlay = new ClientPlayer(Integer.parseInt(message[2])); + player.setAtout(atout, firstToPlay); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.PLAY: + try { + var card = player.play(-1, -1, false); + answer = Collections.singletonList(String.valueOf(card.getNumber())); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_PLAYED_CARD: + try { + var p = new ClientPlayer(Integer.parseInt(message[1])); + var card = new Card(Integer.parseInt(message[2])); + player.setPlayedCard(p, card); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.PLAY_NEXT: + try { + int highestRank = Integer.parseInt(message[1]); + int currentColor = Integer.parseInt(message[2]); + boolean cut = message[3].equals("1"); + var playedCard = player.play(currentColor, highestRank, cut); + answer = Collections.singletonList(String.valueOf(playedCard.getNumber())); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_PLIE_OWNER: + try { + var pl = new ClientPlayer(Integer.parseInt(message[1])); + player.setPlieOwner(pl); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_SCORES: + try { + int ourScore = Integer.parseInt(message[1]); + int opponentScore = Integer.parseInt(message[2]); + player.setScores(ourScore, opponentScore); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + case RemoteCommand.GET_ANOUNCEMENTS: + try { + var anouncements = player.getAnoucement(); + answer.add(String.valueOf(anouncements.size())); + for (var an : anouncements) { + answer.add(String.valueOf(an.getType())); + answer.add(String.valueOf(an.getCard().getNumber())); + } + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_ANOUNCEMENTS: + try { + var p = new ClientPlayer(Integer.parseInt(message[1])); + int numberAnoucements = Integer.parseInt(message[2]); + List anouncements = new ArrayList<>(); + for (int i = 0; i < numberAnoucements; i++) { + var c = new Card(Integer.parseInt(message[4 + i * 2])); + anouncements.add(new Anouncement(Integer.parseInt(message[3 + i * 2]), c)); + } + player.setAnouncement(p, anouncements); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.SET_GAME_RESULT: + try { + var winningTeam = new Team(Integer.parseInt(message[1])); + winningTeam.addPlayer(new ClientPlayer(Integer.parseInt(message[2]))); + winningTeam.addPlayer(new ClientPlayer(Integer.parseInt(message[3]))); + player.setGameResult(winningTeam); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.GET_NEW_GAME: + try { + boolean newGame = player.getNewGame(); + answer = Collections.singletonList(newGame ? "1" : "0"); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + case RemoteCommand.PLAYER_LEFT: + try { + var p = new ClientPlayer(Integer.parseInt(message[1])); + player.playerLeft(p); + } catch (PlayerLeftExpection playerLeftExpection) { + playerLeftExpection.printStackTrace(); + return; + } + break; + default: + System.err.println("Unknown command " + command); + } + sendMessage(answer); + } +} diff --git a/src/main/java/com/leflat/jass/client/ServerDisconnectedException.java b/src/main/java/com/leflat/jass/client/ServerDisconnectedException.java new file mode 100644 index 0000000..2c59837 --- /dev/null +++ b/src/main/java/com/leflat/jass/client/ServerDisconnectedException.java @@ -0,0 +1,4 @@ +package com.leflat.jass.client; + +public class ServerDisconnectedException extends Exception { +} diff --git a/src/main/java/com/leflat/jass/common/Anouncement.java b/src/main/java/com/leflat/jass/common/Anouncement.java new file mode 100644 index 0000000..c441c0c --- /dev/null +++ b/src/main/java/com/leflat/jass/common/Anouncement.java @@ -0,0 +1,129 @@ +package com.leflat.jass.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class Anouncement { + public static final int STOECK = 0; + public static final int THREE_CARDS = 1; + public static final int FIFTY = 2; + public static final int HUNDRED = 3; + public static final int SQUARE = 4; + public static final int NELL_SQUARE = 5; + public static final int BOURG_SQUARE = 6; + + public static final int[] VALUES = {20, 20, 50, 100, 100, 150, 200}; + public static final String[] NAMES = {"stoeck", "3 cartes", "cinquante", "cent", "cent", "cent cinquante", "deux cents"}; + + public Anouncement(int type, Card card) { + this.type = type; + this.card = card; + } + + private int type; // 0: stöck, 1: 3 cartes, 2: cinquante, 3: cent, 4: carré + private Card card; // plus haute carte de l'annonce + + public int getType() { + return type; + } + + public Card getCard() { + return card; + } + + public int getValue() { + if (type == SQUARE) { + switch (card.getRank()) { + case Card.RANK_BOURG: + return 200; + case Card.RANK_NELL: + return 150; + default: + return 100; + } + } + return VALUES[type]; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(NAMES[type]); + if (type == STOECK) { + return sb.toString(); + } + if (type >= SQUARE) { + sb.append(" des ").append(Card.RANK_NAMES[card.getRank()]).append("s"); + } else { + switch (card.getRank()) { + case Card.RANK_DAME: + sb.append(" à la "); + break; + case Card.RANK_AS: + sb.append(" à l'"); + break; + default: + sb.append(" au "); + break; + } + sb.append(card.toString()); + } + return sb.toString(); + } + + public static List findAnouncements(List hand) { + var announcements = findSquares(hand); + announcements.addAll(findSuits(hand)); + return new ArrayList<>(announcements); + } + + public static boolean findStoeck(List hand, int atout) { + int queen = atout * 9 + Card.RANK_DAME; + int king = atout * 9 + Card.RANK_ROI; + var numbers = hand.stream().map(Card::getNumber).collect(Collectors.toList()); + return numbers.contains(queen) && numbers.contains(king); + } + + private static Collection findSquares(List hand) { + int[] rankCount = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + hand.forEach(c -> rankCount[c.getRank()]++); + var announcements = new ArrayList(); + for (int rank = Card.RANK_NELL; rank <= Card.RANK_AS; rank++) { + if (rankCount[rank] == 4) { + int type = SQUARE; + if (rank == Card.RANK_NELL) { + type = NELL_SQUARE; + } else if (rank == Card.RANK_BOURG) { + type = BOURG_SQUARE; + } + announcements.add(new Anouncement(type, new Card(rank, Card.COLOR_SPADE))); + } + } + return announcements; + } + + private static Collection findSuits(List hand) { + var announcements = new ArrayList(); + for (int i = 0; i < hand.size() - 2; i++) { + var firstCard = hand.get(i); + int color = firstCard.getColor(); + int j = i + 1; + int nbrCards = 1; + while ((j < hand.size()) && (hand.get(j).getColor() == color)) { + if (hand.get(j).getNumber() == (firstCard.getNumber() + j - i)) // si les cartes se suivent + nbrCards++; + j++; + } + if (nbrCards > 2) { // on a trouvé une suite + if (nbrCards > 5) { + nbrCards = 5; + } + announcements.add(new Anouncement(nbrCards - 2, hand.get(i + nbrCards - 1))); + System.out.println("Found suit: " + announcements.get(announcements.size() - 1)); + i = j - 1; + } + } + return announcements; + } +} diff --git a/src/main/java/com/leflat/jass/common/BasePlayer.java b/src/main/java/com/leflat/jass/common/BasePlayer.java new file mode 100644 index 0000000..5a55d53 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/BasePlayer.java @@ -0,0 +1,50 @@ +package com.leflat.jass.common; + +import java.util.ArrayList; +import java.util.List; + +public abstract class BasePlayer { + // Variables + protected String name; + protected int id; + protected Team team; + protected List anoucements = new ArrayList<>(); // annonces + + // Constructeur + public BasePlayer(int id) { + this.id = id; + } + + // Méthodes + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { this.name = name; } + + public Team getTeam() { + return team; + } + + public void setTeam(Team team) { + this.team = team; + } + + public void addAnouncement(Anouncement a) { + anoucements.add(a); + } + + public List getAnouncements() { + return anoucements; + } + + public void clearAnouncement() { + anoucements.clear(); + } + + public String toString() { return name; } +} diff --git a/src/main/java/com/leflat/jass/common/BrokenRuleException.java b/src/main/java/com/leflat/jass/common/BrokenRuleException.java new file mode 100644 index 0000000..6abdf62 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/BrokenRuleException.java @@ -0,0 +1,11 @@ +package com.leflat.jass.common; + +public class BrokenRuleException extends Exception { + int brokenRule; + + public BrokenRuleException(int brokenRule) { + this.brokenRule = brokenRule; + } + + public int getBrokenRule() { return brokenRule; } +} diff --git a/src/main/java/com/leflat/jass/common/Card.java b/src/main/java/com/leflat/jass/common/Card.java new file mode 100644 index 0000000..e763693 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/Card.java @@ -0,0 +1,124 @@ +package com.leflat.jass.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +/** + * ************************** REMARQUE ****************************** + * Les cartes sont en fait représentées par des int de 0 à 35 + * où "carte div 9" donne sa couleur et "carte mod 9" sa + * hauteur. La classe Card est donc utilisée ici que pour + * les méthodes statiques getColor et getHeight. + * *************************************************************** + */ + +public class Card { + public static final int DIAMOND_SEVEN = 19; + public static final int RANK_6 = 0; + public static final int RANK_7 = 1; + public static final int RANK_8 = 2; + public static final int RANK_NELL = 3; + public static final int RANK_10 = 4; + public static final int RANK_BOURG = 5; + public static final int RANK_DAME = 6; + public static final int RANK_ROI = 7; + public static final int RANK_AS = 8; + + public static final int COLOR_SPADE = 0; + public static final int COLOR_HEART = 1; + public static final int COLOR_DIAMOND = 2; + public static final int COLOR_CLUB = 3; + + public static final String[] RANK_NAMES = {"six", "sept", "huit", "nell", "dix", "bourg", "dame", "roi", "as"}; + public static final String[] COLOR_NAMES = {"pique", "coeur", "carreau", "trèfle"}; + + public static final int[] VALUES = {0, 0, 0, 0, 10, 2, 3, 4, 11}; + public static final int[] VALUES_ATOUT = {0, 0, 0, 14, 10, 20, 3, 4, 11}; + + public static final int BACK_NUMBER = 200; + private static final Card backCard = new Card(BACK_NUMBER); + + private int number; + + public Card(int cardNumber) { + number = cardNumber; + } + + public Card(int rank, int color) { + number = color * 9 + rank; + } + + public int getColor() { + return number / 9; + } + + public int getRank() { + return number % 9; + } + + public int getNumber() { + return number; + } + + public String toString() { + return RANK_NAMES[getRank()] + " de " + COLOR_NAMES[getColor()]; + } + + public int getValue() { + return getValue(-1); + } + + public int getValue(int atout) { + return atout == getColor() ? VALUES_ATOUT[getRank()] : VALUES[getRank()]; + } + + public boolean isBack() { + return number == BACK_NUMBER; + } + + public static Card getBack() { + return backCard; + } + + public static void sort(List cards) { + quickSortCards(cards, 0, cards.size() - 1); + } + + private static void quickSortCards(List cards, int min, int max) { + int i = min; + int j = max; + int x = cards.get((min + max) / 2).getNumber(); + do { + while (cards.get(i).getNumber() < x) + i++; + while (x < cards.get(j).getNumber()) + j--; + if (i <= j) { + Collections.swap(cards, i, j); + i++; + j--; + } + } while (i <= j); + if (min < j) + quickSortCards(cards, min, j); + if (i < max) + quickSortCards(cards, i, max); + } + + public static List shuffle(int number) { + List cards = new ArrayList<>(); + for (int i = 0; i < number; i++) { + cards.add(new Card(i)); + } + Random rand = new Random(); + for (int i = 35; i > 0; i--) { + int j = rand.nextInt(i + 1); + if (i != j) { + Collections.swap(cards, j, i); + } + } + return cards; + } +} diff --git a/src/main/java/com/leflat/jass/common/ClientConnectionInfo.java b/src/main/java/com/leflat/jass/common/ClientConnectionInfo.java new file mode 100644 index 0000000..9b18d5d --- /dev/null +++ b/src/main/java/com/leflat/jass/common/ClientConnectionInfo.java @@ -0,0 +1,19 @@ +package com.leflat.jass.common; + +public class ClientConnectionInfo { + public int playerId; + public int gameId; + public int error; + + public ClientConnectionInfo(int playerId, int gameId, int error) { + this.playerId = playerId; + this.gameId = gameId; + this.error = error; + } + + public ClientConnectionInfo(int error) { + this.error = error; + this.gameId = -1; + this.playerId = -1; + } +} diff --git a/src/main/java/com/leflat/jass/common/ConnectionError.java b/src/main/java/com/leflat/jass/common/ConnectionError.java new file mode 100644 index 0000000..4228dfa --- /dev/null +++ b/src/main/java/com/leflat/jass/common/ConnectionError.java @@ -0,0 +1,8 @@ +package com.leflat.jass.common; + +public abstract class ConnectionError { + public static final int CONNECTION_SUCCESSFUL = 0; + public static final int UNKNOWN_GAME = -1; + public static final int GAME_FULL = -2; + public static final int SERVER_UNREACHABLE = -3; +} diff --git a/src/main/java/com/leflat/jass/common/IJassUi.java b/src/main/java/com/leflat/jass/common/IJassUi.java new file mode 100644 index 0000000..488cef3 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/IJassUi.java @@ -0,0 +1,51 @@ +package com.leflat.jass.common; + +import java.util.List; + +public interface IJassUi { + void setPlayer(BasePlayer player, int relativePosition) throws Exception; + + void showUi(boolean enable); + + TeamSelectionMethod chooseTeamSelectionMethod(); + + void prepareTeamDrawing(boolean firstAttempt); + + void drawCard(Thread thread); + + int getDrawnCardPosition(); + + void setDrawnCard(int playerPosition, int cardPosition, Card card) throws IndexOutOfBoundsException; + + BasePlayer choosePartner(List players); + + void setPlayerHand(List hand); + + int chooseAtout(boolean allowedToPass); + + void setAtout(int atout, int positionOfPlayerToChooseAtout); + + void play(Plie currentPlie, Thread threadToSignal); + + Card getPlayedCard(); + + void setPlayedCard(Card card, int playerPosition); + + void setOtherPlayersHands(int numberOfCards); + + void prepareGame(); + + void setPlieOwner(int playerPosition); + + void setScore(int ourScore, int opponentScore); + + boolean hasPlayerAnounced(); + + void displayStatusMessage(String message); + + void displayGameResult(Team winningTeam); + + boolean getNewGame(); + + void canceledGame(int leavingPlayerPosition); +} diff --git a/src/main/java/com/leflat/jass/common/IPlayer.java b/src/main/java/com/leflat/jass/common/IPlayer.java new file mode 100644 index 0000000..5be8e07 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/IPlayer.java @@ -0,0 +1,45 @@ +package com.leflat.jass.common; + +import com.leflat.jass.server.PlayerLeftExpection; + +import java.util.List; + +public interface IPlayer { + void setPlayerInfo(BasePlayer player) throws PlayerLeftExpection; + + TeamSelectionMethod chooseTeamSelectionMethod() throws PlayerLeftExpection; + + void prepareTeamDrawing(boolean firstAttempt) throws PlayerLeftExpection; + + int drawCard() throws PlayerLeftExpection; + + void setCard(BasePlayer player, int cardPosition, Card card) throws PlayerLeftExpection; + + void setPlayersOrder(List playerIds) throws PlayerLeftExpection; + + int choosePartner() throws PlayerLeftExpection; + + void setHand(List cards) throws PlayerLeftExpection; + + int chooseAtout(boolean first) throws PlayerLeftExpection; + + void setAtout(int color, BasePlayer firstToPlay) throws PlayerLeftExpection; + + Card play(int currentColor, int highestRank, boolean cut) throws PlayerLeftExpection; + + void setPlayedCard(BasePlayer player, Card card) throws PlayerLeftExpection; + + void setPlieOwner(BasePlayer player) throws PlayerLeftExpection; + + void setScores(int score, int opponentScore) throws PlayerLeftExpection; + + List getAnoucement() throws PlayerLeftExpection; + + void setAnouncement(BasePlayer player, List anouncements) throws PlayerLeftExpection; + + void setGameResult(Team winningTeam) throws PlayerLeftExpection; + + boolean getNewGame() throws PlayerLeftExpection; + + void playerLeft(BasePlayer player) throws PlayerLeftExpection; +} diff --git a/src/main/java/com/leflat/jass/common/IRemotePlayer.java b/src/main/java/com/leflat/jass/common/IRemotePlayer.java new file mode 100644 index 0000000..3ca9513 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/IRemotePlayer.java @@ -0,0 +1,9 @@ +package com.leflat.jass.common; + +public interface IRemotePlayer { + int connect(String name, String host, int gameId); + + boolean disconnect(); + + boolean isConnected(); +} diff --git a/src/main/java/com/leflat/jass/common/Plie.java b/src/main/java/com/leflat/jass/common/Plie.java new file mode 100644 index 0000000..a76a8a2 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/Plie.java @@ -0,0 +1,87 @@ +package com.leflat.jass.common; + + +public class Plie { + public int highest; // la plus haute carte de la plie (celle qui tient la plie) + public int color; // la couleur demandée + public int score; // la valeur de la plie + public boolean cut; // 0 : pas coupé, 1 : coupé + public BasePlayer owner = null; // iD de celui qui tient la plie + + public Plie(Card card, int atout, BasePlayer owner) { + color = card.getColor(); + highest = card.getRank(); + score = card.getValue(atout); + this.owner = owner; + cut = false; + } + + public Plie(int color, int highestRank, boolean cut) { + this.color = color; + this.highest = highestRank; + this.cut = cut; + } + + public void playCard(Card card, int atout, BasePlayer player) throws BrokenRuleException { + if (card.getColor() == atout) { + if (color != atout) { // si on coupe + if (cut) { // already cut + switch (card.getRank()) { // surcoupe + case Card.RANK_NELL: // si on joue le nell + if (highest == Card.RANK_BOURG) { + throw new BrokenRuleException(Rules.RULES_CANNOT_UNDERCUT); + } + highest = card.getRank(); + owner = player; + break; + case Card.RANK_BOURG: // si on joue le bourg + highest = card.getRank(); + owner = player; + break; + default: // sinon + if ((highest == Card.RANK_BOURG) || + (highest == Card.RANK_NELL) || + (card.getRank() < highest)) { + throw new BrokenRuleException(Rules.RULES_CANNOT_UNDERCUT); + } + highest = card.getRank(); + owner = player; + break; + } + // else souscoupe => nothing to do + } else { // first to cut + cut = true; + highest = card.getRank(); + owner = player; + } + } else { // si c'est joué atout + switch (card.getRank()) { + case Card.RANK_NELL: // si on joue le nell + if (highest != Card.RANK_BOURG) { + highest = card.getRank(); + owner = player; + } + break; + case Card.RANK_BOURG: // si on joue le bourg + highest = card.getRank(); + owner = player; + break; + default: // sinon + if ((highest != Card.RANK_BOURG) && + (highest != Card.RANK_NELL) && + (card.getRank() > highest)) { + highest = card.getRank(); + owner = player; + } + break; + } + } + } else if (card.getColor() == color) { + if ((card.getRank() > highest) && !cut) { + highest = card.getRank(); + owner = player; + } + } + score += card.getValue(atout); // augmente le score de la plie + } +} diff --git a/src/main/java/com/leflat/jass/common/RemoteCommand.java b/src/main/java/com/leflat/jass/common/RemoteCommand.java new file mode 100644 index 0000000..aaccf78 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/RemoteCommand.java @@ -0,0 +1,26 @@ +package com.leflat.jass.common; + +public abstract class RemoteCommand { + public static final int SET_PLAYER_INFO = 2; + public static final int CHOOSE_TEAM_SELECTION_METHOD = 3; + public static final int PREPARE_TEAM_DRAWING = 4; + public static final int DRAW_CARD = 5; + public static final int SET_CARD = 6; + public static final int RESTART_TEAM_DRAWING = 7; + public static final int SET_PLAYERS_ORDER = 8; + public static final int CHOOSE_PARTNER = 9; + public static final int SET_HAND = 10; + public static final int CHOOSE_ATOUT = 11; + public static final int CHOOSE_ATOUT_SECOND = 12; + public static final int SET_ATOUT = 13; + public static final int PLAY = 14; + public static final int SET_PLAYED_CARD = 15; + public static final int PLAY_NEXT = 16; + public static final int SET_PLIE_OWNER = 17; + public static final int SET_SCORES = 18; + public static final int GET_ANOUNCEMENTS = 19; + public static final int SET_ANOUNCEMENTS = 20; + public static final int SET_GAME_RESULT = 21; + public static final int GET_NEW_GAME = 22; + public static final int PLAYER_LEFT = 23; +} diff --git a/src/main/java/com/leflat/jass/common/Rules.java b/src/main/java/com/leflat/jass/common/Rules.java new file mode 100644 index 0000000..95283b9 --- /dev/null +++ b/src/main/java/com/leflat/jass/common/Rules.java @@ -0,0 +1,68 @@ +package com.leflat.jass.common; + +import java.util.List; + +public class Rules { + public static final int RULES_OK = 0; + public static final int RULES_MUST_FOLLOW = 1; + public static final int RULES_CANNOT_UNDERCUT = 2; + + + public static int canPlay(Card card, Plie currentPlie, List hand, int atoutColor) { + if (currentPlie.color < 0) { + return RULES_OK; + } + if (card.getColor() == currentPlie.color) { + return RULES_OK; + } + if (card.getColor() == atoutColor) { + if (!currentPlie.cut) { + return RULES_OK; + } + + switch (card.getRank()) { + case Card.RANK_BOURG: + return RULES_OK; + case Card.RANK_NELL: + if (currentPlie.highest == Card.RANK_BOURG) { + return RULES_CANNOT_UNDERCUT; // on ne peut pas sous-couper + } + return RULES_OK; // nell sans bourg : ok! + default: + if ((currentPlie.highest == Card.RANK_BOURG) || + (currentPlie.highest == Card.RANK_NELL) || + (currentPlie.highest > card.getRank())) { + return RULES_CANNOT_UNDERCUT; // on ne peut pas sous-couper + } + return RULES_OK; + } + } else { // carte jouée pas d'atout + if (!hasColor(hand, currentPlie.color)) { + return RULES_OK; + } + // The player owns cards from the required color + if ((currentPlie.color == atoutColor) && hasBourSec(hand, atoutColor)) { + return RULES_OK; // bourg sec -> ok + } + return RULES_MUST_FOLLOW; + } + } + + public static boolean hasColor(List hand, int color) { + return hand.stream().anyMatch(c -> c.getColor() == color); + } + + public static boolean hasBourSec(List hand, int atout) { + int numberAtouts = 0; + boolean bourg = false; + for (var card : hand) { + if (card.getColor() == atout) { + numberAtouts += 1; + if (card.getRank() == Card.RANK_BOURG) { + bourg = true; + } + } + } + return bourg && numberAtouts == 1; + } +} diff --git a/src/main/java/com/leflat/jass/common/Team.java b/src/main/java/com/leflat/jass/common/Team.java new file mode 100644 index 0000000..b00ea3a --- /dev/null +++ b/src/main/java/com/leflat/jass/common/Team.java @@ -0,0 +1,57 @@ +package com.leflat.jass.common; + +import java.util.ArrayList; +import java.util.List; + +public class Team { + // Variables + private int currentScore; + private List players = new ArrayList<>(); + private int id; + public static final int WINNING_SCORE = 1500; + + // Constructeur + public Team(int id) { + currentScore = 0; + this.id = id; + } + + // Méthodes + public void resetScore() { + currentScore = 0; + } + + public void reset() { + players.clear(); + resetScore(); + } + + public void addScore(int score) { + currentScore += score; + } + + public boolean hasWon() { + return currentScore >= WINNING_SCORE; + } + + public int getScore() { + return currentScore; + } + + public BasePlayer getPlayer(int i) { + return players.get(i); + } + + public void addPlayer(BasePlayer p) { + players.add(p); + p.setTeam(this); + } + + public void addAnnoucementScore(List anouncements, int atout) { + for (var a : anouncements) { + currentScore += atout == Card.COLOR_SPADE ? 2 * a.getValue() : a.getValue(); + } + } + + public int getId() { return id; } +} diff --git a/src/main/java/com/leflat/jass/common/TeamSelectionMethod.java b/src/main/java/com/leflat/jass/common/TeamSelectionMethod.java new file mode 100644 index 0000000..a97dd1a --- /dev/null +++ b/src/main/java/com/leflat/jass/common/TeamSelectionMethod.java @@ -0,0 +1,5 @@ +package com.leflat.jass.common; + +public enum TeamSelectionMethod { + RANDOM, MANUAL +} diff --git a/src/main/java/com/leflat/jass/server/ConnectionListener.java b/src/main/java/com/leflat/jass/server/ConnectionListener.java new file mode 100644 index 0000000..8cc174b --- /dev/null +++ b/src/main/java/com/leflat/jass/server/ConnectionListener.java @@ -0,0 +1,86 @@ +package com.leflat.jass.server; + +import com.leflat.jass.common.ConnectionError; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.*; + +public class ConnectionListener extends Thread { + private ServerSocket serverSocket; + private Map games = new HashMap<>(); + private boolean running = false; + + public ConnectionListener(int port) throws IOException { + serverSocket = new ServerSocket(port); + + // TODO: remove (DEBUG) + games.put(0, new GameController(0)); + } + + @Override + public void run() { + System.out.println("Jass server running on port " + serverSocket.getLocalPort()); + running = true; + while (running) { + try { + var clientSocket = serverSocket.accept(); + handleNewConnection(clientSocket); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void handleNewConnection(Socket clientSocket) throws IOException { + var network = new PlayerNetwork(clientSocket); + + try { + var game = selectGame(network); + if (game == null) { + return; + } + + var newPlayer = new RemotePlayer(game.getNbrPlayers(), network); + game.addPlayer(newPlayer); + + if (game.isGameFull()) { + game.start(); + } + } catch (PlayerLeftExpection ignored) { + System.err.println("Error: client left while attempting to connect"); + } + } + + private GameController selectGame(PlayerNetwork network) throws PlayerLeftExpection { + GameController game; + String connectionMessage = network.receiveRawMessage(); + int gameId = Integer.parseInt(connectionMessage); + if (gameId < 0) { + int newGameId = getRandomGameId(); + network.sendMessage(String.valueOf(newGameId)); + game = new GameController(newGameId); + games.put(newGameId, game); + } else { + if (!games.containsKey(gameId)) { + network.sendMessage(String.valueOf(ConnectionError.UNKNOWN_GAME)); + System.err.println("Error: unknown game id " + gameId); + return null; + } + game = games.get(gameId); + if (game.isGameFull()) { + network.sendMessage(String.valueOf(ConnectionError.GAME_FULL)); + System.err.println("Error: attempting to enter full game " + gameId); + return null; + } + network.sendMessage(String.valueOf(gameId)); + } + return game; + } + + private int getRandomGameId() { + Random rnd = new Random(); + return rnd.nextInt(999999); + } +} diff --git a/src/main/java/com/leflat/jass/server/GameController.java b/src/main/java/com/leflat/jass/server/GameController.java new file mode 100644 index 0000000..f078ec7 --- /dev/null +++ b/src/main/java/com/leflat/jass/server/GameController.java @@ -0,0 +1,386 @@ +package com.leflat.jass.server; + +import com.leflat.jass.common.*; + +import java.util.*; +import java.util.stream.Collectors; + +public class GameController extends Thread { + private int gameId; + private List players = new ArrayList<>(); + private Team[] teams = new Team[2]; // les 2 équipes + private int atout; + + public GameController(int id) { + this.gameId = id; + for (int i = 0; i < 2; i++) { // création des équipes + teams[i] = new Team(i); + } + } + + public void addPlayer(RemotePlayer newPlayer) throws PlayerLeftExpection { + assert players.size() < 4; + for (var p : players) { + p.setPlayerInfo(newPlayer); + newPlayer.setPlayerInfo(p); + } + players.add(newPlayer); + } + + public int getNbrPlayers() { + return players.size(); + } + + public boolean isGameFull() { + return players.size() == 4; + } + + public int getGameId() { + return gameId; + } + + @Override + public void run() { + System.out.println("Starting game room " + gameId); + + try { + boolean playAnotherGame; + do { + chooseTeam(); // détermine les équipes + + playOneGame(); + + playAnotherGame = players.get(0).getNewGame(); + + for (Team team : teams) { + team.resetScore(); + } + } while (playAnotherGame); + + } catch (PlayerLeftExpection e) { + var disconnectedPlayer = getPlayerById(e.getPlayerId()); + players.remove(disconnectedPlayer); + for (var player : players) { + try { + player.playerLeft(disconnectedPlayer); + } catch (PlayerLeftExpection ee) { + System.err.println("Player " + ee.getPlayerId() + " also left."); + } + } + } catch (BrokenRuleException e) { + System.err.println("Error: Jass rule broken: " + e.getBrokenRule()); + } + + System.out.println("Game " + gameId + " ended"); + } + + private void playOneGame() throws PlayerLeftExpection, BrokenRuleException { + int firstToPlay = drawCards(); + int nextPlayer; + do { + atout = chooseAtout(firstToPlay); // choisit l'atout + nextPlayer = firstToPlay; + + int plieNumber = 0; + while ((plieNumber < 9) && (nextPlayer >= 0)) { // fait jouer les 9 plies + nextPlayer = playPlie(nextPlayer); + plieNumber++; + } + + if (nextPlayer >= 0) { // si personne n'a gagné : on continue normalement + // 5 de der + players.get(nextPlayer).getTeam().addScore(atout == Card.COLOR_SPADE ? 10 : 5); + + for (var p : players) { // envoie le score + var opponentTeam = teams[(p.getTeam().getId() + 1) % 2]; + p.setScores(p.getTeam().getScore(), opponentTeam.getScore()); + } + + /* waits a few seconds so that the players can see the last + * cards and the score */ + waitSec(2); + + firstToPlay = (firstToPlay + 1) % 4; + drawCards(); + } else { // si une équipe a gagné + for (var p : players) { // envoie le score + var opponentTeam = teams[(p.getTeam().getId() + 1) % 2]; + p.setScores(p.getTeam().getScore(), opponentTeam.getScore()); + } + } + + // répète jusqu'à ce qu'on gagne + } while (!teams[0].hasWon() && !teams[1].hasWon()); + + // Sends the winner to all player + var winners = teams[0].hasWon() ? teams[0] : teams[1]; + for (var p : players) { + p.setGameResult(winners); + } + + /* waits a few seconds so that the players can see all the cards */ + waitSec(4); + } + + int playPlie(int startingPlayer) throws PlayerLeftExpection, BrokenRuleException { + var player = players.get(startingPlayer); + var cardPlayed = player.play(-1, -1, false); + var currentPlie = new Plie(cardPlayed, atout, player); + + for (int i = 1; i < 4; i++) { // envoie la carte jouée aux autres + players.get((startingPlayer + i) % 4).setPlayedCard(player, cardPlayed); + } + + player.getAnoucement(); + + for (int i = 1; i < 4; i++) { // demande de jouer + player = players.get((startingPlayer + i) % 4); + // TODO: replace arguments with currentPlie + cardPlayed = player.play(currentPlie.color, currentPlie.highest, currentPlie.cut); + + player.getAnoucement(); + + for (int j = 1; j < 4; j++) { // envoie la carte jouée aux autres + players.get((startingPlayer + i + j) % 4).setPlayedCard(player, cardPlayed); + } + + currentPlie.playCard(cardPlayed, atout, player); + } + + /* now everybody has played ... */ + + /* waits a few seconds so that the players can see all the cards */ + waitSec(1.5f); + + // communique qui a pris la plie + for (var p : players) { + p.setPlieOwner(currentPlie.owner); + } + + // choix et comptabilisation des annonces + processAnoucements(); + + // comptabilisation des points + currentPlie.owner.getTeam().addScore(atout == Card.COLOR_SPADE ? currentPlie.score * 2 : currentPlie.score); + + if (teams[0].hasWon() || teams[1].hasWon()) { + return -1; + } + + return getPlayerPosition(currentPlie.owner); + } + + void processAnoucements() throws PlayerLeftExpection { + BasePlayer playerWithStoeck = null; + int highestAnouncement = -1; + int highestRank = Card.RANK_6; + Team anouncingTeam = null; // joueur qui a la plus grosse annonce + for (var p : players) { + for (var anouncement : p.getAnouncements()) { + System.out.println(p + " announce : " + anouncement); + if (anouncement.getType() == Anouncement.STOECK) { + playerWithStoeck = p; + continue; + } + if (anouncement.getType() > highestAnouncement) { + // plus grosse annonce + anouncingTeam = p.getTeam(); + highestAnouncement = anouncement.getType(); + highestRank = anouncement.getCard().getRank(); + } else if ((anouncement.getType() == highestAnouncement) && + (anouncement.getCard().getRank() > highestRank)) { + // même annonce plus haute + anouncingTeam = p.getTeam(); + highestRank = anouncement.getCard().getRank(); + } else if ((anouncement.getType() == highestAnouncement) && + (anouncement.getCard().getRank() == highestRank) && + (anouncement.getCard().getColor() == atout)) { + // meme annonce, meme hauteur, mais atout + anouncingTeam = p.getTeam(); + } + } + } + + if (anouncingTeam != null) { // there are announces + for (var p : players) { + if (p.getAnoucement().isEmpty()) { + continue; + } + if ((p.getTeam() == anouncingTeam)) { + anouncingTeam.addAnnoucementScore(p.getAnouncements(), atout); + for (var p2 : players) { + p2.setAnouncement(p, p.getAnouncements()); + } + } + p.clearAnouncement(); + } + } else if (playerWithStoeck != null) { // no announce but stock + for (var p : players) { + p.setAnouncement(playerWithStoeck, Collections.singletonList(new Anouncement(Anouncement.STOECK, null))); + } + int stoeckScore = atout == Card.COLOR_SPADE ? Anouncement.VALUES[Anouncement.STOECK] * 2 : Anouncement.VALUES[Anouncement.STOECK]; + // add stock points + playerWithStoeck.getTeam().addScore(stoeckScore); + playerWithStoeck.clearAnouncement(); + } + } + + int chooseAtout(int playerNumber) throws PlayerLeftExpection { + var choice = players.get(playerNumber).chooseAtout(true); // demande de faire atout en premier + if (choice == 4) { // si on passe + var second = players.get((playerNumber + 2) % 4); + choice = second.chooseAtout(false); // demande de faire atout en second + } + for (var p : players) { + p.setAtout(choice, players.get(playerNumber)); + } + return choice; + } + + int drawCards() throws PlayerLeftExpection { + int playerWithDiamondSeven = 0; // 7 de carreau + var cards = Card.shuffle(36); // choisir les cartes au hasard + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 9; j++) { + if (cards.get(i * 9 + j).getNumber() == Card.DIAMOND_SEVEN) { // 7 de carreau + playerWithDiamondSeven = i; + break; + } + } + players.get(i).setHand(cards.subList(i * 9, (i + 1) * 9)); + } + return playerWithDiamondSeven; + } + + private void chooseTeam() throws PlayerLeftExpection { + Arrays.stream(teams).forEach(Team::reset); + + var teamChoiceMethod = players.get(0).chooseTeamSelectionMethod(); + if (teamChoiceMethod == TeamSelectionMethod.RANDOM) { // choisir au hasard + chooseTeamsRandomly(); + } else { // choisir son partenaire + pickTeamMates(); + } + + reorderPlayers(); + + var order = players.stream().map(BasePlayer::getId).collect(Collectors.toList()); + for (var p : players) { + p.setPlayersOrder(order); + } + } + + private void chooseTeamsRandomly() throws PlayerLeftExpection { + // préparation du tirage des équipes + for (var player : players) { + player.prepareTeamDrawing(true); + } + + boolean drawingSuccessful; + do { + HashMap cardsDrawn = new HashMap<>(); // cartes tirées + var cards = Card.shuffle(36); + for (var p : players) { + int cardNumber = p.drawCard(); + + cardsDrawn.put(p, cards.get(cardNumber)); + + for (var p2 : players) { + p2.setCard(p, cardNumber, cards.get(cardNumber)); + } + } + // delay to allow players to watch cards + waitSec(2); + + // détermine les équipes + drawingSuccessful = calculateTeam(cardsDrawn); + if (!drawingSuccessful) { + for (var p : players) { + p.prepareTeamDrawing(false); + } + } + } while (!drawingSuccessful); + } + + private boolean calculateTeam(Map choosenCards) { + var lowest = players.get(0); + var highest = players.get(0); + for (int i = 1; i < 4; i++) { + var player = players.get(i); + if (choosenCards.get(player).getRank() < choosenCards.get(lowest).getRank()) + lowest = player; + if (choosenCards.get(player).getRank() > choosenCards.get(highest).getRank()) + highest = player; + } + boolean ok = true; + for (BasePlayer player : players) { + if (player != lowest) { + if (choosenCards.get(player).getRank() == choosenCards.get(lowest).getRank()) { + ok = false; + } + } + if (player != highest) { + if (choosenCards.get(player).getRank() == choosenCards.get(highest).getRank()) { + ok = false; + } + } + } + if (!ok) return false; + + for (BasePlayer p : players) { + if (p == lowest || p == highest) { + teams[0].addPlayer(p); + } else { + teams[1].addPlayer(p); + } + } + + return true; + } + + private void pickTeamMates() throws PlayerLeftExpection { + int partnerId = players.get(0).choosePartner(); // demande de choisir le partenaire + for (var p : players) { + if (p.getId() == partnerId || p == players.get(0)) { + teams[0].addPlayer(p); + } else { + teams[1].addPlayer(p); + } + } + } + + private RemotePlayer getPlayerById(int id) { + for (var p : players) { + if (p.getId() == id) { + return p; + } + } + System.err.println("Error: unknown player id " + id); + return null; + } + + private int getPlayerPosition(BasePlayer player) { + for (int i = 0; i < players.size(); i++) { + if (players.get(i).getId() == player.getId()) { + return i; + } + } + throw new IndexOutOfBoundsException("Player " + player.getId() + " not found"); + } + + private void reorderPlayers() { + var tempList = List.copyOf(players); + players.clear(); + players.add(tempList.get(teams[0].getPlayer(0).getId())); + players.add(tempList.get(teams[1].getPlayer(0).getId())); + players.add(tempList.get(teams[0].getPlayer(1).getId())); + players.add(tempList.get(teams[1].getPlayer(1).getId())); + } + + private static void waitSec(float seconds) { + try { + Thread.sleep((long) (seconds * 1000)); + } catch (InterruptedException ignored) { + } + } +} diff --git a/src/main/java/com/leflat/jass/server/JassServer.java b/src/main/java/com/leflat/jass/server/JassServer.java new file mode 100644 index 0000000..cca6715 --- /dev/null +++ b/src/main/java/com/leflat/jass/server/JassServer.java @@ -0,0 +1,26 @@ +package com.leflat.jass.server; + +import java.io.IOException; + +public class JassServer { + public static final int DEFAULT_PORT = 23107; + + public static void main(String[] args) { + System.out.println("FLAT Jass System Server"); + System.out.println("Version 1.2"); + System.out.println("(c) 2000-2020 by FLAT(r)"); + System.out.println(); + + // TODO: add command line argument parsing (Apache commons) + ConnectionListener listener = null; + + try { + listener = new ConnectionListener(DEFAULT_PORT); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + + listener.start(); + } +} diff --git a/src/main/java/com/leflat/jass/server/PlayerLeftExpection.java b/src/main/java/com/leflat/jass/server/PlayerLeftExpection.java new file mode 100644 index 0000000..d82e412 --- /dev/null +++ b/src/main/java/com/leflat/jass/server/PlayerLeftExpection.java @@ -0,0 +1,13 @@ +package com.leflat.jass.server; + +public class PlayerLeftExpection extends Exception { + int playerId; + + public PlayerLeftExpection(int clientID) { + this.playerId = clientID; + } + + public int getPlayerId() { + return playerId; + } +} diff --git a/src/main/java/com/leflat/jass/server/PlayerNetwork.java b/src/main/java/com/leflat/jass/server/PlayerNetwork.java new file mode 100644 index 0000000..13e4f70 --- /dev/null +++ b/src/main/java/com/leflat/jass/server/PlayerNetwork.java @@ -0,0 +1,61 @@ +package com.leflat.jass.server; + +import java.io.*; +import java.net.Socket; +import java.util.Arrays; +import java.util.List; + +public class PlayerNetwork { + private BufferedReader is; + private PrintWriter os; + private int playerId = -1; + + public PlayerNetwork(Socket socket) throws IOException { + var isr = new InputStreamReader(socket.getInputStream()); + is = new BufferedReader(isr); + os = new PrintWriter(new BufferedOutputStream(socket.getOutputStream()), false); + } + + public int sendMessage(String message) { + os.println(message); + os.flush(); + System.out.println("Sent : " + message); // DEBUG + return 0; + } + + public int sendMessage(List message) { + return sendMessage(String.join(" ", message)); + } + + public String receiveRawMessage() throws PlayerLeftExpection { + String message = null; + + // TODO: implementer timeout + exc + try { + message = is.readLine(); + } catch (IOException e) { + System.out.println("Error during reception"); + } + if (message != null) + System.out.println("Received : " + message); // DEBUG + else { + System.out.println("Client has left unexpectedly"); + throw new PlayerLeftExpection(playerId); + } + return message; + } + + public String[] receiveMessage() throws PlayerLeftExpection { + var message = receiveRawMessage(); + var tokens = message.split(" "); + assert Integer.parseInt(tokens[0]) == playerId; + if (tokens.length == 1) { + return null; + } + return Arrays.copyOfRange(tokens, 1, tokens.length); + } + + void setPlayerId(int id) { + playerId = id; + } +} diff --git a/src/main/java/com/leflat/jass/server/RemotePlayer.java b/src/main/java/com/leflat/jass/server/RemotePlayer.java new file mode 100644 index 0000000..9b0aead --- /dev/null +++ b/src/main/java/com/leflat/jass/server/RemotePlayer.java @@ -0,0 +1,209 @@ +package com.leflat.jass.server; + +import com.leflat.jass.common.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class RemotePlayer extends BasePlayer implements IPlayer { + private PlayerNetwork network; + + public RemotePlayer(int id, PlayerNetwork network) throws PlayerLeftExpection { + super(id); + this.network = network; + this.network.setPlayerId(id); + updatePlayerInfo(); + } + + @Override + public void setPlayerInfo(BasePlayer player) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_PLAYER_INFO)); + message.add(String.valueOf(player.getId())); + message.add(player.getName()); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public TeamSelectionMethod chooseTeamSelectionMethod() throws PlayerLeftExpection { + network.sendMessage(String.valueOf(RemoteCommand.CHOOSE_TEAM_SELECTION_METHOD)); + var tokens = network.receiveMessage(); + return TeamSelectionMethod.valueOf(tokens[0]); + } + + @Override + public void prepareTeamDrawing(boolean firstAttempt) throws PlayerLeftExpection { + if (firstAttempt) { + network.sendMessage(String.valueOf(RemoteCommand.PREPARE_TEAM_DRAWING)); + } else { + network.sendMessage(String.valueOf(RemoteCommand.RESTART_TEAM_DRAWING)); + } + network.receiveMessage(); + } + + @Override + public int drawCard() throws PlayerLeftExpection { + network.sendMessage(String.valueOf(RemoteCommand.DRAW_CARD)); + return Integer.parseInt(network.receiveMessage()[0]); + } + + @Override + public void setCard(BasePlayer player, int cardPosition, Card card) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_CARD)); + message.add(String.valueOf(player.getId())); + message.add(String.valueOf(cardPosition)); + message.add(String.valueOf(card.getNumber())); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public void setPlayersOrder(List playerIds) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_PLAYERS_ORDER)); + message.addAll(playerIds.stream().map(String::valueOf).collect(Collectors.toList())); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public int choosePartner() throws PlayerLeftExpection { + network.sendMessage(String.valueOf(RemoteCommand.CHOOSE_PARTNER)); + return Integer.parseInt(network.receiveMessage()[0]); + } + + @Override + public void setHand(List cards) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_HAND)); + message.addAll(cards.stream().map(c -> String.valueOf(c.getNumber())).collect(Collectors.toList())); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public int chooseAtout(boolean first) throws PlayerLeftExpection { + if (first) { + network.sendMessage(String.valueOf(RemoteCommand.CHOOSE_ATOUT)); + } else { + network.sendMessage(String.valueOf(RemoteCommand.CHOOSE_ATOUT_SECOND)); + } + return Integer.parseInt(network.receiveMessage()[0]); + } + + @Override + public void setAtout(int color, BasePlayer firstToPlay) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_ATOUT)); + message.add(String.valueOf(color)); + message.add(String.valueOf(firstToPlay.getId())); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public Card play(int currentColor, int highestRank, boolean cut) throws PlayerLeftExpection { + if (currentColor < 0) { + network.sendMessage(String.valueOf(RemoteCommand.PLAY)); + } else { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.PLAY_NEXT)); + message.add(String.valueOf(highestRank)); + message.add(String.valueOf(currentColor)); + message.add(String.valueOf(cut ? 1 : 0)); + network.sendMessage(message); + } + var cardNumber = Integer.parseInt(network.receiveMessage()[0]); + return new Card(cardNumber); + } + + @Override + public void setPlayedCard(BasePlayer player, Card card) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_PLAYED_CARD)); + message.add(String.valueOf(player.getId())); + message.add(String.valueOf(card.getNumber())); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public void setPlieOwner(BasePlayer player) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_PLIE_OWNER)); + message.add(String.valueOf(player.getId())); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public void setScores(int score, int opponentScore) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_SCORES)); + message.add(String.valueOf(score)); + message.add(String.valueOf(opponentScore)); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public List getAnoucement() throws PlayerLeftExpection { + network.sendMessage(String.valueOf(RemoteCommand.GET_ANOUNCEMENTS)); + var tokens = network.receiveMessage(); + this.anoucements.clear(); + int nbrAnouncements = Integer.parseInt(tokens[0]); + for (int i = 0; i < nbrAnouncements; i++) { + var card = new Card(Integer.parseInt(tokens[i * 2 + 2])); + this.anoucements.add(new Anouncement(Integer.parseInt(tokens[i * 2 + 1]), card)); + } + return this.anoucements; + } + + @Override + public void setAnouncement(BasePlayer player, List anouncements) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_ANOUNCEMENTS)); + message.add(String.valueOf(player.getId())); + message.add(String.valueOf(anouncements.size())); + for (var anoucement : anouncements) { + message.add(String.valueOf(anoucement.getType())); + message.add(String.valueOf(anoucement.getCard().getNumber())); + } + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public void setGameResult(Team winningTeam) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.SET_GAME_RESULT)); + message.add(String.valueOf(winningTeam.getId())); + message.add(String.valueOf(winningTeam.getPlayer(0))); + message.add(String.valueOf(winningTeam.getPlayer(1))); + network.sendMessage(message); + network.receiveMessage(); + } + + @Override + public boolean getNewGame() throws PlayerLeftExpection { + network.sendMessage(String.valueOf(RemoteCommand.GET_NEW_GAME)); + return Integer.parseInt(network.receiveMessage()[0]) == 1; + } + + @Override + public void playerLeft(BasePlayer player) throws PlayerLeftExpection { + var message = new ArrayList(); + message.add(String.valueOf(RemoteCommand.PLAYER_LEFT)); + message.add(String.valueOf(player.getId())); + network.sendMessage(message); + network.receiveMessage(); + } + + private void updatePlayerInfo() throws PlayerLeftExpection { + network.sendMessage(String.valueOf(id)); + this.name = network.receiveMessage()[0]; + } +} diff --git a/src/main/java/com/leflat/jass/test/TestClient.java b/src/main/java/com/leflat/jass/test/TestClient.java new file mode 100644 index 0000000..c9e6ff7 --- /dev/null +++ b/src/main/java/com/leflat/jass/test/TestClient.java @@ -0,0 +1,182 @@ +package com.leflat.jass.test; + +import com.leflat.jass.common.Anouncement; +import com.leflat.jass.common.Card; +import com.leflat.jass.common.RemoteCommand; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class TestClient { + public static final int PORT = 23107; + + private BufferedReader is; + private PrintWriter os; + + TestClient() { + ServerSocket serverSocket = null; + Socket clientSocket = null; + try { + serverSocket = new ServerSocket(PORT); + System.out.println("Started test server on port " + PORT); + clientSocket = serverSocket.accept(); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + + InputStreamReader isr = null; + try { + isr = new InputStreamReader(clientSocket.getInputStream()); + is = new BufferedReader(isr); + os = new PrintWriter(new BufferedOutputStream(clientSocket.getOutputStream()), false); + } catch (IOException e) { + e.printStackTrace(); + } + + String connectionMessage = receiveRawMessage(); + int gameId = Integer.parseInt(connectionMessage); + sendMessage(String.valueOf(gameId)); + int playerId = 1; + sendMessage(String.valueOf(playerId)); + String name = receiveMessage()[0]; + System.out.println("Client " + name + " connected"); + + sendMessage(RemoteCommand.SET_PLAYER_INFO + " " + 0 + " Berte" ); + receiveMessage(); + + sendMessage(RemoteCommand.SET_PLAYER_INFO + " " + 2 + " GC" ); + receiveMessage(); + + sendMessage(RemoteCommand.SET_PLAYER_INFO + " " + 3 + " Pischus" ); + receiveMessage(); + + /* + sendMessage(String.valueOf(RemoteCommand.DRAW_CARD)); + + int cardPosition = Integer.parseInt(receiveMessage()[0]); + System.out.println("Drawn card: " + cardPosition); + + var card = new Card(Card.RANK_BOURG, Card.COLOR_HEART); + sendMessage(RemoteCommand.SET_CARD + " " + playerId + " " + cardPosition + " " + card.getNumber()); + receiveMessage(); + + var otherCard = new Card(Card.RANK_DAME, Card.COLOR_DIAMOND); + sendMessage(RemoteCommand.SET_CARD + " " + (playerId+1) + " " + 20 + " " + otherCard.getNumber()); + receiveMessage(); + + sendMessage(RemoteCommand.SET_PLAYERS_ORDER + " 3 0 2 1"); + receiveMessage(); + + sendMessage(String.valueOf(RemoteCommand.CHOOSE_PARTNER)); + int partnerId = Integer.parseInt(receiveMessage()[0]); + + */ +/* + sendMessage(RemoteCommand.SET_HAND + " 10 12 14 16 18"); + receiveMessage(); + + sendMessage(String.valueOf(RemoteCommand.CHOOSE_ATOUT)); + int color = Integer.parseInt(receiveMessage()[0]); + System.out.println("Chosen : " + color); + + sendMessage(String.valueOf(RemoteCommand.CHOOSE_ATOUT_SECOND)); + color = Integer.parseInt(receiveMessage()[0]); + System.out.println("Chosen : " + color); + + sendMessage(String.valueOf(RemoteCommand.PLAY)); + card = new Card(Integer.parseInt(receiveMessage()[0])); + System.out.println(card); + + sendMessage(RemoteCommand.SET_PLAYED_CARD + " 0 35"); + receiveMessage(); + + sendMessage(RemoteCommand.PLAY_NEXT + " 3 1 0"); + receiveMessage(); + + sendMessage(RemoteCommand.SET_PLIE_OWNER + " 3"); + receiveMessage(); + + sendMessage(RemoteCommand.SET_SCORES + " 69 156"); + receiveMessage(); +*/ + sendMessage(RemoteCommand.SET_HAND + " 3 4 5 6 12 21 30"); + receiveMessage(); + + + sendMessage(RemoteCommand.SET_ATOUT + " " + Card.COLOR_DIAMOND + " 2"); + receiveMessage(); + + sendMessage(String.valueOf(RemoteCommand.PLAY)); + var card = new Card(Integer.parseInt(receiveMessage()[0])); + System.out.println(card); + + sendMessage(String.valueOf(RemoteCommand.GET_ANOUNCEMENTS)); + var answer = receiveMessage(); + int nbr = Integer.parseInt(answer[0]); + for (int i=0; i message) { + return sendMessage(String.join(" ", message)); + } +} diff --git a/src/main/resources/pics/0.png b/src/main/resources/pics/0.png new file mode 100644 index 0000000..23b5213 Binary files /dev/null and b/src/main/resources/pics/0.png differ diff --git a/src/main/resources/pics/1.png b/src/main/resources/pics/1.png new file mode 100644 index 0000000..cf22d54 Binary files /dev/null and b/src/main/resources/pics/1.png differ diff --git a/src/main/resources/pics/10.png b/src/main/resources/pics/10.png new file mode 100644 index 0000000..eaae273 Binary files /dev/null and b/src/main/resources/pics/10.png differ diff --git a/src/main/resources/pics/11.png b/src/main/resources/pics/11.png new file mode 100644 index 0000000..de0a49f Binary files /dev/null and b/src/main/resources/pics/11.png differ diff --git a/src/main/resources/pics/12.png b/src/main/resources/pics/12.png new file mode 100644 index 0000000..e90f165 Binary files /dev/null and b/src/main/resources/pics/12.png differ diff --git a/src/main/resources/pics/13.png b/src/main/resources/pics/13.png new file mode 100644 index 0000000..b5a2f93 Binary files /dev/null and b/src/main/resources/pics/13.png differ diff --git a/src/main/resources/pics/14.png b/src/main/resources/pics/14.png new file mode 100644 index 0000000..d5b4f4c Binary files /dev/null and b/src/main/resources/pics/14.png differ diff --git a/src/main/resources/pics/15.png b/src/main/resources/pics/15.png new file mode 100644 index 0000000..8e9fc3b Binary files /dev/null and b/src/main/resources/pics/15.png differ diff --git a/src/main/resources/pics/16.png b/src/main/resources/pics/16.png new file mode 100644 index 0000000..42313d8 Binary files /dev/null and b/src/main/resources/pics/16.png differ diff --git a/src/main/resources/pics/17.png b/src/main/resources/pics/17.png new file mode 100644 index 0000000..3a4fcad Binary files /dev/null and b/src/main/resources/pics/17.png differ diff --git a/src/main/resources/pics/18.png b/src/main/resources/pics/18.png new file mode 100644 index 0000000..d624da6 Binary files /dev/null and b/src/main/resources/pics/18.png differ diff --git a/src/main/resources/pics/19.png b/src/main/resources/pics/19.png new file mode 100644 index 0000000..657811a Binary files /dev/null and b/src/main/resources/pics/19.png differ diff --git a/src/main/resources/pics/2.png b/src/main/resources/pics/2.png new file mode 100644 index 0000000..23c3bb1 Binary files /dev/null and b/src/main/resources/pics/2.png differ diff --git a/src/main/resources/pics/20.png b/src/main/resources/pics/20.png new file mode 100644 index 0000000..13ee843 Binary files /dev/null and b/src/main/resources/pics/20.png differ diff --git a/src/main/resources/pics/21.png b/src/main/resources/pics/21.png new file mode 100644 index 0000000..bc4faaa Binary files /dev/null and b/src/main/resources/pics/21.png differ diff --git a/src/main/resources/pics/22.png b/src/main/resources/pics/22.png new file mode 100644 index 0000000..1f4d8bc Binary files /dev/null and b/src/main/resources/pics/22.png differ diff --git a/src/main/resources/pics/23.png b/src/main/resources/pics/23.png new file mode 100644 index 0000000..f4cb820 Binary files /dev/null and b/src/main/resources/pics/23.png differ diff --git a/src/main/resources/pics/24.png b/src/main/resources/pics/24.png new file mode 100644 index 0000000..7a15f6e Binary files /dev/null and b/src/main/resources/pics/24.png differ diff --git a/src/main/resources/pics/25.png b/src/main/resources/pics/25.png new file mode 100644 index 0000000..d6f58a0 Binary files /dev/null and b/src/main/resources/pics/25.png differ diff --git a/src/main/resources/pics/26.png b/src/main/resources/pics/26.png new file mode 100644 index 0000000..eba6007 Binary files /dev/null and b/src/main/resources/pics/26.png differ diff --git a/src/main/resources/pics/27.png b/src/main/resources/pics/27.png new file mode 100644 index 0000000..377d0f2 Binary files /dev/null and b/src/main/resources/pics/27.png differ diff --git a/src/main/resources/pics/28.png b/src/main/resources/pics/28.png new file mode 100644 index 0000000..6a1b6eb Binary files /dev/null and b/src/main/resources/pics/28.png differ diff --git a/src/main/resources/pics/29.png b/src/main/resources/pics/29.png new file mode 100644 index 0000000..5b5366f Binary files /dev/null and b/src/main/resources/pics/29.png differ diff --git a/src/main/resources/pics/3.png b/src/main/resources/pics/3.png new file mode 100644 index 0000000..92aae78 Binary files /dev/null and b/src/main/resources/pics/3.png differ diff --git a/src/main/resources/pics/30.png b/src/main/resources/pics/30.png new file mode 100644 index 0000000..3a1086f Binary files /dev/null and b/src/main/resources/pics/30.png differ diff --git a/src/main/resources/pics/31.png b/src/main/resources/pics/31.png new file mode 100644 index 0000000..f687a9a Binary files /dev/null and b/src/main/resources/pics/31.png differ diff --git a/src/main/resources/pics/32.png b/src/main/resources/pics/32.png new file mode 100644 index 0000000..e8bb9a2 Binary files /dev/null and b/src/main/resources/pics/32.png differ diff --git a/src/main/resources/pics/33.png b/src/main/resources/pics/33.png new file mode 100644 index 0000000..404a96e Binary files /dev/null and b/src/main/resources/pics/33.png differ diff --git a/src/main/resources/pics/34.png b/src/main/resources/pics/34.png new file mode 100644 index 0000000..781773b Binary files /dev/null and b/src/main/resources/pics/34.png differ diff --git a/src/main/resources/pics/35.png b/src/main/resources/pics/35.png new file mode 100644 index 0000000..d98e95d Binary files /dev/null and b/src/main/resources/pics/35.png differ diff --git a/src/main/resources/pics/4.png b/src/main/resources/pics/4.png new file mode 100644 index 0000000..28e7695 Binary files /dev/null and b/src/main/resources/pics/4.png differ diff --git a/src/main/resources/pics/5.png b/src/main/resources/pics/5.png new file mode 100644 index 0000000..b44c16e Binary files /dev/null and b/src/main/resources/pics/5.png differ diff --git a/src/main/resources/pics/6.png b/src/main/resources/pics/6.png new file mode 100644 index 0000000..ca33786 Binary files /dev/null and b/src/main/resources/pics/6.png differ diff --git a/src/main/resources/pics/7.png b/src/main/resources/pics/7.png new file mode 100644 index 0000000..187ef6e Binary files /dev/null and b/src/main/resources/pics/7.png differ diff --git a/src/main/resources/pics/8.png b/src/main/resources/pics/8.png new file mode 100644 index 0000000..5d7226a Binary files /dev/null and b/src/main/resources/pics/8.png differ diff --git a/src/main/resources/pics/9.png b/src/main/resources/pics/9.png new file mode 100644 index 0000000..3d6b95a Binary files /dev/null and b/src/main/resources/pics/9.png differ diff --git a/src/main/resources/pics/c0.png b/src/main/resources/pics/c0.png new file mode 100644 index 0000000..3383919 Binary files /dev/null and b/src/main/resources/pics/c0.png differ diff --git a/src/main/resources/pics/c1.png b/src/main/resources/pics/c1.png new file mode 100644 index 0000000..46d31ad Binary files /dev/null and b/src/main/resources/pics/c1.png differ diff --git a/src/main/resources/pics/c2.png b/src/main/resources/pics/c2.png new file mode 100644 index 0000000..c78cf66 Binary files /dev/null and b/src/main/resources/pics/c2.png differ diff --git a/src/main/resources/pics/c3.png b/src/main/resources/pics/c3.png new file mode 100644 index 0000000..556af63 Binary files /dev/null and b/src/main/resources/pics/c3.png differ diff --git a/src/main/resources/pics/dos.png b/src/main/resources/pics/dos.png new file mode 100644 index 0000000..3200712 Binary files /dev/null and b/src/main/resources/pics/dos.png differ diff --git a/src/test/java/RulesTests.java b/src/test/java/RulesTests.java new file mode 100644 index 0000000..f2e870f --- /dev/null +++ b/src/test/java/RulesTests.java @@ -0,0 +1,34 @@ +import com.leflat.jass.common.Card; +import com.leflat.jass.common.Rules; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + + +public class RulesTests { + @Test + public void test_bourg_sec() { + int[] list = {Card.RANK_6, Card.RANK_8, Card.RANK_BOURG, 20, 21, 22}; + List hand = Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList()); + assertFalse(Rules.hasBourSec(hand, Card.COLOR_SPADE)); + + int[] list2 = {Card.RANK_BOURG, 20, 21, 22, 28, 29, 30}; + List hand2 = Arrays.stream(list2).mapToObj(Card::new).collect(Collectors.toList()); + assertTrue(Rules.hasBourSec(hand2, Card.COLOR_SPADE)); + } + + @Test + public void test_has_color() { + int[] list = {1, 3, 10, 12, 20, 30, 31}; + List hand = Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList()); + assertTrue(Rules.hasColor(hand, Card.COLOR_HEART)); + + int[] list2 = {1, 3, 4, 8, 20, 30, 31, 32}; + List hand2 = Arrays.stream(list2).mapToObj(Card::new).collect(Collectors.toList()); + assertFalse(Rules.hasColor(hand2, Card.COLOR_HEART)); + } +} diff --git a/src/test/java/ServerTests.java b/src/test/java/ServerTests.java new file mode 100644 index 0000000..913ba40 --- /dev/null +++ b/src/test/java/ServerTests.java @@ -0,0 +1,74 @@ +import com.leflat.jass.common.Anouncement; +import com.leflat.jass.common.Card; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +public class ServerTests { + @Test + public void card_test() { + var card = new Card(Card.RANK_BOURG, Card.COLOR_SPADE); + assertEquals(2, card.getValue()); + assertEquals(20, card.getValue(Card.COLOR_SPADE)); + assertEquals(Card.COLOR_SPADE, card.getColor()); + assertEquals(Card.RANK_BOURG, card.getRank()); + assertEquals("bourg de pique", card.toString()); + assertEquals(5, card.getNumber()); + var card2 = new Card(12); + assertEquals(Card.RANK_NELL, card2.getRank()); + assertEquals(Card.COLOR_HEART, card2.getColor()); + } + + @Test + public void anouncement_test() { + var card = new Card(Card.RANK_DAME, Card.COLOR_CLUB); + var anouncement = new Anouncement(Anouncement.FIFTY, card); + assertEquals("cinquante à la dame de trèfle", anouncement.toString()); + assertEquals(50, anouncement.getValue()); + } + + @Test + public void find_square_test() { + int[] list = {5, 9, 12, 14, 19, 23, 24, 32}; + var annoucements = Anouncement.findAnouncements(Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList())); + assertEquals(1, annoucements.size()); + var anouncement = annoucements.get(0); + assertEquals(anouncement.getType(), Anouncement.BOURG_SQUARE); + assertEquals(anouncement.getCard().getNumber(), 5); + } + + @Test + public void find_suit_test() { + int[] list = {5, 9, 12, 13, 14, 19, 20, 21, 22, 24, 32}; + var annoucements = Anouncement.findAnouncements(Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList())); + assertEquals(2, annoucements.size()); + var firstAnouncement = annoucements.get(0); + assertEquals(firstAnouncement.getType(), Anouncement.THREE_CARDS); + assertEquals(firstAnouncement.getCard().getNumber(), 14); + var secondAnouncement = annoucements.get(1); + assertEquals(secondAnouncement.getType(), Anouncement.FIFTY); + assertEquals(secondAnouncement.getCard().getNumber(), 22); + } + + @Test + public void find_stoeck_test() { + int[] list = {5, 9, 12, 13, 14, 19, 20, 21, 22, 24, 25}; + assertFalse(Anouncement.findStoeck(Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList()), Card.COLOR_HEART)); + assertTrue(Anouncement.findStoeck(Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList()), Card.COLOR_DIAMOND)); + } + + @Test + public void card_sort_test() { + int[] list = {20, 30, 1, 3, 15, 12, 8, 35, 34}; + List hand = Arrays.stream(list).mapToObj(Card::new).collect(Collectors.toList()); + Card.sort(hand); + for (int i=1; i