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
}
}
