Fancy Joust
<< Joust | LabTrailIndex | LightsOut >>
For basic version see Joust
The working demo is here
These sound and image files need to be in your project folder: (Sometimes Eclipse will put these in a different folder. Under Properties select Java Build Path and press the Source Tab Its is easier if the output is in the same folder as all the source files.)
Attach:hit.wav Attach:buzzer.wav
Square.java
Complete the isBurned
method
import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.image.BufferedImage; public class Square { /** * constants */ public static final int black=0; public static final int white=1; public static final int burned=2; /** * instance fields */ private BufferedImage[] img; private Color[] colors= {Color.DARK_GRAY, Color.LIGHT_GRAY, Color.RED}; private int color; private boolean highlighted; private Rectangle box; /** * constructors */ public Square(){ setColor(Square.white); img = new BufferedImage[3]; setHighlighted(false); box=null; } public Square(int color) { this(); //use the default constructor to initialize this.setColor(color); } public Square(int color, Rectangle box) { this(); //use the default constructor to initialize this.setColor(color); this.box=box; } /** * Access Methods */ public int getColor() { return color; } public void setColor(int color) { this.color = color; } public BufferedImage getImg() { return img[color]; } public void setImgArray(BufferedImage blackImg, BufferedImage whiteImg, BufferedImage burnedImg ) { img[0]=blackImg; img[1]=whiteImg; img[2]=burnedImg; } /** * other methods */ public void draw(Graphics g){ if (box==null) return; int w=2;//width of outline int x= (int)box.getX(); int y= (int)box.getY(); int size = (int)box.getHeight(); if (highlighted){ g.setColor(Color.MAGENTA); }else{ g.setColor(Color.BLACK); } g.fillRect(x, y, size, size); if (img[0]==null){ g.setColor(colors[color]); g.fillRect(x+w, y+w, size-2*w, size-2*w); }else{ g.drawImage(img[color], x+w, y+w, x+size-2*w, y+size-2*w, 0, 0, img[color].getWidth(), img[color].getHeight(), null); } } public boolean isHighlighted() { return highlighted; } public void setHighlighted(boolean highlighted) { this.highlighted = highlighted; } /** * given screen location x,y sets the highlight on or off * @param x screen coord * @param y screen coord * @return the Square if highlighted, otherwise null */ public Square select(int x, int y){ this.setHighlighted(box.contains(x,y)); if(this.isHighlighted()) return this; else return null; } public boolean isBurned(){ //your code here } }
Knight.java
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; public class Knight { /** * instance fields */ private BufferedImage img; private int row, col; private String color; public static final String black="\u2658"; //the unicode filled knight letter public static final String white="\u265e"; //the unicode open knight letter /** * constructors */ public Knight() { img=null; color=Knight.white; row=0; col=0; } public Knight(String color){ this(); //use default constructor to initialize fields this.color=color; } public Knight(String color, int row, int col){ this(color); //use other constructor to initialize fields this.row=row; this.col=col; } public Knight(String color, int row, int col, BufferedImage img){ this(color, row, col); this.img=img; } public void draw(Graphics g, Board board){ int size = board.getSquareSize(); int offset = (int)(size/5.0); int x=board.getLeft()+col*size; int y=board.getTop()+(row)*size; if (img==null){ Font font=new Font("Arial Unicode MS", 0, size);//Arial is the most complete for WinXP g.setFont(font); g.setColor(Color.YELLOW); g.drawString(this.getColor(), x, y+size-offset); }else{ int w=2;//width of outline g.drawImage(img, x+w, y+w, x+size-2*w, y+size-2*w, 0, 0, img.getWidth(), img.getHeight(), null); } } public boolean isWhite() { return color==Knight.white; } public boolean isBlack() { return !isWhite(); } public int getRow() { return row; } public void setRow(int row) { this.row = row; } public int getCol() { return col; } public void setCol(int col) { this.col = col; } public String getColor(){ return color; } public void setColor(String color){ this.color=color; } public void setImage(BufferedImage img){ this.img=img; } }
Board.java
complete the isLegalMove
and hasMovesLeft
methods
import java.awt.Graphics; import java.awt.Rectangle; import java.awt.image.BufferedImage; /** * A Joust game board... free to use for educational use * @author Chris Thiel, OFMCap * 30 Sept 2012 * */ public class Board { private int squareSize, top,left; private Square[][] grid; private Square selectedSquare; private int selectedRow, selectedCol; private Knight[] player; private Knight currentPlayer; private String message; public Board(int rows, int cols) { this.setSquareSize(70); grid=new Square[rows][cols]; setTop(20); setLeft(50); setSelectedSquare(null); setSelectedRow(-1); setSelectedCol(-1); setMessage("White's turn"); for (int r=0; r<getNumRows();r++) for (int c=0; c< getNumCols();c++){ int color=(r+c+1)%2;//alternate color int x=left + c*squareSize; int y=top + r*squareSize; Rectangle rectangle=new Rectangle(x,y,squareSize,squareSize); grid[r][c]=new Square(color, rectangle); } player = new Knight[2]; int rand=(int)(getNumCols()*Math.random()); player[0]=new Knight(Knight.white, getNumRows()-1,rand); rand=(int)(getNumCols()*Math.random()); player[1]=new Knight(Knight.black,0,rand); setCurrentPlayer(player[0]); } public Board(int rows, int cols, BufferedImage lightKnight, BufferedImage darkKnight){ this(rows, cols); player[0].setImage(lightKnight); player[1].setImage(darkKnight); } /** * access methods * */ public int getNumRows(){ return grid.length; } public int getNumCols(){ return grid[0].length; } public Square getSquare(int row, int col){ return grid[row][col]; } public int getTop() { return top; } public void setTop(int top) { this.top = top; } public int getLeft() { return left; } public void setLeft(int left) { this.left = left; } public int getSquareSize() { return squareSize; } public void setSquareSize(int squareSize) { this.squareSize = squareSize; } public Knight getCurrentPlayer() { return currentPlayer; } /** * Check if the square at r,c is burned * or occupied by one of the players * @param r * @param c * @return is the square is availible */ public boolean isAvailable(int r, int c){ if (r<0 || c<0 || r>=getNumRows() || c>=getNumCols()) return false; if (grid[r][c].isBurned()) return false; for(int i=0;i<2;i++) if (player[i].getRow()==r && player[i].getCol()==c) return false; return true; } public void setCurrentPlayer(Knight currentPlayer) { this.currentPlayer = currentPlayer; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Square getSelectedSquare() { return selectedSquare; } public void setSelectedSquare(Square selectedSquare) { this.selectedSquare = selectedSquare; } public int getSelectedRow() { return selectedRow; } public void setSelectedRow(int selectedRow) { this.selectedRow = selectedRow; } public int getSelectedCol() { return selectedCol; } public void setSelectedCol(int selectedCol) { this.selectedCol = selectedCol; } /** * other methods */ public void draw(Graphics g){ for (int r=0; r<getNumRows();r++) for (int c=0; c< getNumCols();c++){ grid[r][c].draw(g); } player[0].draw(g, this); player[1].draw(g, this); } public void setHighlight(int x, int y){ for (int r=0; r<getNumRows();r++) for (int c=0; c< getNumCols();c++){ Square s=grid[r][c].select(x, y); if (s!=null) { setSelectedSquare(s); setSelectedRow(r); setSelectedCol(c); } } message="("+selectedRow+", "+selectedCol+") is "; if (isLegalMove(currentPlayer, selectedRow,selectedCol)) message+="legal"; else message+="NOT legal"; } public String getSelected(){ return "("+selectedRow+", "+selectedCol+")"; } public String whoseTurn(){ if (! gameOver() && currentPlayer.isWhite()) return "Whites turn"; if (! gameOver() && currentPlayer.isBlack()) return "Black's turn"; if (hasMovesLeft(player[0])) return "White wins"; return "Black Wins"; } public boolean move(){ boolean result=false; if(gameOver()) return result; if (isLegalMove(currentPlayer, selectedRow, selectedCol)){ grid[currentPlayer.getRow()][currentPlayer.getCol()].setColor(Square.burned); currentPlayer.setRow(selectedRow); currentPlayer.setCol(selectedCol); result=true; if (!gameOver() ){ if (currentPlayer==player[0]) currentPlayer=player[1]; else currentPlayer=player[0]; } } message=whoseTurn(); return result; } /** * Checks if both players have any * available Moves left * @return whether the game is over */ public boolean gameOver(){ for (int i=0;i<2;i++) if (!hasMovesLeft(player[i])) return true; return false; } /** * Using a series of conditional statements * checks to see if the square at r,c * is a valid place to move this knight * @param board * @param r the row in question * @param c the column in question * @return whether the knight can validly go to the square */ public boolean isLegalMove(Knight player, int r, int c) { //your code here int row=player.getRow(); int col=player.getCol(); if (r<0 || c<0 || r>getNumRows() || c>getNumCols()) return false; if (!isAvailable(r, c)) return false; if (r+2==row) if(c+1==col || c-1==col) return true; if (r-2==row) if(c+1==col || c-1==col) return true; if (r+1==row) if(c+2==col || c-2==col) return true; if (r-1==row) if(c+2==col || c-2==col) return true; return false; } public boolean hasMovesLeft(Knight player){ int maxRow=getNumRows(); int maxCol=getNumCols(); int row=player.getRow(); int col=player.getCol(); if (row+2<maxRow ){ if (col+1< maxCol && isAvailable(row+2, col+1)) return true; if (col-1>=0 && isAvailable(row+2, col-1)) return true; } if (row+1<maxRow ){ if (col+2< maxCol && isAvailable(row+1, col+2)) return true; if (col-2>=0 && isAvailable(row+1, col-2)) return true; } if (row-2>=0 ){ if (col+1< maxCol && isAvailable(row-2, col+1)) return true; if (col-1>=0 && isAvailable(row-2, col-1)) return true; } if (row-1>=0 ){ if (col+2< maxCol && isAvailable(row-1, col+2)) return true; if (col-2>=0 && isAvailable(row-1, col-2)) return true; } return false; } }
JoustApplet.java
import java.applet.Applet; import java.applet.AudioClip; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; /** * A applet to hold the Joust Board * and deal with user input * Free for educational use. * @author Chris Thiel, OFMCap * @version 30 Sept 2012 * */ public class JoustApplet extends Applet implements MouseMotionListener, MouseListener { /** * Instance fields for the Game * */ private Board board; private Rectangle restartBtn; /** * These instance field with hold the images for * the squares and knights and sounds */ private AudioClip click,buzzer; private BufferedImage darkSquareImg, lightSquareImg, burnedSquareImg; private BufferedImage darkKnightImg, lightKnightImg; /** * These instance fields are for getting rid of flicker * on the Windows platform-- the Applet will draw the * picture in memory before putting it on the screen */ private Image virtualMem; private Graphics gBuffer; private Font font;//The font for our messages private String message; public void init() { readResources(); board=new Board(5,5, lightKnightImg, darkKnightImg); for (int r=0; r< board.getNumRows();r++) for (int c=0; c<board.getNumCols(); c++) board.getSquare(r, c).setImgArray(darkSquareImg, lightSquareImg, burnedSquareImg); this.restartBtn = new Rectangle (670, 350, 80,40); this.addMouseListener(this); this.addMouseMotionListener(this); font = new Font("Helvetica", Font.BOLD, 18); message="Joust! "+"White"+"'s move"; } /** * On loading the Applet we read the sound and image files * from the java archive (jar file), and play the sounds * to initialize them. */ public void readResources() { try { darkSquareImg = ImageIO.read( getClass().getResource("/darkSquare.png")); lightSquareImg = ImageIO.read( getClass().getResource("/lightSquare.png")); burnedSquareImg = ImageIO.read( getClass().getResource("/burnedSquare.png")); darkKnightImg = ImageIO.read( getClass().getResource("/darkKnight.png")); lightKnightImg = ImageIO.read( getClass().getResource("/lightKnight.png")); } catch (IOException e) { e.printStackTrace(); } click = getAudioClip(getClass().getResource("/hit.wav")); click.play(); buzzer = getAudioClip(getClass().getResource("/buzzer.wav")); buzzer.play(); } public void paint (Graphics g) { //make a new buffer in case the applet size changed virtualMem = createImage(getWidth(),getHeight()); gBuffer = virtualMem.getGraphics(); gBuffer.setColor(Color.WHITE); gBuffer.fillRect(0, 0, this.getWidth(), this.getHeight()); gBuffer.setColor(Color.BLACK); gBuffer.setFont(font); gBuffer.drawString(message, 625, 20); gBuffer.drawString(board.getMessage(), 625, 40); if (board.gameOver()){ gBuffer.setColor(Color.BLUE); gBuffer.fillRect(restartBtn.x, restartBtn.y, restartBtn.width, restartBtn.height); gBuffer.setColor(Color.YELLOW); gBuffer.drawString("Restart", restartBtn.x+10, restartBtn.y+25); } board.draw(gBuffer); g.drawImage(virtualMem,0,0,this);//set new display to Screen } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) { if (board.move()) click.play(); else buzzer.play(); if(board.gameOver()){ if (restartBtn.contains(e.getPoint())){ board=new Board(8,8); repaint(); } buzzer.play(); } repaint(); } @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mouseDragged(MouseEvent e) {} @Override public void mouseMoved(MouseEvent e) { int x=e.getX(); int y=e.getY(); board.setHighlight(x, y); message=board.whoseTurn(); repaint(); } public void update(Graphics g) { paint(g); //get rid of flicker with this method } }