Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 2272fb4a authored by Jérôme Euzenat's avatar Jérôme Euzenat
Browse files

Created API for strategy; Cleaned up ClassGraphiSession

* An API for user defined agents has been created
- introducing interface ClassPlayer
- implementing AbstractClassPlayer from most of ClassPlayerAgent
- providing MyClassPlayer as an example
- the BitSets used for representing sets of cards have been 'abstracted' info CardSets which can expose Cards
- Card (which are actually integer representing their position in BitSets) shows features
- AbstractClassPlayer also offers access to the environment
- This is documented in INTERFACE.MD

* ClassGraphiSession was a copy of ClassSession with various modifications
- whatever I found to relocate has been relocated in ClassSession
- this involves quite some reorganisation, but seems to work
parent 56f495e0
Branches
No related tags found
No related merge requests found
Showing
with 838 additions and 370 deletions
# Agent interface for implementing _Class?_ strategies
## Purpose
It is possible to implement your own strategy for playing _Class?_.
For that purpose it suffices to implement a player class and to tell the program to use it.
In principle, the interface to implement is very simple (two methods to implement and, in fact, only one).
In reality, implementing an accurate strategy may be quite complex.
In the end, we suggest that you start with the provided example and try to improve it progressively.
For the time being, it is only proposed to implement the behaviour of the guesser (who do not have access to the used classification).
This may change if requested.
## The interface to be implemented
It can deal with its cards through:
~~~~
public class MyClassPlayer extends AbstractClassPlayer implements ClassPlayer {
/* To do for playing your turn (this has to be implemented) */
@Override
public void playGame( ClassGame game ) throws Exception { ... }
/* To do when notified of the issue of a turn (this has to be implemented, but may be left empty) */
@Override
public void acceptNotice( ClassGame game ) { ... }
/* To do when receiving new cards (initially, upon creating new classes, as penalty) */
@Override
public void receiveCards( CardSet cards ) { super.receiveCards( cards ); ... }
/* To do when releasing cards upon your successful turn */
@Override
public void releaseCards( CardSet crds ) { super.releaseCards( crds ); ... }
}
~~~~
The ```receiveCards``` and ```releaseCards``` methods are launched when new cards are added (at the beginning to create the initial hand, or as penalties for creating a new class or for an incorrect play) or retrieved (a correct play) from the hand of the player.
These methods are already implemented in the ```AbstractClassPlayer``` in order to automatically update the necessary structure of the player.
It is thus not necessary to override them, and advised to call them through super if overriding them.
The ```AbstractClassPlayer``` also implements direct access to the necessary structures, i.e. its hand (set of card) and the set of classes on the table:
~~~~
public interface ClassPlayer {
/* The set of cards in the hand of the player */
CardSet getHand();
/* The id */
int getId();
/* How many classes are there on the table */
int getCurrentClassNumber()
/* What are the cards of class cl */
CardSet getCurrentClassCards( int cl )
}
~~~~
So, they can be consulted when playing.
The ```acceptNotice``` method provides at each turn the information about what has been played, by whom and if it was correct or not.
This belongs to the ```ClassGame``` interface (see below).
A player who pays attention to what happens will certainly have to perform some action here.
Finally, the main method to implement a strategy is the ```playGame``` method.
It receives a ```ClassGame``` object to which the player must set:
* the class in which to play (identified by its index or -1 if a new class has to be created);
* the cards to be played to that class.
This is done with the ```play``` method of the ```ClassGame``` interface.
## The interfaces that can be used
Three interfaces are used for describing what happens during the game.
### ClassGame
```ClassGame``` represents one turn of the game:
~~~~
public interface ClassGame {
/* Playing cards in class cl (-1 for a new class) */
public void play( CardSet cards, int cl );
/* the cards played */
public CardSet getCards();
/* the class played (-1 for a new class)*/
public int getAssigned();
/* the player id */
public int getPlayerId()
/* the correctness or incorrectness of the turn */
public boolean getIssue();
}
~~~~
### CardSet
```CardSet``` is a set of cards:
~~~~
public interface CardSet extends Iterable<Card> {
/* Number of available cards */
final static int NBCARDS;
/* Number of cards in the set */
public int size();
/* does the set includes the card */
public boolean includes( Card card );
/* does the set includes the cards */
public boolean includes( CardSet cards );
/* add a card to a set */
public void addCard( Card card );
/* add cards to a set */
public void addCards( CardSet cards );
}
~~~~
It is possible to iterate on the cards of a ```CardSet``` by:
~~~~
CardSet cs;
for( Card c: cs ) {
...
}
~~~~
### Card
```Card``` is just a card.
~~~~
public interface Card {
/* the card with these values */
public Card( Feature.Number number, Feature.Filling filling, Feature.Shape shape, Feature.Color color );
public Feature.Number getNumber();
public Feature.Filling getFilling();
public Feature.Shape getShape();
public Feature.Color getColor();
}
~~~~
## Example
Here is a fully working example of a player who plays the first cards it has not played yet to the first available class and if none, create a new class:
~~~~
package fr.inria.moex.classapp;
import java.util.Properties;
public class MyClassPlayer extends AbstractClassPlayer implements ClassPlayer {
public MyClassPlayer( ClassEnvironment e, int id ) {
super( e, id );
System.out.println( "Created player "+getId() );
}
// To records where cards have been played
private CardSet[] cache;
public MyClassPlayer init( Properties params ) {
super.init( params );
cache = new CardSet[CardSet.NBCARDS]; // creates a far too large cache
System.out.println( "Initialised player "+getId() );
return this;
}
@Override
public void playGame( ClassGame game ) throws Exception {
System.out.print( "Player "+getId()+" plays" );
// Try something
int nbClasses = getCurrentClassNumber();
CardSet crds = new CardSet();
for ( int cl=0; cl < nbClasses; cl++ ) { // Iterate on classes
// It is possible to look into the class through
// getCurrentClassCards( cl )
// If cache not ready initialise it
if ( cache[cl] == null ) cache[cl] = new CardSet();
for ( Card crd: getHand() ) { // Iterate on cards in the hand
if ( !cache[cl].includes( crd ) ) { // If not played in class
crds.addCard( crd ); //
game.play( crds, cl ); // play this card to this class
cache[cl].addCard( crd );// cache it
System.out.println( " card "+printCard( crd )+" to class "+cl );
return; // we only play one card
}
}
} // Apparently, all cards have been played in all classes
for ( Card crd: getHand() ) {
crds.addCard( crd ); // add the first card
game.play( crds, -1 ); // play it in a new class
// it will be a success, we do not need to cache it
System.out.println( " card "+printCard( crd )+" to new class " );
return;
}
}
// The issue of each move is notified
@Override
public void acceptNotice( ClassGame game ) {
if ( game.getPlayerId() == getId() ) {
if ( game.getIssue() ) {
System.out.println( "This was correct" );
} else {
System.out.println( "This was not correct" );
}
}
}
@Override
public void receiveCards( CardSet cards ) {
super.receiveCards( cards ); // will put the received cards in the hand
System.out.println( "Player "+getId()+" receiced cards: " );
for ( Card crd : cards ) { // print each cards characteristics
System.out.println( " "+printCard( crd ) );
}
}
@Override
public void releaseCards( CardSet cards ) {
super.releaseCards( cards ); // Will put the played cards out of the hand
}
private String printCard( Card crd ) {
return crd.getNumber()+"-"+crd.getColor()+"-"+crd.getFilling()+"-"+crd.getShape();
}
}
~~~~
## You can try it
The example belongs to the distribution so you can try it.
Either in command line:
~~~~
$ java -jar lib/classapp/classapp.jar -Dplayer=fr.inria.moex.classapp.MyClassPlayer -DnbRuns=1 -DnbAgents=3 -DnbInitCards=1
~~~~
or graphically:
~~~~
$ java -Duser.language=fr -Dlog.level=INFO -jar lib/classapp/classgui.jar -Dplayer=fr.inria.moex.classapp.MyClassPlayer -DnbRuns=1 -DnbAgents=4 -DnbInitCards=2 -Dinteractive
~~~~
Here you play against them so it should be easy, right?
Notice that we have to launch the game with only three players receiving one card!
The reason is that this strategy is so bad that if they start with more cards, the knower will always win
(if the knower were playing like these agents, i.e. blindly, then the players will exhaust the deck with the penalties they receive).
Can you do better?
......@@ -41,4 +41,9 @@ In both cases the same arguments may be passed:
- interactive: if there is an interactive agent (that'll be you in command line)
- hints: present a synthetic view of the current state of the game
## Programming interface
There is a [simple API](INTERFACE.md) with which you may implement your own strategies!
## [TODOs](TODO.md)
......@@ -10,7 +10,7 @@
- Add a class for running automatic games and collecting statistics (testing benefits of strategies, training learners...).
- To replay (currently some code is here for storing and replaying games but this is not fully implemented):
- reload classif (easy)
- reload deck!
- reload deck! (this is only the seed)
- reload initial service
## GUI
......@@ -20,26 +20,26 @@
- Implement change of parameters
- Make card and classes reorganisable
- Terrible colors (?)
- Show... and guess, classification
- Show classification
- Guess classification
## Misc
- Networked, multi-players server?
- Making it browser/smartphone app?
- Extending it to all games of the _Class?_ curriculum
- Write a program that: Given a board; Allow user to ask some questions (is this a class); Guess the classification
- Providing an API for others to implement their strategies
- Add licenses (should be GPL 2.1 / CeCCIL-?)
## NOTES
### SVG Library (2022-08-13)
Cards are rendered from SVG. The ClassCard class has been implemented with three of them with the aim of reducing the application footprint:
Cards are rendered from SVG. The ClassCard class has been implemented with three SVG libraries with the aim of reducing the application footprint:
* batik (1.14, 4MB, works)
* jsvg (0.3.0, 300KB, works but slightly less neat than batik)
* SVG Salamander (1.1.3, 312KB, does not print well fillings)
The three implementations are available in the ClassCard code, but only batik is used (and only its libs loaded).
The three implementations are available in the ClassCard code, but only batik is used (and only its jars loaded).
The relatively large footprint in the classgui Jar seems anyway provided by our svg cards!
The relatively large footprint in the classgui Jar seems anyway due to our svg cards!
Even if it is only text, it is clear that it could largely be rationalised.
......@@ -104,9 +104,20 @@ public abstract class AbstractClassPlayer implements ClassPlayer {
return cards.cardinality();
}
public CardSet getCards() {
/**
* These are here for facilitating the API
**/
public CardSet getHand() {
return cards;
}
public int getCurrentClassNumber() {
return env.nbClasses();
}
public CardSet getCurrentClassCards( int cl ) {
return env.getCards( cl );
}
/**
* TO IMPLEMENT
......@@ -114,11 +125,19 @@ public abstract class AbstractClassPlayer implements ClassPlayer {
public abstract void acceptNotice( ClassGame game );
public abstract void receiveCards( CardSet crds );
public void receiveCards( CardSet crds ) {
// Add them to cards
cards.addCards( crds );
logger.debug( PlayClass.getString( "i13" ), envid, knower?"*":"", crds.toPatternList() );
}
public abstract CardSet releaseCards( ClassGame turn );
public void releaseCards( CardSet crds ) {
// Suppress cards from own lot
cards.removeCards( crds );
// return these
}
public abstract void playGame( int remaining, ClassGame game ) throws Exception;
public abstract void playGame( ClassGame game ) throws Exception;
/***
* THIS IS NOT PART OF THE INTERFACE
......@@ -143,7 +162,7 @@ public abstract class AbstractClassPlayer implements ClassPlayer {
protected void printHand( PrintStream os ) {
os.print( PlayClass.getString( "i15" ) );
for ( int i = cards.nextSetBit(0); i >= 0; i = cards.nextSetBit(i+1)) {
os.print( "\t"+Card.displayPattern( i ) );
os.print( "\t"+Card.toPattern( i ) );
}
os.println();
}
......@@ -161,7 +180,7 @@ public abstract class AbstractClassPlayer implements ClassPlayer {
}
for ( int i = cards.nextSetBit(0); i >= 0; i = cards.nextSetBit(i+1)) {
os.println();
os.print( Card.displayPattern( i )+"\t" );
os.print( Card.toPattern( i )+"\t" );
for ( int cl = 0; cl < nbClasses; cl++ ) { // classes on the table
// memory
CardSet wrong = env.getWrongs( cl );
......
......@@ -31,11 +31,15 @@ public class Card {
public static int NBFEATURES = Feature.NBFEATURES;
public static int NBVALUES = 3;
public Card() {
}
public Card() {}
public Card( String color, String number, String shape, String filling ) {
public Card( Feature.Number number, Feature.Shape shape, Feature.Filling filling, Feature.Color color ) {
this();
card = 0;
card += featureEncoding( Feature.NUMBER.ordinal(), number.ordinal() );
card += featureEncoding( Feature.SHAPE.ordinal(), shape.ordinal() );
card += featureEncoding( Feature.FILLING.ordinal(), filling.ordinal() );
card += featureEncoding( Feature.COLOR.ordinal(), color.ordinal() );
}
/**
......@@ -50,7 +54,7 @@ public class Card {
if ( powers == null ) initPowers(); // Can't we do this at load time?
return powers[feature];
}
private static void initPowers () {
powers = new int[NBFEATURES];
int p = Card.NBVALUES;
......@@ -60,7 +64,6 @@ public class Card {
}
}
// REWRITE EVERYTHING WITH THAT
public static int featureValue( int card, int feature ) {
if ( powers == null ) initPowers(); // Can't we do this at load time?
if ( feature == NBFEATURES-1 ) return card%(powers[feature]);
......@@ -75,38 +78,71 @@ public class Card {
else return powers[feature+1]*value;
}
/** END **/
/**
* internals
* internals
* Cards whihc in the genuine implementation do not have to exist
* are here cached for the API (CardSet iterator)
**/
private int card;
public Card( int i ) {
this();
private static Card[] cardCache;
private static void initCache() {
cardCache = new Card[CardSet.NBCARDS];
}
private Card( int i ) {
card = i;
putCard( i, this );
}
private void putCard( int i, Card crd ) {
if ( cardCache == null ) initCache();
if ( cardCache[i] == null ) cardCache[i] = crd;
}
public static Card getCard( int i ) {
if ( cardCache == null ) initCache();
if ( cardCache[i] == null ) {
return new Card( i ); // it is put in cache
} else {
return cardCache[i];
}
}
public int getRepr() { return card; }
public static int NUMBER = 0;
public static int FILLING = 1;
public static int SHAPE = 2;
public static int COLOR = 3;
public Feature.Number getNumber() {
return Feature.NUMBERS_INDEX[featureValue( card, NUMBER )];
}
public Feature.Filling getFilling() {
return Feature.FILLINGS_INDEX[featureValue( card, FILLING )];
}
public Feature.Shape getShape() {
return Feature.SHAPES_INDEX[featureValue( card, SHAPE )];
}
public Feature.Color getColor() {
return Feature.COLORS_INDEX[featureValue( card, COLOR )];
//return Feature.COLORS_INDEX[1];
}
public int getRepr() { return card; }
/*
public static String displayCard( int card ) {
int number = env.featureValue( card, 0 );
int filling = env.featureValue( card, 1 );
int shape = env.featureValue( card, 2 );
int color = env.featureValue( card, 3 );
return ""+number+filling+shape+color;
}*/
public static String displayPattern( int c ) {
public static String toPattern( int c ) {
String result = "";
for ( int i=0; i<NBFEATURES; i++ ) {
result += featureValue( c, i );
}
return result;
}
public String displayPattern() {
return displayPattern( card );
public String toPattern() {
return toPattern( card );
}
public static int patternToInt( String pattern ) {
int result = 0;
if ( pattern.length() != NBFEATURES ) return -1;
......
......@@ -17,27 +17,20 @@
*/
/**
* A tentative cards interface...
* CardSet: a bitset with accessors
* Card: basically an integer representing the card
* The implementation of CardSet is:
* - an extension of BitSet (that can be manipulated as such in internals)
* - a clean API that can be exploited as interface from outside
*/
package fr.inria.moex.classapp;
import java.util.BitSet;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/***
* JE2022: This should become an interator in which to write
* for ( Card card: cards ) {...}
* Would not be bad to also have
* for ( int c: cards ) {...}
* instead of
* for ( int c = cards.nextSetBit(0); c >= 0; c = cards.nextSetBit(c+1)) {...}
**/
public class CardSet extends BitSet {
public class CardSet extends BitSet implements Iterable<Card> {
final static int NBCARDS = (int)Math.pow( Card.NBVALUES, Feature.NBFEATURES );
......@@ -79,12 +72,23 @@ public class CardSet extends BitSet {
public void addCards( CardSet cards ) {
or( cards );
}
public void removeCards( CardSet cards ) {
andNot( cards );
}
public int size() {
return cardinality();
}
public Iterator<Card> iterator() {
return new CardSetIterator( this );
}
public String toPatternList() {
String result = "{";
for ( int i=0; i < NBCARDS; i++ ) {
if ( get( i ) ) {
result += " "+Card.displayPattern( i );
result += " "+Card.toPattern( i );
/*
result += " ";
result += (number+1);
......@@ -112,3 +116,25 @@ public class CardSet extends BitSet {
return result+" }";
}
}
/**
* Specific BitSet iterator for Cards
**/
class CardSetIterator implements Iterator<Card> {
private int currentIndex = 0;
private BitSet bitset;
CardSetIterator( CardSet bs ){
bitset = bs;
currentIndex = bitset.nextSetBit(0);
}
public boolean hasNext(){
return ( currentIndex >= 0 ); // != -1 );
}
public Card next() {
Card card = Card.getCard( currentIndex );
currentIndex = bitset.nextSetBit( currentIndex+1 );
return card;
}
}
......@@ -23,7 +23,6 @@ import java.io.PrintStream;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -36,8 +35,6 @@ import org.slf4j.LoggerFactory;
public class ClassEnvironment {
final static Logger logger = LoggerFactory.getLogger( ClassEnvironment.class );
private Random rand = null;
protected static int NBFEATURES = Feature.NBFEATURES;
protected static int NBCARDS = CardSet.NBCARDS;
......@@ -51,6 +48,19 @@ public class ClassEnvironment {
Classification board;
/**
* Deck
*/
Deck deck;
public int drawCard() throws Exception {
return deck.drawCard();
}
public CardSet drawCards( int nb ) throws Exception {
return deck.drawCards( nb );
}
/**
* Number of levels in classification (-DnbLevels)
*/
......@@ -79,45 +89,6 @@ public class ClassEnvironment {
return board;
}
/**
* Deck: a CardSet used as a BitSet
*/
// The deck is just the (non ordered) card set...
CardSet deck;
public void initDeck() {
deck = new CardSet();
logger.debug( PlayClass.getString( "i12" ) );
}
public boolean inDeck( int card ) {
return !deck.get(card); // indeck if false
}
/**
* Cards draws from the deck
*/
public int drawCard() throws Exception { // draw values between 0 and 80
// Check that it is not empty
int card = deck.nextClearBit( rand.nextInt( NBCARDS ) );
if ( card > NBCARDS-1 ) card = deck.nextClearBit( 0 );
if ( card > NBCARDS-1 ) throw new Exception( PlayClass.getString( "i16" ) );
deck.flip(card); // out of deck
return card;
}
// Leave then as String for the moment,
// they should be preserved as numbers...
public CardSet drawCards( int nb ) throws Exception {
CardSet cards = new CardSet();
for ( int i = nb; i > 0; i-- ) {
cards.addCard( drawCard() );
}
return cards;
}
/**
* Table: the set of classes featured on the table
*/
......@@ -399,7 +370,7 @@ public class ClassEnvironment {
}
public ClassEnvironment init( Properties param ) throws Exception {
rand = new Random(); // could use setSeed( long seed );
deck = new Deck();
classes = new Vector<CardSet>();
leaves = new Vector<CardSet>();
samediff = new Vector<int[]>();
......@@ -448,7 +419,7 @@ public class ClassEnvironment {
os.print( " "+PlayClass.getString( "cl" )+" "+cl+":" );
CardSet classcards = getCards( cl );
for ( int i = classcards.nextSetBit(0); i >= 0; i = classcards.nextSetBit(i+1)) {
os.print( "\t"+Card.displayPattern( i ) );
os.print( "\t"+Card.toPattern( i ) );
}
os.println();
}
......
......@@ -75,6 +75,10 @@ public class ClassGame {
return player;
}
public int getPlayerId() {
return player.getId();
}
public boolean getIssue() {
return issue;
}
......
......@@ -56,7 +56,7 @@ public interface ClassPlayer {
public int nbCards();
public CardSet getCards();
public CardSet getHand();
/**
* Playing interface
......@@ -66,8 +66,8 @@ public interface ClassPlayer {
public void receiveCards( CardSet crds );
public CardSet releaseCards( ClassGame turn );
public void releaseCards( CardSet crds );
public void playGame( int remaining, ClassGame game ) throws Exception;
public void playGame( ClassGame game ) throws Exception;
}
......@@ -107,7 +107,8 @@ public class ClassPlayerAgent extends AbstractClassPlayer implements ClassPlayer
return this;
}
public void playGame( int remaining, ClassGame game ) throws Exception {
@Override
public void playGame( ClassGame game ) throws Exception {
nbClasses = env.nbClasses();
if ( knower ) {
......@@ -656,22 +657,16 @@ public class ClassPlayerAgent extends AbstractClassPlayer implements ClassPlayer
return bestClass;
}
// The issue of each move is notified
public void acceptNotice( ClassGame game ) {
}
public void receiveCards( CardSet crds ) {
// Add them to cards
cards.or( crds );
logger.debug( PlayClass.getString( "i13" ), envid, knower?"*":"", crds.toPatternList() );
}
@Override
public void acceptNotice( ClassGame game ) {}
public CardSet releaseCards( ClassGame turn ) {
// Suppress cards from own lot
cards.andNot( turn.getCards() );
// return these
return turn.getCards();
}
/*
@Override
public void receiveCards( CardSet crds ) {}
@Override
public void releaseCards( CardSet crds ) {}
*/
// Use our compact notation?
public void guessClassification( ) {
......
......@@ -29,6 +29,8 @@ import java.util.Iterator;
import java.util.Properties;
import java.util.Random;
import java.lang.reflect.Constructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -57,20 +59,33 @@ public class ClassSession {
/**
* Number of agents to play (-DnbAgents)
*/
private int numberOfAgents = 3;
protected int numberOfAgents = 3;
/**
* Number of agents to play (-DnbInitCards)
*/
private int NBINITCARDS = 8;
protected int NBINITCARDS = 8;
/**
* D (-Dinteractive)o I create an interactive player
*/
private int INTERACT = 0;
protected int INTERACT = 0;
/**
* For printing out information
*/
private PrintStream os = System.out;
public void setOutput( PrintStream stream ) {
os = stream;
}
/**
* -D player = fullclassname
* This class should be available in the environment and implement ClassPlayer
**/
private String playerClassName = "fr.inria.moex.classapp.ClassPlayerAgent";
/**
* Subdirectories for saving data
*/
......@@ -78,25 +93,40 @@ public class ClassSession {
File initDir = null;
File finalDir = null;
/**
* Where (and if) to save games to
*/
// Where (and if) to save games to
File saveGames = null;
/**
* Where (and if) to load games from
*/
// Where (and if) to load games from
String loadGames = null;
protected ClassEnvironment env = null;
public ClassSession() {}
protected int player;
protected ClassPlayer knower;
protected ClassPlayer lastInteractivePlayer; // JE2022: for the gui
public void setOutput( PrintStream stream ) {
os = stream;
public ClassEnvironment getEnvironment() {
return env;
}
public ClassPlayer getLastInteractivePlayer() {
return lastInteractivePlayer;
}
public int getNumberOfAgents() {
return numberOfAgents;
}
public ClassPlayer[] getAgents() {
return agents;
}
public ClassSession() {}
public void init( Properties param ) throws Exception {
if ( param.getProperty( "player" ) != null ) {
playerClassName = param.getProperty( "player" );
}
if ( param.getProperty( "nbAgents" ) != null ) {
numberOfAgents = Integer.parseInt( param.getProperty( "nbAgents" ) );
} else { // Set the default for sub processes
......@@ -150,24 +180,64 @@ public class ClassSession {
// Create agents
agents = new ClassPlayer[numberOfAgents];
// Draw randomly the knower
Random agentFinder = new Random(); // could use setSeed( long seed );
player = agentFinder.nextInt( numberOfAgents );
for ( int ag = 0; ag < numberOfAgents; ag++ ) {
agents[ag] = new ClassPlayerAgent( ((ClassEnvironment)env), ag );
if ( ag == player ) {
agents[ag] = new ClassPlayerAgent( env, player );
} else {
agents[ag] = createAgent( env, ag );
}
agents[ag].init( param );
}
knower = agents[ player ];
knower.setKnower( "Yes" ); // Useless
// Save and log
initSaveAgents();
env.logInit(); // TODO Code qui sert à rien
env.logInit();
}
/**
* Player creation
**/
private Constructor<?> playerConstructor;
private ClassPlayer createAgent( ClassEnvironment env, int id ) throws Exception {
//return new ClassPlayerAgent( env, id );
try {
if ( playerConstructor == null ) {
Class<?> playerClass = Class.forName( playerClassName );
Class<?>[] cparams = { ClassEnvironment.class, int.class };
playerConstructor = playerClass.getConstructor(cparams);
}
Object[] mparams = { env, id };
return (ClassPlayer)playerConstructor.newInstance( mparams );
} catch ( Exception ex ) {
logger.error( "Cannot create players {}", playerClassName );
throw ex;
}
}
public ClassPlayer[] getAgentTable() {
return agents;
}
private int player;
private ClassPlayer knower;
/**
* Classification
**/
private Classification classif = null;
/**
*
**/
public void initSession() throws Exception {
Random agentFinder = new Random(); // could use setSeed( long seed );
// Save and log
PrintWriter prGames = null;
if ( saveGames != null ) {
try {
......@@ -196,17 +266,14 @@ public class ClassSession {
// These should be the number of levels and leaves (it is also stored in env...)
classif = env.genBoard();
logger.debug( PlayClass.getString( "i11" ), classif );
// Draw randomly the knower
player = agentFinder.nextInt( numberOfAgents );
knower = agents[ player ];
knower.setKnower( "Yes" ); // TODO Le "Yes" n'est pas utilisé
// Choose randomly those interactive agents
for ( int i = 0; i < INTERACT; i++ ) {
int interactive = agentFinder.nextInt( numberOfAgents );
while ( interactive == player || agents[interactive].isInteractive() ) interactive = agentFinder.nextInt( numberOfAgents );
agents[interactive].setInteractive();
lastInteractivePlayer = agents[interactive]; // JE2022: for the gui
}
// - distribute cards (ask environment)
env.initDeck();
for ( int ag = 0; ag < numberOfAgents; ag++ ) {
agents[ag].receiveCards( env.drawCards( NBINITCARDS ) );
}
......@@ -215,46 +282,14 @@ public class ClassSession {
logger.debug( PlayClass.getString( "i14" ), env.getCards(0) );
}
protected ClassPlayer currentPlayer;
protected int iteration;
public void process() throws Exception {
initSession();
// Loop
ClassPlayer currentPlayer = null;
int iteration = 0;
iteration = 0;
while( true ) {
iteration++;
// ag.playGame( iteration, turn );
currentPlayer = agents[player];
ClassGame turn = new ClassGame( currentPlayer );
/* TODO Ici le joueur choisi une liste de cartes à jouer ainsi qu'une
* classe sur laquelle jouer. Si c'est un joueur humain il faudra faire
* mes modifs pour passer par l'interface.*/
printPlayer( currentPlayer );
currentPlayer.playGame( iteration, turn );
if ( turn.newClass() ) currentPlayer.receiveCards( env.drawCards( 1 ) );
if ( os != null ) {
printTurn( turn );
}
// Check the knower anyway!
//if ( currentPlayer != knower ) {
if ( knower.judgeTurn( turn ) ) {
turn.setIssue( true );
printIssue( "a1" );
currentPlayer.releaseCards( turn );
env.notify( turn );
} else {
turn.setIssue( false );
printIssue( "a1" );
currentPlayer.receiveCards( env.drawCards( 1 ) );
env.notify( turn );
}
//} else { // assuming the knower knows what it does
//turn.setIssue( true );
//logger.info( " ***SUCCESS*** " );
//env.assignCards( turn.getAssigned(), currentPlayer.releaseCards( turn ) );
//}
for ( int ag = 0; ag < numberOfAgents; ag++ ) {
agents[ag].acceptNotice( turn );
}
playCore();
// if no card, then exit
if ( currentPlayer.nbCards() == 0 ) break;
player++;
......@@ -289,6 +324,41 @@ public class ClassSession {
finalSaveAgents();
}
public ClassGame playCore() throws Exception {
iteration++;
currentPlayer = agents[player];
ClassGame turn = new ClassGame( currentPlayer );
printPlayer( currentPlayer );
// Play
currentPlayer.playGame( turn );
logger.debug( PlayClass.getString( "turninfo" ), currentPlayer.getId(), turn.getCards().toPatternList(), turn.getAssigned() );
// Decide
turnIssue( turn );
return turn;
}
public void turnIssue( ClassGame turn ) throws Exception {
// New class penalty
if ( turn.newClass() ) currentPlayer.receiveCards( env.drawCards( 1 ) );
printTurn( turn );
// Check the knower anyway!
if ( knower.judgeTurn( turn ) ) {
turn.setIssue( true );
printIssue( "a1" );
env.notify( turn );
currentPlayer.releaseCards( turn.getCards() );
} else {
turn.setIssue( false );
printIssue( "a2" );
env.notify( turn );
currentPlayer.receiveCards( env.drawCards( 1 ) );
}
// Notify the agents
for ( int ag = 0; ag < numberOfAgents; ag++ ) {
agents[ag].acceptNotice( turn );
}
}
/**
* Creates the directory necessary for saving sessions
*/
......
/*
* Copyright (C) INRIA, 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package fr.inria.moex.classapp;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class defines the deck of cards
* It extends CardSet, but the bit is set to true when the card is _not_ in the set
*/
public class Deck extends CardSet {
final static Logger logger = LoggerFactory.getLogger( Deck.class );
private Random rand = null;
public Deck() {
rand = new Random(); // could use setSeed( long seed );
logger.debug( PlayClass.getString( "i12" ) );
}
// These should be cancelled: there is no reason to look into the deck
public boolean includes( int c ) {
return !get( c ); // indeck if false
}
/**
* Cards draws from the deck
*/
public int drawCard() throws Exception { // draw values between 0 and 80
// Check that it is not empty
int card = nextClearBit( rand.nextInt( NBCARDS ) );
if ( card > NBCARDS-1 ) card = nextClearBit( 0 );
if ( card > NBCARDS-1 ) throw new Exception( PlayClass.getString( "i16" ) );
flip( card ); // out of deck
return card;
}
public CardSet drawCards( int nb ) throws Exception {
CardSet cards = new CardSet();
for ( int i = nb; i > 0; i-- ) {
cards.addCard( drawCard() );
}
return cards;
}
}
......@@ -34,4 +34,16 @@ public enum Feature {
if ( random == null ) random = new Random();
return values()[random.nextInt(NBFEATURES)];
}
/* Return the right order! */
public static enum Number { I, II, III };
public static enum Filling { FILLED, HATCHED, EMPTY };
public static enum Shape { SQUARE, TRIANGLE, CIRCLE };
public static enum Color { RED, BLUE, GREEN };
public static Number[] NUMBERS_INDEX = Number.values().clone();
public static Filling[] FILLINGS_INDEX = Filling.values().clone();
public static Shape[] SHAPES_INDEX = Shape.values().clone();
public static Color[] COLORS_INDEX = Color.values().clone();
}
/*
* Copyright (C) INRIA, 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package fr.inria.moex.classapp;
import java.util.Properties;
public class MyClassPlayer extends AbstractClassPlayer implements ClassPlayer {
public MyClassPlayer( ClassEnvironment e, int id ) {
super( e, id );
System.out.println( "Created player "+getId() );
}
private CardSet[] cache;
public MyClassPlayer init( Properties params ) {
super.init( params );
//String strat = params.getProperty( "classStrategy" );
cache = new CardSet[CardSet.NBCARDS]; // creates a far too large cache
System.out.println( "Initialised player "+getId() );
return this;
}
@Override
public void playGame( ClassGame game ) throws Exception {
System.out.print( "Player "+getId()+" plays" );
// Try something
int nbClasses = getCurrentClassNumber();
CardSet crds = new CardSet();
for ( int cl=0; cl < nbClasses; cl++ ) { // Iterate on classes
// It is possible to look into the class through
// getCurrentClassCards( cl )
// If cache not ready initialise it
if ( cache[cl] == null ) cache[cl] = new CardSet();
for ( Card crd: getHand() ) { // Iterate on cards in the hand
if ( !cache[cl].includes( crd ) ) { // If not played in class
crds.addCard( crd ); //
game.play( crds, cl ); // play this card to this class
cache[cl].addCard( crd );// cache it
System.out.println( " card "+printCard( crd )+" to class "+cl );
return; // we only play one card
}
}
} // Apparently, all cards have been played in all classes
for ( Card crd: getHand() ) {
crds.addCard( crd ); // add the first card
game.play( crds, -1 ); // play it in a new class
// it will be a success, we do not need to cache it
System.out.println( " card "+printCard( crd )+" to new class " );
return;
}
}
// The issue of each move is notified
@Override
public void acceptNotice( ClassGame game ) {
if ( game.getPlayerId() == getId() ) {
if ( game.getIssue() ) {
System.out.println( "This was correct" );
} else {
System.out.println( "This was not correct" );
}
}
}
@Override
public void receiveCards( CardSet cards ) {
super.receiveCards( cards ); // will put the received cards in the hand
System.out.println( "Player "+getId()+" receiced cards: " );
for ( Card crd : cards ) { // print each cards characteristics
System.out.println( " "+printCard( crd ) );
}
}
@Override
public void releaseCards( CardSet cards ) {
super.releaseCards( cards ); // Will put the played cards out of the hand
}
private String printCard( Card crd ) {
return crd.getNumber()+"-"+crd.getColor()+"-"+crd.getFilling()+"-"+crd.getShape();
}
}
......@@ -113,7 +113,7 @@ public class PlayClass {
protected Properties parameters = null;
/**
* The number of experiments to be run (-DnbRuns=)
* The number of sessions to be run (-DnbRuns=)
*/
private int nbRuns = 5;
......@@ -216,7 +216,7 @@ public class PlayClass {
logger.debug( getString( "i3" ) );
// Initialize (already done here with the parsed parameters)
init( parameters );
// Run expe
// Run session
process();
}
......@@ -261,16 +261,16 @@ public class PlayClass {
if ( loadDir != null ) {
parameters.setProperty( "loadRunDir", loadDir.toString()+"/"+i );
}
ClassSession expe = new ClassSession();
System.err.println( expe );
ClassSession session = new ClassSession();
// create save directory
if ( saveDir != null ) {
parameters.setProperty( "runDir", saveDir.toString()+"/"+i ); // could be better...
}
expe.init( parameters );
session.init( parameters );
session.initSession();
logger.debug( getString( "i9" ), i );
expe.process();
session.process();
}
return;
}
......
......@@ -137,7 +137,8 @@ pwon = Player {} won.
# debug
bot = A bot is playing : {}\\nIteration \#{}
turninfo = Player {} played {}
bot = Iteration \#{}: Automatic player
inter = Iteration \#{}: Interactive player
turninfo = Player {} played {} on class {}
move = \ added card : {} in position {} ({},{})
......@@ -136,8 +136,9 @@ pwon = Le joueur {} a gagné.
# debug
bot = Un \'bot\' joue : {}\\nTour \#{}
turninfo = Le joueur {} a joué {}
bot = Tour \#{}: joueur automatique
inter = Tour \#{}: joueur interactif
turninfo = Le joueur {} a joué {} sur la classe {}
move = \ ajouté la carte : {} en position {} ({},{})
......@@ -29,35 +29,13 @@ import fr.inria.moex.classapp.ClassEnvironment;
import fr.inria.moex.classapp.ClassGame;
import fr.inria.moex.classapp.CardSet;
import fr.inria.moex.classapp.ClassPlayer;
import fr.inria.moex.classapp.ClassPlayerAgent;
import fr.inria.moex.classapp.ClassSession;
import fr.inria.moex.classapp.PlayClass;
/**
* @author Nathan Lufuluabo
*
* On dcidera ici de ne pas passer par une boucle dans
* process() mais de faire des appels rcursifs ou
* dclenchs par un click de l'utilisateur de
* la mthode play(int, BitSet).
*/
public class ClassGraphicSession extends ClassSession {
final static Logger logger = LoggerFactory.getLogger( ClassGraphicSession.class );
/**
* Number of agents to play (-DnbAgents)
*/
private int numberOfAgents = 4;
/**
* Number of agents to play (-DnbInitCards)
*/
private int NBINITCARDS = 8;
/**
* D (-Dinteractive)o I create an interactive player
*/
private int INTERACT = 1;
/**
* Delay between play
*/
......@@ -65,106 +43,32 @@ public class ClassGraphicSession extends ClassSession {
//private int LAGDELAY = 10*1000; // this is in milliseconds
private ClassGui gui;
private ClassPlayer[] agents;
private int iteration;
private int player;
private ClassPlayer knower;
private ClassPlayer currentPlayer;
private ClassPlayer lastInteractivePlayer;
private ClassGame currentTurn;
public ClassGraphicSession( ClassGui gui ) {
super();
setOutput( null );
this.gui = gui;
}
/**
* Modification du type de l'attribut {@code agents}
* et suppression de quelques blocs if non ncessaires.
*/
@Override
public void init( Properties params ) {
try {
super.init( params ); // This reads and creates everything
if ( params.getProperty( "LagDelay" ) != null ) {
LAGDELAY = Integer.parseInt( params.getProperty( "LagDelay" ) ) * 1000;
}
agents = getAgentTable();
numberOfAgents = agents.length;
initSession();
} catch (Exception ex) {
logger.error( ex.getMessage() ); // printStackTrace is also possible...
// JE: Replay does not work because at that point, the panels have not been initialised (there is a problem of order)
gui.showErrorWarning( ex );
}
}
public Properties getParameters() {
//Properties params = super.getParameters();
Properties params = new Properties();
params.setProperty( "nbAgents", String.valueOf( numberOfAgents ) );
params.setProperty( "nbInitCards", String.valueOf( NBINITCARDS ) );
System.err.println( "Le knower is **** "+knower );
/* JE2022: This is implementation specific
if ( knower != null ) {
System.err.println( knower+" --> "+knower.getStrategy() );
params.setProperty( "classStrategy", knower.getStrategy() );
params.setProperty( "classKnowerStrategy", knower.getKnowerStrategy() );
}*/
if ( env != null ) {
params.setProperty( "nbLeaves", String.valueOf( env.numberOfLeaves() ) );
params.setProperty( "nbLevels", String.valueOf( env.numberOfLevels() ) );
@Override
public void init( Properties params ) throws Exception {
super.init( params ); // This reads and creates everything
if ( params.getProperty( "LagDelay" ) != null ) {
LAGDELAY = Integer.parseInt( params.getProperty( "LagDelay" ) ) * 1000;
}
// params.setProperty( "nbRuns", );
params.setProperty( "interactive", String.valueOf( INTERACT ) );
//params.setProperty( "hints", );
params.setProperty( "LagDelay", String.valueOf( LAGDELAY/1000 ) );
params.setProperty( "Language", PlayClass.getLocale().getLanguage() );
return params;
}
// initSession is different from that of ClassSession
public void initSession() throws Exception {
/* TODO Recoder sans la boucle infinie
* et penser appeler setActivePlayer() pour
* le HandPanel. */
//initSaveAgents();
//env.logInit(); // TODO Code qui sert rien
Random agentFinder = new Random(); // could use setSeed( long seed );
// Init
// - create board (ask environment)
env.genBoard();
// Draw randomly the knower
player = agentFinder.nextInt( numberOfAgents ); // Field
knower = agents[ player ]; // Field
knower.setKnower( "Yes" ); // TODO Le "Yes" n'est pas utilis
for ( int i = 0; i < INTERACT; i++ ) {
int interactive = agentFinder.nextInt( numberOfAgents );
while ( interactive == player || agents[interactive].isInteractive() ) interactive = agentFinder.nextInt( numberOfAgents );
agents[interactive].setInteractive();
lastInteractivePlayer = agents[interactive];
}
// - distribute cards (ask environment)
env.initDeck();
for ( int ag = 0; ag < numberOfAgents; ag++ ) {
agents[ag].receiveCards( env.drawCards( NBINITCARDS ) );
}
// Fields
super.initSession();
iteration = 0;
currentPlayer = agents[player]; // Le 1er joueur est le knower
// Should draw the initial card...
env.assignCards( -1, env.drawCards( 1 ) );
}
currentPlayer = knower; // Le 1er joueur est le knower
}
/**
* Class used for processing plays with delay.
* JE2022: This works as expected but seems to cause badly diplayed cards sometimes...
* To investigate.
*/
**/
class WaitingThread extends Thread {
private int cl;
......@@ -183,79 +87,47 @@ public class ClassGraphicSession extends ClassSession {
}
public void run () {
session.playCompCore( cl, cards );
try {
session.playCore( cl, cards );
Thread.sleep( LAGDELAY );
} catch ( Exception ex ) {
ex.printStackTrace();
} catch ( InterruptedException iex ) {
iex.printStackTrace();
gui.showErrorWarning( iex );
}
}
}
/**
* The method called by ClassGUI
* Here it switches between delayed or not
*
* @param cl
* @param cards
* @throws Exception
*/
public void play( int cl, CardSet cards ) throws Exception {
if ( LAGDELAY > 0 ) { // If we use a delay
WaitingThread thread = new WaitingThread( cl, cards, this );
thread.start();
} else {
playCore( cl, cards );
playCompCore( cl, cards );
}
}
/**
* The method that plays a turn (inspired from ClassSession)
*
* @param cl
* @param cards
* @throws Exception
*/
public void playCore( int cl, CardSet cards ) throws Exception {
/* This simply allow to connect the playCore to the rest */
public void playCompCore( int cl, CardSet cards ) {
try {
logger.debug( PlayClass.getString( "bot" ), !currentPlayer.isInteractive(), iteration );
iteration++;
if (currentPlayer.isInteractive()) {
lastInteractivePlayer = currentPlayer;
currentTurn = new ClassGame( currentPlayer, cards, cl );
} else {
currentTurn = new ClassGame( currentPlayer );
currentPlayer.playGame( iteration, currentTurn );
}
if ( currentTurn.newClass() ) currentPlayer.receiveCards( env.drawCards( 1 ) );
logger.debug( PlayClass.getString( "turninfo" ), currentPlayer, currentTurn );
if ( knower.judgeTurn( currentTurn ) ) {
currentTurn.setIssue( true );
currentPlayer.releaseCards( currentTurn );
env.notify( currentTurn );
// Add the played cards to the corresponding class...
int playedClass = currentTurn.getAssigned();
if ( currentTurn.newClass() ) {
// Last class created
playedClass = env.nbClasses()-1;
gui.getTablePanel().addClassToTable( playedClass );
}
// Then add the cards to the corresponding class...
gui.getTablePanel().addCardsToClass( playedClass, currentTurn.getCards() );
} else {
currentTurn.setIssue( false );
currentPlayer.receiveCards( env.drawCards( 1 ) );
env.notify( currentTurn );
}
for ( int ag = 0; ag < numberOfAgents; ag++ ) {
agents[ag].acceptNotice( currentTurn );
}
ClassGame turn = playCore( cl, cards );
if ( currentPlayer.nbCards() == 0 ) {
gui.updateGui( currentTurn );
gui.updateGui( turn );
endSession( currentPlayer );
} else {
player++;
if ( player == numberOfAgents ) player = 0;
currentPlayer = agents[player];
gui.updateGui( currentTurn );
gui.updateGui( turn );
if ( !currentPlayer.isInteractive() ) {
play(-2, null); // Si le joueur suivant est un bot on rappel la mthode
play(-2, null); // Si le joueur suivant est un bot on rappelle la mthode
}
}
} catch (Exception ex) { // Typical empty desk exception
......@@ -264,6 +136,32 @@ public class ClassGraphicSession extends ClassSession {
}
}
/**
* The method that plays a turn (inspired from ClassSession)
* Likely a lot of it should return in it...
*
* @param cl
* @param cards
* @throws Exception
*/
public ClassGame playCore( int cl, CardSet cards ) throws Exception {
iteration++;
ClassGame turn;
// Play
if ( currentPlayer.isInteractive() ) {
logger.debug( PlayClass.getString( "inter" ), iteration );
lastInteractivePlayer = currentPlayer;
turn = new ClassGame( currentPlayer, cards, cl );
} else {
logger.debug( PlayClass.getString( "bot" ), iteration );
turn = new ClassGame( currentPlayer );
currentPlayer.playGame( turn );
}
// Decide
turnIssue( turn );
return turn;
}
public void endSession( ClassPlayer player ) {
logger.debug( "====== {} ======", PlayClass.getString( "endgame" ) );
if ( player.isInteractive() ) {
......@@ -275,26 +173,29 @@ public class ClassGraphicSession extends ClassSession {
}
}
public ClassEnvironment getEnvironment() {
return env;
}
public ClassPlayer getCurrentPlayer() {
return currentPlayer;
}
public ClassPlayer getLastInteractivePlayer() {
return lastInteractivePlayer;
}
public int getNumberOfAgents() {
return numberOfAgents;
}
public ClassPlayer[] getAgents() {
return agents;
}
public ClassGame getCurrentTurn() {
return currentTurn;
/**
* Parameter management for editing these
*/
public Properties getParameters() {
//Properties params = super.getParameters();
Properties params = new Properties();
params.setProperty( "nbAgents", String.valueOf( numberOfAgents ) );
params.setProperty( "nbInitCards", String.valueOf( NBINITCARDS ) );
/* JE2022: This is implementation specific
if ( knower != null ) {
params.setProperty( "classStrategy", knower.getStrategy() );
params.setProperty( "classKnowerStrategy", knower.getKnowerStrategy() );
}*/
if ( env != null ) {
params.setProperty( "nbLeaves", String.valueOf( env.numberOfLeaves() ) );
params.setProperty( "nbLevels", String.valueOf( env.numberOfLevels() ) );
}
// params.setProperty( "nbRuns", );
params.setProperty( "interactive", String.valueOf( INTERACT ) );
//params.setProperty( "hints", );
params.setProperty( "LagDelay", String.valueOf( LAGDELAY/1000 ) );
params.setProperty( "Language", PlayClass.getLocale().getLanguage() );
return params;
}
public boolean isABotPlaying() {
......
......@@ -20,7 +20,6 @@
package fr.inria.moex.classgui;
import java.util.Map.Entry;
import java.util.BitSet;
import java.util.Properties;
import java.net.URL;
import java.net.URI;
......@@ -129,13 +128,14 @@ public class ClassGui extends PlayClass {
public void play() throws Exception {
// This is the content of process...
session = new ClassGraphicSession( this );
logger.debug( "{}", session );
logger.debug( "Here is the current session: {}", session );
session.init( parameters );
session.initSession();
infoPanel.initProperties( session );
// Add initial class to GUI
tablePanel.addClassToTable( 0 );
tablePanel.addCardsToClass( 0, session.getEnvironment().getCards( 0 ) );
// Add initial class to GUI (class 0)
int cl = tablePanel.addClassToTable();
tablePanel.addCardsToClass( cl, session.getEnvironment().getCards( 0 ) );
// JE2022: Does not update the gui???
session.play( -2, null );
......@@ -191,15 +191,11 @@ public class ClassGui extends PlayClass {
public void updateGui( ClassGame lastTurn ) {
handPanel.updateCards();
infoPanel.updateInfos( lastTurn );
tablePanel.updateTable( lastTurn );
infoPanel.updateInfos( lastTurn );
frame.repaint();
}
public void addCardsToClass( int cl, CardSet cards ) {
tablePanel.addCardsToClass( cl, cards );
}
public ClassGraphicSession getSession() {
return session;
}
......@@ -450,7 +446,7 @@ public class ClassGui extends PlayClass {
int nbClasses = env.nbClasses();
// The hand
CardSet hand = session.getLastInteractivePlayer().getCards();
CardSet hand = session.getLastInteractivePlayer().getHand();
int xpos = 1;
int ypos = nbClasses;
if ( hand != null ) {
......@@ -573,6 +569,7 @@ public class ClassGui extends PlayClass {
@Override
public void actionPerformed( ActionEvent e ) {
try {
session = null; // JE2022 useless
playAgain();
} catch (Exception ex) {
ex.printStackTrace();
......@@ -610,6 +607,7 @@ public class ClassGui extends PlayClass {
}
public void showErrorWarning( Exception ex ) {
ex.printStackTrace();
final JDialog modalDialog = new JDialog(frame, PlayClass.getString( "errorname" ),
Dialog.ModalityType.DOCUMENT_MODAL);
Container dialogContainer = modalDialog.getContentPane();
......@@ -634,6 +632,7 @@ public class ClassGui extends PlayClass {
@Override
public void actionPerformed( ActionEvent e ) {
try {
session = null; // JE2022 useless
playAgain();
} catch (Exception ex) {
ex.printStackTrace();
......
......@@ -100,7 +100,7 @@ public class HandPanel extends JPanel {
public void updateCards() {
// On commence par vider la main de ses cartes
cards.clear();
CardSet hand = gui.getSession().getLastInteractivePlayer().getCards();
CardSet hand = gui.getSession().getLastInteractivePlayer().getHand();
if ( hand != null ) {
for ( int c = hand.nextSetBit(0); c >= 0; c = hand.nextSetBit(c+1)) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment