Teoria dei Giochi

Dama Italiana

  Checkers.java


Implementazione della parte grafica

Costruttore

Implementazione del gioco
switch_toMove

 

Codice



//******************************************************************************
// Checkers.java:	Applet
// (C)opyright 1997 Victor Huang and Sung Ha Huh. All rights reserved.
//******************************************************************************
import java.applet.*;
import java.awt.* 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Vector;

import javax.swing.JApplet;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;


  Indice
//==============================================================================
// Main Class for applet Checkers
//
//==============================================================================
/**
  *	Classe principale per la creazione dell'applet e la gestione del gioco. 
  *	Con il costruttore della classe si disegna la board.
  *	Con il metodo switch_toMove si gestiscono i turni di gioco per il giocatore bianco e nero,
  *	invocando gli opportuni metodi.
  */
public class Checkers extends Applet
{

//	I) Definizione dei campi utilizzati dalla classe Checkers

// 	I.1) Costanti

	static final int MOSSEPATTA=400;			// indica il numero massimo di mosse per la patta

	static final int WHITE = 1;				// numero identificativo per la pedina bianca
	static final int BLACK = 2;				// numero identificativo per la pedina nera
	static final int WKING = 3;				// numero identificativo per la dama bianca
	static final int BKING = 4;				// numero identificativo per la dama nera
	static final int EMPTY = 0;				// numero identificativo per la casella vuota
	static final int PATTA = -1;				// indica il caso di patta


// 	I.2) Variabili e strutture dati

	int[][] position = new int[8][8];			// board virtuale con lo stato corrente delle pedine

	int contaPATTA=0;					// contatore per il numero di mossa per dichiarare la patta
	int toMove = BLACK;					// contiene il nome di chi gioca (bianco o nero)
	int loser = EMPTY;					// contiene il nome di chi perde, inizialmente nessuno

//	variabili utilizzate per creare la parte grafica dell'applet

	Choice whitePlayer = new Choice();			// per selezionare il giocatore bianco (umano o computer)
	Choice blackPlayer = new Choice();			// per selezionare il giocatore nero (umano o computer)

	Label toMoveLabel = new Label();			// etichetta che indica chi deve giocare

	Choice maxDepthW = new Choice();			// scelta profondita' di ricerca richiesta per il bianco
	Choice maxDepthB = new Choice();			// scelta profondita' di ricerca richiesta per il nero

	Choice bFunVal = new Choice();				// scelta del tipo di funzione di valutazione per il bianco
	Choice nFunVal = new Choice();				// scelta del tipo di funzione di valutazione per il nero

	static TextArea mosseFatte = new TextArea(5,30);	// area di visualizzazione delle mosse

	Button newgameButton, stopButton;			// bottone di inizio e fine gioco
	Label messaggio;					// etichetta per messaggi


	boolean running;					// flag che indica se si sta giocando
	boolean giocoIniziato;					// flag per indicare se il gioco e' iniziato

	Board board = new Board(this);				// cotruzione di un oggetto di tipo board


