Listing A. Presentation layer for SET game.
- By Vince Huston
- August 16, 2001
Java Primer
The Game of SET & Software Design
Vince Huston
Listing A. Presentation layer for SET game.
// Presentation layer for SET game
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
public class SetGameGUI extends JPanel implements ActionListener {
private Card[] deckOfCards = new Card[27];
private JFrame parentFrame;
private Border[] border = new Border[2];
private JLabel setsFound = new JLabel( "0" );
private JLabel setsPresent;
private JButton refillSlots = new JButton( "Refill slots" );;
private ArrayList emptySlots = new ArrayList();
private ArrayList selectList = new ArrayList();
private int nextCard = 12, rows = 4;
///// Deal out more cards to fill all empty slots /////
private void refillSlotsHandler() {
JButton btn;
String str;
///// Deal out replacement cards /////
for (int i=0; i < emptySlots.size(); i++) {
if (nextCard > 26) break;
btn = (JButton) emptySlots.get(i);
str = Integer.toString( deckOfCards[nextCard++].getNumber() + 1 );
btn.setIcon( new ImageIcon( str + ".gif" ) );
btn.setActionCommand( str );
}
emptySlots.clear();
///// Compute the number of sets present /////
int numberOfSets = computeSetsPresent();
///// If there are no sets present, then add a new row /////
while ((numberOfSets == 0) && (nextCard < 27)) {
System.out.println( "numberOfSets was 0" );
setLayout( new GridLayout(++rows,3,10,10) );
JButton[] btns = new JButton[3];
for (int i=0; i < 3; i++) {
if (nextCard > 26) break;
str = Integer.toString( deckOfCards[nextCard++].getNumber() + 1 );
btns[i] = new JButton( new ImageIcon( str + ".gif" ) );
btns[i].addActionListener( this );
btns[i].setBorder( border[0] );
btns[i].setActionCommand( str );
add( btns[i] );
}
numberOfSets = computeSetsPresent();
}
setsPresent.setText( Integer.toString( numberOfSets ) );
}
private void handleHighlighting( JButton b ) {
if (selectList.contains( b )) {
b.setBorder( border[0] );
b.repaint();
int index = selectList.indexOf( b );
selectList.remove( index );
return;
}
if (selectList.size() == 3) return;
selectList.add( b );
b.setBorder( border[1] );
b.repaint();
}
private Card findCardInDeck( int in ) {
for (int i=0; i < deckOfCards.length; i++)
if (deckOfCards[i].getNumber() == in) return deckOfCards[i];
return null;
}
private int computeSetsPresent() {
java.awt.Component[] wids = getComponents();
ArrayList arr = new ArrayList();
ArrayList ans = new ArrayList();
int numberOfSets = 0;
///// Create a list of the Cards present (remove empty slots) /////
///// Create a parallel list of offsets for display of the answer /////
for (int i=0, num; i < wids.length; i++) {
num = Integer.parseInt( ((AbstractButton)wids[i]).getActionCommand() );
if (num != 0) {
arr.add( findCardInDeck( num-1 ) );
ans.add( new Integer( i+1 ) );
} }
///// Enumerate all possible combinations. For 12 cards taken 3 at a time /////
///// the number is 220 = 12 * 11 * 10 / 3!. For 6 cards taken 3 at a /////
///// time, the answer is 20 = 6 * 5 * 4 / 3!. /////
Set thisSet;
for (int i=0; i < arr.size() - 2; i++)
for (int j=i+1; j < arr.size() - 1; j++)
for (int k=j+1; k < arr.size(); k++) {
thisSet = new Set( (Card)arr.get(i), (Card)arr.get(j), (Card)arr.get(k) );
if (thisSet.isValid()) {
System.out.print( ans.get(i) +" " +ans.get(j) +" " +ans.get(k) +" " );
numberOfSets++;
} }
if (numberOfSets > 0) System.out.println();
return numberOfSets;
}
/////////////////// MAIN EVENT HANDLER ///////////////////
public void actionPerformed( ActionEvent e ) {
if (e.getSource() == refillSlots) {
refillSlotsHandler();
return;
}
JButton btn = (JButton) e.getSource() ;
if (btn.getActionCommand().equals("0")) return;
handleHighlighting( btn );
if (selectList.size() < 3) return;
Card[] arr = new Card[3];
for (int i=0; i < 3; i++)
arr[i] = findCardInDeck( Integer.parseInt(
((AbstractButton)selectList.get(i)).getActionCommand() ) - 1 );
Set theSet = new Set( arr[0], arr[1], arr[2] );
if (theSet.isValid()) {
for (int i=0, val; i < 3; i++) {
btn = (JButton) selectList.get(i);
btn.setBorder( border[0] );
btn.setIcon( null );
btn.setActionCommand( "0" );
emptySlots.add( btn );
}
String str = setsFound.getText();
setsFound.setText( "" + (Integer.parseInt( str ) + 1) );
setsPresent.setText( Integer.toString( computeSetsPresent() ) );
selectList.clear();
} else
JOptionPane.showMessageDialog( parentFrame, "NOT a set" );
}
public SetGameGUI( JFrame parent ) {
parentFrame = parent;
setLayout( new GridLayout(4,3,10,10) );
border[0] = BorderFactory.createLineBorder( Color.lightGray, 7 );
border[1] = BorderFactory.createLineBorder( Color.black, 7 );
///// Create the domain layer //////
for (int i=0; i < deckOfCards.length; i++)
deckOfCards[i] = new Card();
///// Deal out the first 12 cards /////
JButton[] btn = new JButton[12];
String str;
for (int i=0; i < 12; i++) {
str = Integer.toString( deckOfCards[i].getNumber() + 1 );
btn[i] = new JButton( new ImageIcon( str + ".gif" ) );
btn[i].addActionListener( this );
btn[i].setBorder( border[0] );
btn[i].setActionCommand( str );
add( btn[i] );
}
///// Create the widgets at the bottom of the frame /////
JPanel bottom = new JPanel();
parentFrame.getContentPane().add( bottom, BorderLayout.SOUTH );
bottom.add( new JLabel( "Sets found:" ) );
bottom.add( setsFound );
bottom.add( new JLabel( " " ) );
bottom.add( new JLabel( "Sets present:" ) );
setsPresent = new JLabel( Integer.toString( computeSetsPresent() ) );
bottom.add( setsPresent );
bottom.add( new JLabel( " " ) );
refillSlots.addActionListener( this );
bottom.add( refillSlots );
}
public static void main( String[] args ) {
JFrame f = new JFrame( "Set" );
f.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } );
f.getContentPane().add( new SetGameGUI( f ) );
f.pack();
f.setLocation( 40, 40 );
f.setVisible( true );
} }