import java.io.*; import java.lang.*; import java.awt.*; import java.applet.*; import SkipBo; import InputFrame; /* This class provides the interface to the card game. It draws the cards, interprets mouse clicks as game commands, and manages window to get info to and from the players. The most important feature is the gamestate array. This array holds all the visible card values from the build stacks and the from the current player's hand and stacks. It is used to paint the cards and it is used by the computer player in decision making. The gamestate is updated each time a command is processed. */ public class SkipBoWrapper extends Applet { static final int cardheight = 67; static final int cardwidth = 47; static final int x_space = 50; static final int x_offset = 0; static final int offset = 26; static boolean first_instance = true; protected SkipBo game; protected InfoFrame infowindow = new InfoFrame(); protected InputFrame inputwindow = new InputFrame(this); protected Font f = new Font("TimesRoman",Font.BOLD,20); protected Font f2 = new Font("TimesRoman",Font.BOLD,16); protected Image img[] = new Image[15]; protected MediaTracker tracker; int gamestate[] = new int [14]; boolean firstclick = true; boolean gamestarted = false; boolean gameover; char command; int index1, index2; public void init () /* sets the visual attributes of the applet and adds two buttons. Two information windows are created and displayed ( one is a help window, the other is for player input ). The MediaTracker is used to oversee the loading of images. It prevents the applet from continuing until all the images are completly loaded. This prevents annoying repaint effects in the beginning. */ { if (first_instance) { tracker = new MediaTracker(this); loadImages(img); this.setBackground(Color.white); this.setForeground(Color.blue); this.setFont(f); Button help = new Button ("Help"); this.add(help); Button restart = new Button ("Restart"); this.add(restart); infowindow.resize(550,650); } gameover = false; infowindow.show(); inputwindow.show(); first_instance = false; } public boolean action (Event evt, Object what) { String label = (String)what; if (evt.target instanceof Button) { if (label.equals ("Help")) { if (!infowindow.isShowing ()) infowindow.show (); return true; } else if (label.equals ("Restart")) { this.stop(); this.init(); return true; } } return false; } public boolean mouseDown (Event evt, int x, int y) /* this function maps a mouse click to a particular card or a no card zone. Each card is painted at specific coordinates. This function checks for a match to those coordinates. It is broken into two sections: a firstclick and secondclick. The first click on a valid card position sets a command character and saves the index of the card relative to its hand or stack. The second click adds the destination of card. The playCommand function is called if the destination was valid. */ { int i; Integer junk = new Integer (0); //maps click to a card in the hand if (firstclick && gamestarted) { if (180 <= y && y <= 180 + cardheight) { for (i = 0; i < 5; i++) { if (i*50 <= x && x <= i*50+47) { command = 'h'; index1 = i; firstclick = false; this.showStatus("Click on your destination."); return true; } } } //maps click to the store stack else if (255 <= y && y <= 255 + cardheight) { if (100 <= x && x <= 167) { command = 's'; firstclick = false; this.showStatus("Click on your destination."); return true; } } //maps click to one of the discard stacks else if (330 <= y && y <= 330 + cardheight) { for (i = 0; i < 4; i++) { if (i*50+26 <= x && x <= i*50+47+26) { command = 'd'; index1 = i; firstclick = false; this.showStatus("Click on your destination."); return true; } } } } //end of firstclick //beginning of second click, passes only a valid destination //if first click was in the hand then either a build stack or a discard //stack can be the destination. //maps second click to a build stack else if(!firstclick && gamestarted) { if (50 <= y && y <= 50 + cardheight) { for (i = 0; i < 4; i++) { if (i*50+26 <= x && x <= i*50+47+26) { index2 = i; firstclick = true; this.showStatus("Destination selected"); //determines where first click was and call appropriate function if (command == 's') gameover = game.playCommand(index2, gamestate); else gameover = game.playCommand(command, index1, index2, gamestate); repaint(); return true; } } } //maps second click to the hand, an invalid play so logic is reset else if (180 <= y && y <= 180 + cardheight) { for (i = 0; i < 5; i++) { if (i*50 <= x && x <= i*50+47) { command = 'p'; firstclick = true; this.showStatus("Play Reset."); return true; } } } //maps second click to store stack, an invalid play so logic is rest else if (255 <= y && y <= 255 + cardheight) { if (100 <= x && x <= 167) { command = 'p'; firstclick = true; this.showStatus("Play Reset."); return true; } } //maps second click to a discard stack, a valid play to fisnish the turn else if (330 <= y && y <= 330 + cardheight) { for (i = 0; i < 4; i++) { if (i*50+26 <= x && x <= i*50+47+26) { //if first click was in the hand, then change to command to discard if (command == 'h') { command = 'f'; index2 = i; this.showStatus("Destination selected"); gameover = game.playCommand(command, index1, index2, gamestate); repaint(); } else { this.showStatus ("Play Reset."); } firstclick = true; return true; } } } //default click resets the logic else { this.showStatus("Play reset"); firstclick = true; } return true; } //end of second click repaint(); return true; } public void startGame (int storesize, String str1, String str2) /* provides interface for input window. Passes user input along to create a new game. */ { game = new SkipBo (storesize, str1, str2, gamestate); gamestarted = true; repaint(); } public void paint (Graphics g) /* paints each card at a specific x,y coordinate. The value of the card is gotten from the gamestate array. The card value is an integer that is used as the index to the array of card images. For example, the first build stack is represented by gamestate[0]. if gamestate[0] == 1, then image[1] is drawn (image[1] is a picture of an ace). */ { Color color; if (gameover) color = Color.lightGray; else color = Color.white; //draws the global build stacks then a extra large space g.drawImage(img[gamestate[0]], offset+0*x_space, 50, color, this); g.drawImage(img[gamestate[1]], offset+1*x_space, 50, color, this); g.drawImage(img[gamestate[2]], offset+2*x_space, 50, color, this); g.drawImage(img[gamestate[3]], offset+3*x_space, 50, color, this); g.drawString("Build Stacks", 226, 88); //draws name of current player once the game starts if (gamestarted) g.drawString(game.getName(), 0, 170); //draws the player's hand g.drawImage(img[gamestate[4]], 0*x_space, 180, color, this); g.drawImage(img[gamestate[5]], 1*x_space, 180, color, this); g.drawImage(img[gamestate[6]], 2*x_space, 180, color, this); g.drawImage(img[gamestate[7]], 3*x_space, 180, color, this); g.drawImage(img[gamestate[8]], 4*x_space, 180, color, this); g.drawString("Hand", 250, 218); //draws the player's store stack (centered) g.drawImage(img[gamestate[9]], 2*x_space+x_offset, 255, color, this); g.drawString("Store Stack", 150, 293); //draws the player's discard stacks g.drawImage(img[gamestate[10]], offset+0*x_space, 330, color, this); g.drawImage(img[gamestate[11]], offset+1*x_space, 330, color, this); g.drawImage(img[gamestate[12]], offset+2*x_space, 330, color, this); g.drawImage(img[gamestate[13]], offset+3*x_space, 330, color, this); g.drawString("Discard Stacks", 226, 368); } private void loadImages (Image img[]) /* the codebase is used to build a string that provides a URL path to each image. The images are loading into an array according to their values. This function will not return until all cards are loaded. */ { int i; String str = new String(); img[0] = this.getImage(this.getCodeBase(), "images/back.gif"); img[1] = this.getImage(this.getCodeBase(), "images/14c.gif"); for (i = 2; i < 14; i++) { str = "images/" + i + "c.gif"; img[i] = this.getImage(this.getCodeBase(), str); } img[14] = this.getImage(this.getCodeBase(), "images/joker.gif"); for (i = 0; i < 15; i++) { tracker.addImage(img[i], i); } for (i = 0; i <15; i++) { //MediaTracker waits for all this.showStatus("Loading image " + i); //images to load before try tracker.waitForID(i); //continuing catch (InterruptedException e); } for (i = 0; i < 14; i++) { //causes all cards to be displayed gamestate[i] = i; //before the game starts } } public void stop () { inputwindow.hide(); inputwindow.dispose(); infowindow.hide(); infowindow.dispose(); if (game != null) game.dispose(); } }//end of class definition