  Indice
// II) Costruttore della classe
	/**
	  * Checkers Class Constructor.
	  * Si definisce la grafica dell'applet
	  */
	public Checkers(){

		setBackground(Color.white);			// imposto il colore

	// - Creazione del messaggio di new game		
		messaggio = new Label("Press NEW GAME to start."); // etichetta di inizio gioco

	// - Creazione del bottone di new game
		newgameButton = new Button("New game");	
		newgameButton.addActionListener(new ActionListener(){	// gestione evento associato al bottone
			public void actionPerformed(ActionEvent event){
				Checkers.mosseFatte.setText("");	// azzero le mosse fatte dall'area di visualizzazione
				contaPATTA=0;				// azzero il contatore della patta

				start();				// invoco il metodo start

				giocoIniziato=true;			// imposto a vero il flag di inzio gioco
				resetBoard();				// resetto la board, disengnando quella inziale
				toMove=BLACK;				// imposto che il primo giocatore che deve giocare ' il nero

				if (whitePlayer.getSelectedIndex() == 1 && toMove == WHITE){ // controllo giocatore bianco
					toMove = BLACK;			// imposto il giocatore
					switch_toMove();		// invoco il metodo di gestione della partita
				}else if ( blackPlayer.getSelectedIndex() == 1 && toMove == BLACK){
					toMove = WHITE;			// imposto il giocatore
					switch_toMove();		// invoco il metodo di gestione della partita
				}else if ( blackPlayer.getSelectedIndex() == 0 && toMove == BLACK) //solo se deve partire il nero umano
					board.mosseInizialiTurno=Move.generate_moves(position,Move.color(toMove)); // genero le mosse iniziali
			}
		});

	// - Creazione del bottone di stop game
		stopButton = new Button("Stop game");		// creazione del bottone di fine gioco
		stopButton.addActionListener(new ActionListener(){ // gestione dell'evento
			public void actionPerformed(ActionEvent event){
				stop();				// invoco metodo di stop
				giocoIniziato=false;		// pongo flag di gioco iniziato a falso
				resetBoard();			// reset della board che viene disegnata come all'inizio
				toMove=BLACK;			// imposto che primo giocatore e' il nero
			}
		});


	// - Definizione delle scelte per maxDepth
		for (int i=2;i<=10;i+=2)
		{
			maxDepthW.addItem(Integer.toString(i));
			maxDepthB.addItem(Integer.toString(i));
		}

		maxDepthW.select(1);				// impostazione di default di maxDepthW
		maxDepthB.select(1);				// impostazione di default di maxDepthB


	// - Definizione del pannello SN: per il giocatore bianco
		JPanel pBianco = new JPanel(new GridLayout(10,1)); // creazione del pannello

		Label whiteLabel = new Label("White ");			// etichetta giocatore bianco
		whiteLabel.setAlignment(Label.RIGHT);			// allineamento dell'etichetta a destra
		
		Label eGiocatore=new Label("Giocatore");		// etichetta per la scelta del giocatore
		whitePlayer.addItem("Human");				// - inserisco nella scelta tipo: giocatore umano 
		whitePlayer.addItem("Computer");			// - inserisco nella scelta tipo: giocatore computer 		whitePlayer.select(1);

		Label eFunzione=new Label("Tipo intelligenza");		// etichetta per la scelta della funzione
		bFunVal.addItem("Originale");				// - funzione originale: EvalOriginale
		bFunVal.addItem("Prima");				// - funzione Priam: EvalPrima
		bFunVal.addItem("Funzione 2");				// - funzione Funzione2: Evaluation2
		bFunVal.addItem("Spettacolo");				// - funzione Spettacolo: EvalSpettacolo
		bFunVal.addItem("SoloPedine");				// - funzione SoloPedine: EvalSoloPedine

		Label sdLabel = new Label("Search Depth");		// etichetta per la scelta della profondita'

		// inserimento delle componenti nel pannello
		pBianco.add(whiteLabel);
		pBianco.add(eGiocatore);
		pBianco.add(whitePlayer);
		pBianco.add(eFunzione);
		pBianco.add(bFunVal);
		pBianco.add(sdLabel);
		pBianco.add(maxDepthW);


	//	- definizione del pannello DX: per il giocatore nero
		JPanel pNero = new JPanel(new GridLayout(10,1));

		Label blackLabel = new Label("Black ");
		blackLabel.setAlignment(Label.LEFT);

		Label eGiocatoreB=new Label("Giocatore");

		blackPlayer.addItem("Human");
		blackPlayer.addItem("Computer");
		blackPlayer.select(1);

		Label eFunzioneB=new Label("Tipo intelligenza");

		nFunVal.addItem("Originale");
		nFunVal.addItem("Prima");
		nFunVal.addItem("Funzione 2");
		nFunVal.addItem("Spettacolo");
		nFunVal.addItem("SoloPedine");
		nFunVal.addItem("Funz2Compl");

		Label sdLabelB = new Label("Search Depth");
		
		// inserimento delle componenti nel pannello
		pNero.add(blackLabel);
		pNero.add(eGiocatoreB);
		pNero.add(blackPlayer);
		pNero.add(eFunzioneB);
		pNero.add(nFunVal);
		pNero.add(sdLabelB);
		pNero.add(maxDepthB);

    //	- definzione dell'area centrale di gioco
		this.board.setSize(900,900);


    //	- definzione dell'area sotto
		Panel pDestra = new Panel(new BorderLayout(10,0));
		this.toMoveLabel.setAlignment(Label.CENTER);

		pDestra.add(pNero,BorderLayout.WEST);
		pDestra.add(Checkers.mosseFatte,BorderLayout.CENTER);
		Panel pBottoni = new Panel();
		pBottoni.add(newgameButton);
		pBottoni.add(stopButton);

		setLayout(new BorderLayout());
		add(pBianco,BorderLayout.WEST);
		add(pDestra,BorderLayout.EAST);
		add(board, BorderLayout.CENTER);
		add(this.toMoveLabel, BorderLayout.SOUTH);
		add(pBottoni, BorderLayout.NORTH);

		giocoIniziato=false;
		repaint();

	}

Indice
	/**
	  * Metodo APPLET INFO SUPPORT.
	  *		The getAppletInfo() method returns a string describing the applet's author.
	  *
    	  */
	public String getAppletInfo()
	{
		return "Name: Checkers\r\n" +
		       "Authors: Elisa Caniato e Mirco Gelain \r\n";
	}

