2010-04-14 4 views
1

J'ai eu la tâche d'écrire un jeu simple simulant deux joueurs ramassant 1-3 matchs l'un après l'autre jusqu'à ce que la pile soit partie. J'ai réussi à le faire pour l'ordinateur en choisissant la valeur aléatoire des matchs, mais maintenant je voudrais aller plus loin et permettre aux humains de jouer le jeu. Voici ce que j'ai déjà: http://paste.pocoo.org/show/201761/contrôler le filetage des flux

Class Player est un lecteur d'ordinateur, et PlayerMan doit être un être humain. Le problème est, ce fil de PlayerMan devrait attendre jusqu'à ce que la valeur appropriée des allumettes soit donnée mais je ne peux pas le faire fonctionner de cette manière. La logique est la suivante: le thread s'exécute jusqu'à ce que les correspondances soient égales à zéro. Si le numéro de joueur est correct au moment où la fonction pickMatches() est appelée. Après avoir diminué le nombre de correspondances sur la table, le thread doit attendre et un autre thread doit être notifié. Je sais que je dois utiliser wait() et notify() mais je ne peux pas les placer correctement. Classe partagée conserve la valeur du joueur actuel, ainsi que le nombre de matchs.

public void suspendThread() { 
    suspended = true; 
} 

public void resumeThread() { 
    suspended = false; 
} 

@Override 
public void run(){ 
    int matches=1; 
    int which = 0; 
    int tmp=0; 
    Shared data = this.selectData(); 
    String name = this.returnName(); 
    int number = this.getNumber(); 

    while(data.getMatches() != 0){ 

     while(!suspended){ 

      try{    
       which = data.getCurrent(); 

       if(number == which){ 

        matches = pickMatches(); 

        tmp = data.getMatches() - matches; 
        data.setMatches(tmp, number); 

        if(data.getMatches() == 0){ 
         System.out.println("       "+ 
          name+" takes "+matches+" matches."); 
         System.out.println("Winner is player: "+name); 
         stop(); 
        } 

        System.out.println("       "+ 
          name+" takes "+matches+" matches."); 

        if(number != 0){ 
         data.setCurrent(0); 
        } 
        else{ 
         data.setCurrent(1); 
        } 
       } 
       this.suspendThread(); 
       notifyAll(); 
       wait(); 

      }catch(InterruptedException exc) {}  
     } 
    } 
} 

@Override 
synchronized public int pickMatches(){ 
    Scanner scanner = new Scanner(System.in); 
    int n = 0; 
    Shared data = this.selectData(); 

    System.out.println("Choose amount of matches (from 1 to 3): "); 

     if(data.getMatches() == 1){ 
      System.out.println("There's only 1 match left !"); 
      while(n != 1){ 
       n = scanner.nextInt(); 
      } 
     } 
     else{ 
      do{ 
       n = scanner.nextInt(); 
      } 
      while(n <= 1 && n >= 3); 
     } 
    return n; 
} 

}

+0

@owca trop de code! Essayez de le rendre plus conforme à l'exemple compilable court et autonome (sscce): http://mindprod.com/jgloss/sscce.html – Kiril

Répondre

1

Eh bien, permettez-moi d'abord vous dire que je pense que vous faites ce que vous avez besoin plus résistants à. Si c'était moi, je créerais une classe 'GameMaster' dont le travail consiste à faire une boucle et à dire à chaque joueur quand son tour arrive. Vos classes de joueur n'auraient pas de boucles, juste une méthode takeTurn. De cette façon, vous pouvez supprimer le comportement d'attente/notification de vos classes de joueurs.

Si vous souhaitez garder le design que vous avez, je me débarrasserais toujours de l'attente/notifier et utiliser un Semaphore. Vérifiez les docs pour une utilisation correcte, mais l'essentiel est que vous supprimez les méthodes suspend/resume et avez un appel acquire() en haut de votre boucle et relâchez en bas. Assurez-vous juste que l'équité est définie sur true dans le constructeur, de cette façon vous n'aurez pas à vous inquiéter si un joueur prend deux tours d'affilée en acquérant le verrou de sémaphore deux fois de suite.

1

Lorsque vous vous trouvez avoir à établir une communication entre les threads pour synchroniser leur exécution, juste pour qu'une séquence déterminée les événements se déroulent (comme jouer à tour de rôle à un tour), c'est un bon signe que vous ayez plus de threads que nécessaire.

Dans ce cas, considérez un thread unique qui exécute une méthode takeTurn() sur différentes extensions d'une classe Player, ce qui peut vous faciliter la vie. Vous pouvez faire de Player une classe de base abstraite qui impose .takeTurn(), puis les classes HumanPlayer et MachinePlayer encapsulent le code qui a du sens pour chaque type de joueur à l'intérieur de cette méthode. Cela devrait rendre l'extension à un plus grand nombre de joueurs relativement triviale par rapport à beaucoup de wait() et notify().