	/**
	  *	The init() method is called by the AWT when an applet is first loaded or
	  *	reloaded.  Override this method to perform whatever initialization your
	  *	applet needs, such as initializing data structures, loading images or
	  *	fonts, creating frame windows, setting the layout manager, or adding UI
	  *	components.
    	  */
	public void init(){
        	resetBoard();
		// TODO: Place additional initialization code here
	}

	/**
	  *	Place additional applet clean up code here.  destroy() is called when
	  *	when you applet is terminating and being unloaded.
	  */
	public void destroy(){

		// TODO: Place applet cleanup code here
	}

	/**
	  *	Metodo per avviare l'applet
	  */
	public void start(){

		running = true;
	}

	/**
	  *	Metodo per terminare l'applet
	  */

	public void stop(){

		running = false;
	}

	/**
	  * Checkers Paint Handler
	  */
	public void paint(Graphics g){

	}

Indice

	/**
	  * 	Metodo che permette di ridisegnare la board, sistemando le pedine nella configurazione inziale di gioco
	  */
	private void resetBoard(){

		this.board.highlight = false;
		this.board.incomplete = false;
		loser = EMPTY;

		// set up checkers
		for (int j=0; j<8; j++)
		{
			for (int i=0; i<8; i++)
				position[i][j] = EMPTY;			// setto la casella inzialmente vuota

			for (int i=0; i<3; i++)				
			if ( possible_square(i,j) )
				position[i][j] = WHITE;			// inserisco le pedine bianche

			for (int i=5; i<8; i++)
			if ( possible_square(i,j) )
				position[i][j] = BLACK;			// inserisco le pedine nere
		}

		this.toMove = BLACK;					// imposto primo giocatore
		updateMoveLabel();					// aggiorno le etichette
		displayBoard();						// visualizzo la board corrispondente
	}

	/**
	  *	Metodo per aggiornare le label.
	  */
	void updateMoveLabel(){

		this.toMoveLabel.setForeground(Color.red);		// si setta colore della scritta dell'etichetta di rosso
		if (this.toMove == WHITE)				// se turno del giocatore bianco
		{
			this.toMoveLabel.setBackground(Color.white);	// setto colore sfondo etichetta di bianco	
			this.toMoveLabel.setText("White to move");	// scrivo il testo
		}
		else
		{
			this.toMoveLabel.setBackground(Color.black);	// si setta colore sfondo dell'etichetta di nero
			this.toMoveLabel.setText("Black to move");	// scrivo il testo 
		}

		// se c'e' un perdente
		if (loser == WHITE)					// se e' il bianco
		{
			this.toMoveLabel.setBackground(Color.black);	// si setta lo sfondo di nero
			this.toMoveLabel.setText("Black wins!");	// si scrive che il giocatore nero ha vinto	
		}
		else if (loser == BLACK)				// se e' il nero
		{
			this.toMoveLabel.setBackground(Color.white);	// si setta lo sfondo di bianco
			this.toMoveLabel.setText("White wins!");	// si scrive che il giocatore bianco ha vinto
		}
		
		// se c'e' la patta
		if (loser == PATTA)
		{
			this.toMoveLabel.setBackground(Color.GREEN);	// si setta sfondo di verde
			this.toMoveLabel.setText("PATTA!");		// si scrive la patta
		}
	}

	/**
	  *	Metodo per visualizzare la board
	  */
	private void displayBoard()
	{
		this.board.paint(this.board.getGraphics());
		Thread.yield();

	}


 >/A>
Indice
	/**
	  *	Metodo centrale che gestisce i giocatori che devono giocare e controlla lo stato della partita, ossia
	  *	se allo stato attuale c'e' un vincitore o la patta, segnalandola in questi casi e terminando la partita,
	  *	continuando il gioco altrimenti.
	  */
	public void switch_toMove()
	{
		int score;					// definizione del punteggio
		Vector result = new Vector();	// definizione del risultato
		int[] counter = new int[1];			// contatore
		Date date;					// definizione dell'oggetto per la gestione del tempo

		counter[0]=0;					// contatore inizialmente a zero

		if(!running) return;				// se non si sta giocando il gioco viene terminato

		if(contaPATTA==MOSSEPATTA){			// si controlla se si e' raggiunta la condizione di patta
			loser = PATTA;				// imposto la patta
			updateMoveLabel();			// aggiorno le etichette
			return;					// termino la partita
		}

		// black just made his move
		displayBoard();					// aggiorno la board
		if (this.toMove == BLACK && whitePlayer.getSelectedIndex()==1){

			this.toMove = WHITE;			// aggiorno il giocatore cui spetta il turno
			updateMoveLabel();			// aggiorno le etichette
			date = new Date();			// creo la variabile per il calcolo del tempo
			long time = date.getTime();		// seleziono il tempo
			score = Engine.MiniMax(position,0,Integer.parseInt(maxDepthW.getSelectedItem()),result,this.toMove,counter, nFunVal.getSelectedIndex(), bFunVal.getSelectedIndex(), board); // valuto la posizione migliore
			date = new Date();			// salvo nuovo tempo
			time = date.getTime() - time;		// calcolo tempo impiegato per scegliere la mossa

			// stampo  l'esito della mossa: punteggio, tempo
			print_status(score,counter[0],time,this.toMove); 

			if (result.size()==0) //se non c'e' nessuna mossa, la destinazione dovrebbe rimanere a (-1, -1)
				loser = WHITE;
			else	// si esegue la mossa
			{
				if(Move.isKing(position[result.elementAt(0)[0]][result.elementAt(0)[1]]))
					this.contaPATTA++;	// si incrementa variabile di patta se si e' mosso una dama	
				else
					this.contaPATTA=0;	// si azzerra la variabile che conta la patta perche' si e' mossa una pedina
				Move.eseguiMossa(position, result, true, this.board);
				
				if (running && loser == EMPTY && blackPlayer.getSelectedIndex()==1)
					switch_toMove();
				this.toMove = BLACK;
			}
		}

		// white just made his move
		else if (this.toMove == WHITE && blackPlayer.getSelectedIndex()==1){

			this.toMove = BLACK;			// aggiorno il giocatore cui spetta il turno
			updateMoveLabel();			// aggiorno le etichette
			date = new Date();			// creo la variabile per il calcolo del tempo
			long time = date.getTime();		// seleziono il tempo
			score = Engine.MiniMax(position,0,Integer.parseInt(maxDepthB.getSelectedItem()),result,this.toMove,counter, nFunVal.getSelectedIndex(),  bFunVal.getSelectedIndex(), board);  // valuto la posizione migliore
			date = new Date();			// salvo nuovo tempo
			time = date.getTime() - time;		// calcolo tempo impiegato per scegliere la mossa

			// stampo  l'esito della mossa: punteggio, tempo
			print_status(score,counter[0],time, this.toMove);

			if (result.size() == 0) //se non c'e' nessuna mossa, la destinazione dovrebbe rimanere a -1 -1
				loser = BLACK;
			else
			{
				if(Move.isKing(position[result.elementAt(0)[0]][result.elementAt(0)[1]]))
					this.contaPATTA++;	// si incrementa variabile di patta se si e' mosso una dama	
				else
					this.contaPATTA=0;	// si azzerra la variabile che conta la patta perche' si e' mossa una pedina
				Move.eseguiMossa(position, result, true, this.board);
				if (running && loser == EMPTY && whitePlayer.getSelectedIndex()==1)
					switch_toMove();
				this.toMove = WHITE;
			}
		}
		else{
		// se non sta giocando il computer:
		//	- si setta il giocatore che deve eseguire la prossima mossa
			if (this.toMove == WHITE)
				this.toMove = BLACK;
			else
				this.toMove = WHITE;
		}

		//	- si generano tutte e sole le mosse possibili per il prossimo giocatore
		board.mosseInizialiTurno=Move.generate_moves(position,Move.color(toMove));

		//	- si controlla se non ci sono piu' mosse possibili, vuol dire che il giocatore attuale ha perso
		if(board.mosseInizialiTurno.size() == 0){
			loser=Move.color(toMove);
		}

		
		if(loser!=EMPTY)
			giocoIniziato=false;

		updateMoveLabel();			// si aggiornano le etichette
		displayBoard();				// si aggiorna la board
	}

	/**
	  *	Metodo per aggiornare la grafica
	  */
	public void update(Graphics g){

		paint(g);
	} // update()


	/**
	  *	Metodo che verifica se la casella posizionata e' fra le caselle di gioco
	  */
	boolean possible_square(int i, int j)
	{
		return (i+j)%2 == 0;
	}


	/**
	  *	Metodo che stampa lo stato del gioco, indicando chi sta giocando, il punteggio, il tempo impiegato e velocita'
	  */
	void print_status(int score, int positions, long time, int player)
	{
		System.out.print("Player: ");
		System.out.print(player);
		System.out.print("\tScore: ");
		System.out.print(score);
		System.out.print("\tPos : ");
		System.out.print(positions);
		System.out.print("\tTime : ");
		System.out.print(time);
		System.out.print("\tSpeed: ");
		if (time == 0) System.out.print(0);
		else System.out.print(positions*1000/time);
		System.out.println(" pos/sec");
	}

}