In the constructor, how would I represent the top and bottom Diagram parameters with a char[][]?
Casting doesn't work.
public CombineLeftRight(Diagram left, Diagram right, int animationType)
A Constructor that initializes the animationType with the provided parameter value and initializes the board with the diagram resulting from calling TwoDimArrayUtil.appendLeftRight() on the boards associated with the left and right diagrams.
public static char[][] appendLeftRight(char[][] left, char[][] right) {
int numRows = (left.length > right.length) ? left.length : right.length;
int numCols = left[0].length + right[0].length;
char[][] retArray = new char[numRows][numCols];
TwoDimArrayUtil.copyArray(retArray, left, 0, 0);
TwoDimArrayUtil.copyArray(retArray, right, 0, left[0].length);
return retArray;
}
Thank you in advance!
public interface Diagram {
/**
* Returns a two-dimensional array of characters representing a diagram.
*
* #return
*/
public char[][] getBoard();
/**
* Returns the next two-dimensional array of characters to display during an
* animation.
*
* #return
*/
public char[][] nextAnimationStep();
/**
* Number of rows associated with the diagram.
*
* #return
*/
public int getNumberRows();
/**
* Number of columns associated with the diagram.
*
* #return
*/
public int getNumberCols();
}
I am guessing that if your constructor is of this format:
// Constructor
public CombineLeftRight(Diagram left, Diagram right, int animationType){
...
}
Then you need to convert each Diagram into a 2D array of char - something along the lines of
char[][] left2dArr = left.getBoard();
char[][] right2dArr = right.getBoard();
So that you can invoke the static method as you mentioned... like
TwoDimArrayUtil.appendLeftRight(left2dArr, right2dArr);
// or simply
TwoDimArrayUtil.appendLeftRight(left.getBoard(), right.getBoard());
putting it all together (still guessing here as there is not enough code in your question to know for sure), your constructor could look like:
// Constructor
public CombineLeftRight(Diagram left, Diagram right, int animationType){
...
TwoDimArrayUtil.appendLeftRight(left.getBoard(), right.getBoard());
...
}
Related
need some help here. Working on "Classes and Object-Oriented Development" and could use some help with both my logic and code for a question in the textbook.
Question: I am asked to Modify my previous example of my Rectangle class to override the equals() and toString() methods. Two rectangles are equal when they both have the same length and width.
My approach: I tried to change it to do this, and then decided it would be easier to compare by areas, rather than comparing both by width and length, so below is what I have so far. Let me know if you have any ideas to help. There is a previous example of the equals() method that compares a circle's radius but isnt helping when comparing 2 different things. Thanks before hand all ! If your wondering why they are all not their own separate files, I haven't gotten there in the chapter yet so it's alot to look at I know ;P
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package chapter8javaExamples;
/**
*
* #author Eric
*/
public class Rectangle {
private double length, width;
/**
* constructor
* pre: none
* post: A rectangle class is created.
*/
public Rectangle() {
length = 2; //default length
width = 4; //default width
}
/**
* constructor
* pre: none
* post: A rectangle object is created with length and width.
*/
public Rectangle (double l, double w) {
length = l;
width = w;
}
/**
* Changes the length of the rectangle
* pre: none
* post: Length has been changed.
*/
public void setLength (double newLength) {
length = newLength;
}
/**
* Changes the width of the rectangle.
* pre: none
* post: Width has been changed.
*/
public void setWidth (double newWidth) {
width = newWidth;
}
/**
* Returns the length of the rectangle.
* pre: none
* post: The length of the rectangle has been returned.
*/
public double getLength() {
return(length);
}
/**
* Returns the width of the rectangle.
* pre: none
* post: The width of the rectangle has been returned.
*/
public double getWidth() {
return(width);
}
/**
* Returns the area of rectangle
* pre: none
* post: The area of the rectangle is returned
*/
public double area() {
double triArea;
triArea = length * width;
return(triArea);
}
/**
* Returns the perimeter of the rectangle
* pre: none
* post: The perimeter of the rectangle is returned
*/
public double perimeter() {
double triPer;
triPer = length + width + length + width;
return(triPer);
}
/**
* Displays the formula for area of a rectangle.
* pre: none
* post: The formula is displayed.
*/
public static void displayAreaFormula(){
System.out.println("The formula for the area of a rectangle is a=l*w");
}
/**
* Determines if the object is equal to another
* Circle object.
* pre: c is a Circle object.
* post: true has been returned if the objects have
* the same radii, false otherwise.
*/
public boolean equals(Object r) {
Rectangle testObj = (Rectangle) r;
Rectangle testObj2 = (Rectangle) r2;
if (testObj.getArea() == area && testObj2.getArea == area()) {
return(true);
} else {
return(false);
}
}
/**
* Returns a String that represents the Circle object.
* pre: none
* post: A string representing the Circle object has
* been returned.
*/
public String toString(){
String rectangleString;
rectangleString = "Rectangle has the Area " + length*width;
return(rectangleString);
}
/**
*
* #param args
*/
public static void main(String [] args){
Rectangle spot = new Rectangle();
Rectangle spot2 = new Rectangle(5, 9);
System.out.println("Area is: " + spot.area());
System.out.println("Perimeter: " + spot.perimeter());
Rectangle.displayAreaFormula();
}
}
I don't think that comparing the areas is a good idea in the equals method, because a rectangle that is 2x8 would equal a rectangle that is 4x4, because both areas are 16. This contradicts your requirement:
Two rectangles are equal when they both have the same length and width.
Here, your r2 variable is undefined. But beyond that, the equals method shouldn't compare two other objects, it should compare this object to another object.
You should return true if the r object is a Rectangle and this rectangle's length matches the other rectangle's length and this rectangle's width matches the other rectangle's width.
Your equals method should always have the following structure:
public boolean equals(Object r) {
if(r == null || !r instanceof Rectangle) return false;
// rest of the code
}
This is because you don't want to perform operations on a null-reference (which would throws errors), and this can't equals null anyway. Secondly: if r is not an instance of the rectangle class, we can quit before having to perform other operations, because a Rectangle would not equal a String, or a Circle.
Now, to get to your question: if you want to check on equality purely by width and length, I would write the method like this:
public boolean equals(Object r) {
if(r == null || !r instanceof Rectangle) return false;
if(length == r.length && width == w.width) return true;
return false;
}
This compares the width and length. If they are both equal, two rectangles are equal. You are comparing the area, but this could give false positives. Take this example:
Rectangle r1;
Rectangle r2;
r1.width = 10;
r1.length = 5;
r2.width = 5;
r2.length = 10;
Your code would produce a positive, while these rectangles are orientated differently.
Two rectangles are equal when they have both same length and width.
Are these following rectangles the same?
and
Hey! Both have the same area don't they?
So in short, no you have use && to see if the length and breadth of both are equal or you could compare the .toString()s of both rectangles to see if they are exact.
To add to the other answers (read those first)
If you are comparing "physical" objects (a block of wood for example) then you might want to compare length to width and width to length as well. The orientation a user inputs might be submitted differently for two of the same objects. Consider this when reading your requirements.
I've been working on this program for a couple weeks now, adding components to an applet in order to output a simple tic tac toe game. I've gotten some of it to work, but as of now, when you run, all it does is that you click it once, the CPU projects its mark in the upper left corner, and then you can click anywhere else and it automatically says you win. I can't get the CPU to keep playing. I don't expect anyone to tell me what to do, but I'm just confused as to which method I need to work on in order to get the CPU to respond. My professor has left some very helpful pseudocode, but I still don't quite understand. I've been working with the method "gameEnd," checking for winners horizontally, vertically and diagonally to see if that's the source to getting the game to continue beyond just two marks, but it's not working. Anyone got any suggestions? Thanks.
import java.awt.Color;
import java.awt.Event;
import java.awt.Font;
import java.awt.Graphics;
import java.util.Random;
public class TicTacToe extends java.applet.Applet {
// Ignore this constant
private static final long serialVersionUID = 1942709821640345256L;
// You can change this boolean constant to control debugging log output
private static final boolean DEBUGGING = false;
// Constants
// Size of one side of the board in pixels
private static final int BOARD_SIZE_PIXELS = 600;
// Number of squares on one side of the board
private static final int SQUARES = 3;
// Diameter of the circle drawn in each square
private static final int CIRCLE_WIDTH = 90;
// Colors to be used in the game
private static final Color BACKGROUND_COLOR = Color.WHITE;
private static final Color SQUARE_BORDER_COLOR = Color.BLACK;
private static final Color GAME_OVER_MESSAGE_COLOR = Color.BLACK;
private static final Color HUMAN_COLOR = Color.RED;
private static final Color HUMAN_WINNING_COLOR = Color.MAGENTA;
private static final Color CPU_COLOR = Color.BLUE;
private static final Color CPU_WINNING_COLOR = Color.CYAN;
// Status constant values for the game board
private static final int EMPTY = 0;
private static final int HUMAN = 1;
private static final int HUMAN_WINNING = 2;
private static final int CPU = -1;
private static final int CPU_WINNING = -2;
// String displayed when the game ends
private static final String GAME_WIN_MESSAGE = "You win! Click to play again.";
private static final String GAME_LOSE_MESSAGE = "You lose......Click to play again.";
private static final String GAME_DRAW_MESSAGE = "No one wins? Click to play again...";
// Instance variables that control the game
// Whether or not the user just clicked the mouse
private boolean mouseClicked = false;
// Whether or not to start the game again
private boolean restart = false;
// Whether or not the CPU should start playing a move.
// USED ONLY WHEN THE CPU PLAYS FIRST!
private boolean onFirstMove = false;
// The column and row of the SQUARE the user clicked on
private int xMouseSquare; // column
private int yMouseSquare; // row
// The width (and height) of a single game square
private int squareWidth = BOARD_SIZE_PIXELS / SQUARES;
// An array to hold square status values on the board.
// The status values can be EMPTY, HUMAN, CPU or other values
private int[][] gameBoard;
// The column and row of the SQUARE the CPU player will move on
private int xCPUMove;
private int yCPUMove;
// Add the rest of your instance variables here, if you need any. (You won't
// need to, but you may if you want to.)
// Ignore these instance variables
// CPUinMove represents if the CPU is thinking (generating the CPU move).
// If it is true, it means the CPUMove() method is running and no new move
// should be added
private boolean CPUinMove;
// Methods that you need to write:
/*
* Pre: x and y are x-coordinate and y-coordinate where the user just
* clicks. squareWidth is the width (and height) of a single game square.
*
* Post: xMouseSquare and yMouseSquare are set to be the column and row
* where the user just clicked on (depending on x and y).
*
* Hint: You need only two statements in this method.
*/
// Setting MouseSquare equal to x and y divided by the Square Width to create a location for
// the user after clicking
private void setMouseSquare(int x, int y) {
//
xMouseSquare = x/squareWidth;
yMouseSquare = y/squareWidth;
}
/*
* Pre: SQUARES is an int that holds the number of game squares along one
* side of the game board. xSquare is an int such that 0 <= xSquare <
* SQUARES. CIRCLE_WIDTH is an int that holds the diameter of the circle to
* be drawn in the center of a square. squareWidth is an int that holds the
* width and height in pixels of a single game square.
*
* Post: Return the correct x-coordinate (in pixels) of the left side of the
* circle centered in a square in the column xSquare.
*
* Hint: This method should be very simple. What you need to do is to find
* the right equation.
*/
private int getIconDisplayXLocation(int xSquare) {
// This line is an example of using DEBUGGING variable
if (DEBUGGING) {
System.out.println("The input that getIconDisplayXLocation() receives is: " + xSquare);
}
// equation that returns the correct variable in the column xSquare
return squareWidth * xSquare + (squareWidth - CIRCLE_WIDTH)/2;
}
/*
* Pre: SQUARES is an int that holds the number of game squares along one
* side of the game board. ySquare is an int such that 0 <= ySquare <
* SQUARES. CIRCLE_WIDTH is an int that holds the diameter of the circle to
* be drawn in the center of a square. squareWidth is an int that holds the
* width and height in pixels of a single game square.
*
* Post: Return the correct y-coordinate (in pixels) of the top of the
* circle centered in a square in the row ySquare.
*
* Hint: This method should be very simple. What you need to do is to find
* the right equation.
*/
private int getIconDisplayYLocation(int ySquare) {
// This line is an example of using DEBUGGING variable
if (DEBUGGING) {
System.out.println("The input that getIconDisplayYLocation() receives is: " + ySquare);
}
// equation that returns the correct variable in the column ySquare
return squareWidth * ySquare + (squareWidth - CIRCLE_WIDTH)/2;
}
/*
* The instance variable gameBoard will be created and initialized
*
* Pre: SQUARES is set to an int. gameBoard is a 2-dimensional array type
* variable that holds the status of current game board. Each value in the
* array represents a square on the board
*
* Post: gameBoard must be assigned a new 2-dimensional array. Every square
* of gameBoard should be initialized to EMPTY.
*
* Hint: A loop.
*/
private void buildBoard() {
// Setting the two methods equal to local variables, x and y
int x = xMouseSquare;
int y = yMouseSquare;
// This line creates the gameBoard array. You must write several more
// lines to initialize all its values to EMPTY
// Write game board using the equation of three across and down for each column
// Constructs a 3 by 3 array of integers for the board
gameBoard = new int[3][3];
// Initialize variables i and j, set equal to 0; this establishes a connection for loop
for (x = 0; x < 3; x++) {
for (y = 0; y < 3; y++) {
gameBoard[x][y] = EMPTY;
}
}
}
/*
* Returns whether the most recently clicked square is a legal choice in the
* game.
*
* Pre: gameBoard is a 2-dimensional array type variable that holds the
* status of current game board. xSquare and ySquare represent the column
* and row of the most recently clicked square.
*
* Post: Returns true if and only if the square is a legal choice. If the
* square is empty on current game board, it is legal and the method shall
* return true; if it is taken by either human or CPU or it is not a square
* on current board, it is illegal and the method shall return false.
*
* Hint: Should be simple but think carefully to cover all cases.
*/
private boolean legalSquare(int xSquare, int ySquare) {
if (gameBoard[xSquare][ySquare] == EMPTY)
return true;
else return false;
}
/*
* Pre: gameBoard is an array that holds the current status of the game
* board. xSquare and ySquare represent the column and row of the most
* recently clicked square. player represent the current player (HUMAN or
* CPU). This method is always called after checking legalSquare().
*
* Post: Set the square as taken by current player on the game board if the
* square is empty.
*
* Hint: Very simple.
*/
private void setMovePosition(int xSquare, int ySquare, int player) {
player = HUMAN;
player = CPU;
this.xMouseSquare = xSquare;
this.yMouseSquare = ySquare;
}
/*
* Check if HUMAN or CPU wins the game.
*
* Pre: gameBoard is an array to hold square status values on the board. The
* status values can be EMPTY, HUMAN, CPU or other values.
*
* Post: The method will return true if and only if a player wins the game.
* Winning a game means there is at least one row, one column, or one
* diagonal that is taken by the same player. The method does not need to
* indicate who wins because if it is implemented correctly, the winner must
* be the one who just made a move.
*
* Hint: Complicated method. Use loops to shorten your code. Think about how
* to represent "a player takes 3 squares in a row/column/diagonal".
*/
private boolean gameEnd() {
// Setting local variables
int i = 0;
int x = xMouseSquare;
int y = yMouseSquare;
int sw = squareWidth;
int[][] g = gameBoard;
// Checking for a winner
// Checking columns
for (y = 0; y < 3; y++) {
for (x = 0; x < 3; x++) {
i = g[x][y] + i;
}
}
{
// Checking rows
for (x = 0; x < 3; x++) {
for (y = 0; y < 3; y++) {
i = g[x][y] + i;
}
}
}
// Checking first diagonal
{
for (x = 0; x < 3; x++) {
g[x][x] = 3;
}
}
for (x = 1; x < 3; x++) {
g[x][x] = 3;
}
for (x = 2; x < 3; x++) {
g[x][x] = 3;
}
// Checking second diagonal
for (y = 0; y < 3; y++) {
g[y][2 - y] = 3;
}
for (y = 1; y < 3; y++) {
g[y][2 - y] = 3;
}
for (y = 2; y < 3; y++) {
g[y][2 - y] = 3;
}
return true;
}
/*
* Check if the game ends as a draw.
*
* Pre: gameBoard is an array to hold square status values on the board. The
* status values can be EMPTY, HUMAN, CPU or other values. This method is
* always called after gameEnd().
*
* Post: The method will return true if and only if all squares on the game
* board are taken by HUMAN or CPU players (no EMPTY squares left).
*
* Hint: Should be simple. Use loops.
*/
// Value of...
private boolean gameDraw() {
if (squareWidth == (3^2 - 1)) {
}
return true;
}
/*
* Marks circles on the line on which a player wins.
*
* Pre: g is Graphics object that is ready to draw on. HUMAN_WINNING_COLOR
* and CPU_WINNING_COLOR are both Color objects that represent the color to
* show when HUMAN/CPU wins. gameBoard is gameBoard is an array to hold
* square status values on the board. The status values can be EMPTY, HUMAN,
* CPU or other values.
*
* Post: ALL the row(s)/column(s)/diagonal(s) on which a player wins will be
* marked as the special color.
*
* Hint: You must draw a new circle with the special color (to replace the
* old circle) on the square if the square belongs to a winning
* row/column/diagonal. You can change gameBoard because the board will be
* reset after displaying the winning line. You can use helper methods
* (existing ones or your own) to finish this method. Pay attention that
* many functions in this method is similar to gameEnd(). You should think
* about reusing code.
*
* Hint2: This method is not necessary for the game logic. You don't have to
* start it early. Start when you know everything else is correct.
*/
private void markWinningLine(Graphics g) {
// TODO
}
/*
* Generates the next square where the CPU plays a move.
*
* Pre: gameBoard is an array to hold square status values on
* the board. The status values can be EMPTY, HUMAN, CPU or other values.
*
* Post: Set xCPUMove and yCPUMove to represent the column and the row which
* CPU plans to play a move on. The respective square MUST BE EMPTY! It will
* cause a logical error if this method returns a square that is already
* taken!
*
* Hint: Don't start too early -- currently this method works (though
* naively). Make sure that everything else works before touching this
* method!
*/
private void CPUMove() {
// TODO
// The following block gives a naive solution -- it finds the first
// empty square and play a move on it. You can use this method to test
// other methods in the beginning. However, you must replace this block
// with your own algorithms eventually.
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (gameBoard[i][j] == 0) {
xCPUMove = i;
yCPUMove = j;
return;
}
}
}
}
/* Put any helper methods you wish to add here. */
/* You will not need to change anything below this line. */
/*
* DO NOT change this method.
*
* Set the game board to show a new, blank game.
*/
private void wipeBoard(Graphics g) {
g.setColor(BACKGROUND_COLOR);
g.fillRect(0, 0, BOARD_SIZE_PIXELS, BOARD_SIZE_PIXELS);
}
/*
* DO NOT change this method.
*
* Displays a circle on g, of the given color, in the center of the given
* square.
*/
private void displayHit(Graphics g, Color color, int xSquare, int ySquare) {
g.setColor(color);
g.fillOval(getIconDisplayXLocation(xSquare),
getIconDisplayYLocation(ySquare), CIRCLE_WIDTH, CIRCLE_WIDTH);
}
/*
* DO NOT change this method.
*
* This method handles mouse clicks. You will not need to call it.
*/
#Override
public boolean mouseDown(Event e, int xMouse, int yMouse) {
if (isClickable()) {
mouseClicked = true;
setMouseSquare(xMouse, yMouse);
}
repaint();
return true;
}
/*
* DO NOT change this method.
*
* This method handles drawing the board. You will not need to call it.
*/
#Override
public void update(Graphics g) {
paint(g);
}
/*
* DO NOT change this method.
*
* Draws the border between game squares onto canvas. Also, draws the moves
* that are already made.
*/
private void displayGame(Graphics canvas) {
canvas.setColor(SQUARE_BORDER_COLOR);
for (int i = 0; i < BOARD_SIZE_PIXELS; i += squareWidth) {
for (int j = 0; j < BOARD_SIZE_PIXELS; j += squareWidth) {
canvas.drawRect(i, j, squareWidth, squareWidth);
}
}
for (int i = 0; i < SQUARES; i++) {
for (int j = 0; j < SQUARES; j++) {
switch (gameBoard[i][j]) {
case HUMAN:
case HUMAN_WINNING:
displayHit(canvas, HUMAN_COLOR, i, j);
break;
case CPU:
case CPU_WINNING:
displayHit(canvas, CPU_COLOR, i, j);
break;
default:
break;
}
}
}
}
/*
* DO NOT change this method.
*
* This method relays information about the availability of mouse clicking
* in the game. You will not need to call it.
*/
private boolean isClickable() {
return !CPUinMove;
}
/*
* DO NOT change the contents this method.
*
* If this method is changed to public void paint(Graphics canvas), it will
* execute the program with the CPU-first order.
*
* This method is like the "main" method (but for applets). You will not
* need to call it. It contains most of the game logic.
*/
// #Override
public void paint(Graphics canvas) {
displayGame(canvas);
if (mouseClicked) {
if (onFirstMove) {
CPUMove();
setMovePosition(xCPUMove, yCPUMove, CPU);
displayHit(canvas, CPU_COLOR, xCPUMove, yCPUMove);
onFirstMove = false;
} else {
if (restart) {
wipeBoard(canvas);
setUpGame();
repaint();
} else if (legalSquare(xMouseSquare, yMouseSquare)) {
setMovePosition(xMouseSquare, yMouseSquare, HUMAN);
displayHit(canvas, HUMAN_COLOR, xMouseSquare, yMouseSquare);
if (gameEnd()) {
markWinningLine(canvas);
canvas.setFont(new Font("SansSerif", Font.PLAIN, 30));
canvas.setColor(GAME_OVER_MESSAGE_COLOR);
canvas.drawString(GAME_WIN_MESSAGE, squareWidth / 2,
squareWidth);
restart = true;
} else {
CPUinMove = true;
CPUMove();
setMovePosition(xCPUMove, yCPUMove, CPU);
displayHit(canvas, CPU_COLOR, xCPUMove, yCPUMove);
CPUinMove = false;
if (gameEnd()) {
markWinningLine(canvas);
canvas
.setFont(new Font("SansSerif", Font.PLAIN,
30));
canvas.setColor(GAME_OVER_MESSAGE_COLOR);
canvas.drawString(GAME_LOSE_MESSAGE,
squareWidth / 2, squareWidth);
restart = true;
} else if (gameDraw()) {
canvas
.setFont(new Font("SansSerif", Font.PLAIN,
30));
canvas.setColor(GAME_OVER_MESSAGE_COLOR);
canvas.drawString(GAME_DRAW_MESSAGE,
squareWidth / 2, squareWidth);
restart = true;
}
}
}
}
mouseClicked = false;
}
}
/*
* DO NOT change this method.
*
* This method is like the "main" method (but for applets). You will not
* need to call it. It contains most of the game logic.
*/
public void paint_game(Graphics canvas) {
// display the current game board
displayGame(canvas);
// the following block will run every time the user clicks the mouse
if (mouseClicked) { // when the user clicks the mouse
// if the game is ready to start or to be restarted
if (restart) {
// clear the window and set up the game again
wipeBoard(canvas);
setUpGame();
repaint();
}
// else, if the game is in play, check if the click is on a legal
// square
else if (legalSquare(xMouseSquare, yMouseSquare)) {
// if the square is legal, mark the corresponding position as
// taken by HUMAN
setMovePosition(xMouseSquare, yMouseSquare, HUMAN);
// display the new position with a HUMAN_COLOR circle
displayHit(canvas, HUMAN_COLOR, xMouseSquare, yMouseSquare);
// check if the game ends (if it is, HUMAN wins)
if (gameEnd()) {
// if HUMAN wins, mark the winning line as a special color.
markWinningLine(canvas);
// display the human winning message
canvas.setFont(new Font("SansSerif", Font.PLAIN, 30));
canvas.setColor(GAME_OVER_MESSAGE_COLOR);
canvas.drawString(GAME_WIN_MESSAGE, squareWidth / 2,
squareWidth);
// mark the game as ready to restart
restart = true;
} else if (gameDraw()) {
// if HUMAN doesn't win but the board is full, it is a draw
// display the draw message
canvas.setFont(new Font("SansSerif", Font.PLAIN, 30));
canvas.setColor(GAME_OVER_MESSAGE_COLOR);
canvas.drawString(GAME_DRAW_MESSAGE, squareWidth / 2,
squareWidth);
// mark the game as ready to restart
restart = true;
} else {
// if HUMAN doesn't win and the board is not full, the CPU
// is ready to move
CPUinMove = true;
// calculates the next CPU move
CPUMove();
// mark the corresponding position as taken by CPU
setMovePosition(xCPUMove, yCPUMove, CPU);
// display the new position with a CPU_COLOR circle
displayHit(canvas, CPU_COLOR, xCPUMove, yCPUMove);
CPUinMove = false;
if (gameEnd()) {
// if CPU wins, mark the winning line as a special
// color.
markWinningLine(canvas);
// display the human losing message
canvas.setFont(new Font("SansSerif", Font.PLAIN, 30));
canvas.setColor(GAME_OVER_MESSAGE_COLOR);
canvas.drawString(GAME_LOSE_MESSAGE, squareWidth / 2,
squareWidth);
// mark the game as ready to restart
restart = true;
}
// else (if the game is not ended after the CPU move), the
// game is ready to get the next HUMAN move
}
}
mouseClicked = false;
}
}
/*
* DO NOT change this method.
*
* This method initializes the applet. You will not need to call it.
*/
#Override
public void init() {
setSize(BOARD_SIZE_PIXELS, BOARD_SIZE_PIXELS);
setBackground(BACKGROUND_COLOR);
setUpGame();
}
/*
* DO NOT change this method.
*
* Creates a fresh game board and sets up the game state to get ready for a
* new game.
*/
private void setUpGame() {
buildBoard();
CPUinMove = false;
restart = false;
onFirstMove = true;
}
}
I've been given a 2^k * 2^k sized board, and one of the tiles is randomly removed making it a deficient board. The task is to fill the with "trominos" which are an L-shaped figure made of 3 tiles.
The process of the solving it isn't too difficult. If the board is 2x2, then it only takes one tromino to fill it. For any greater size, it must be divided into quarters (making four 2^(k-1) sized boards), with one tromino placed at the center point, so each quadrant has one filled in tile. After that, the board can be recursively filled until every tile is filled with a random colored tromino.
My main problem is actually implementing the code. My skills with Java programming are generally pretty weak, and I often have trouble simply finding a place to start. The only work to be done is in the tile method in the tiling class, which takes as input the deficient board to tile, the row and column to start tiling in, and the number of tiles to fill. This is a homework problem, so I'm simply looking for some guidance or a place to start - any help would be greatly appreciated.
public class BoardViewer extends JFrame {
private static final int WIDTH = 1024;
private static final int HEIGHT = 768;
private static final int OFFSET = 30;
public static final int UPVERT = 1;
public static final int DNVERT = 2;
public static final int RHORIZ = 4;
public static final int LHORIZ = 8;
public static final int FILL = 16;
private Color [][] board;
public BoardViewer(DeficientBoard db) {
super();
setSize(WIDTH + (OFFSET*2), HEIGHT + (OFFSET*2));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
board = db.getBoardColor();
}
public void paint(Graphics g) {
super.paint(g);
int width = WIDTH/board[0].length;
int height = HEIGHT/board.length;
for (int r = 0; r < board.length; r++)
for (int c = 0; c < board[r].length; c++) {
g.setColor(board[r][c]);
int x = c*width + OFFSET;
int y = r*height + OFFSET + (OFFSET/2);
g.fillRect(x+1, y+1, width-1, height-1);
}
}
}
public class DeficientBoard {
private int n;
private Color board[][];
// The four rotations of the tile.
// UL is XX
// X
// UR is XX
// X
// LL is X
// XX
// LR is X
// XX
public final int UL = 0;
public final int UR = 1;
public final int LL = 2;
public final int LR = 3;
/**
* Create a 2^k x 2^k deficient board.
*
* #param k power
*/
public DeficientBoard(int k) {
n = (int)Math.pow(2, k);
createBoard(Color.LIGHT_GRAY);
}
/**
* Actually create an n x n deficient board.
*
* #param color background color
*/
private void createBoard(Color color) {
board = new Color[n][n];
for (int r = 0; r < board.length; r++)
for (int c = 0; c < board[0].length; c++)
board[r][c] = color;
int d_row = (int)(Math.random() * n);
int d_col = (int)(Math.random() * n);
board[d_row][d_col] = Color.BLACK;
}
/**
* Given a row and column and shape based on that point
* place a tromino of the given color.
*
* #param r row
* #param c column
* #param s shape (UL, UR, LL, LR)
* #param theColor a Color
*/
public void placeTromino(int r, int c, int s, Color theColor) {
if (s == UL) {
board[r][c] = theColor;
board[r][c+1] = theColor;
board[r+1][c] = theColor;
} else if (s == UR) {
board[r][c] = theColor;
board[r][c+1] = theColor;
board[r+1][c+1] = theColor;
} else if (s == LL) {
board[r][c] = theColor;
board[r+1][c] = theColor;
board[r+1][c+1] = theColor;
} else {
board[r+1][c] = theColor;
board[r+1][c+1] = theColor;
board[r][c+1] = theColor;
}
}
/**
* Get the 2^k x 2^k board.
*
* #return the Color board.
*/
public Color[][] getBoardColor() {
return board;
}
/**
* Find and return the deficient row.
*
* #param row row
* #param col column
* #param sz size of the baord
* #return the row the deficient block is located
*/
public int getDeficientRow(int row, int col, int sz) {
for (int r = row; r < (row + sz); r++)
for (int c = col; c < (col + sz); c++)
if (board[r][c] != Color.LIGHT_GRAY)
return r;
return -1;
}
/**
* Find and return the deficient column.
*
* #param row row
* #param col column
* #param sz size of the baord
* #return the row the deficient block is located
*/
public int getDeficientCol(int row, int col, int sz) {
for (int r = row; r < (row + sz); r++)
for (int c = col; c < (col + sz); c++)
if (board[r][c] != Color.LIGHT_GRAY)
return c;
return -1;
}
/**
* Get the size of the deficient board.
*
* #return the size
*/
public int getSize() {
return n;
}
/**
* Display information about the deficient board.
*/
public String toString() {
return ("Deficient board of size "
+ n + "x" + n
+ " with position missing at ("
+ getDeficientRow(0, 0, n) + "," + getDeficientCol(0, 0, n) +").");
}
}
public class Tiling {
private static Color randColor() {
int r = (int)(Math.random() * 256);
int g = (int)(Math.random() * 256);
int b = (int)(Math.random() * 256);
return new Color(r, g, b);
}
public static void tile(DeficientBoard db, int row, int col, int n) {
}
public static void main(String[] args) {
DeficientBoard db = new DeficientBoard(3);
System.out.println(db);
tile(db, 0, 0, db.getSize());
BoardViewer bv = new BoardViewer(db);
bv.setVisible(true);
}
}
In general, when a recursive function implements a divide-and-conquer algorithm, it has to handle two basic cases:
The base case. This is the case where you're done dividing, and need to conquer a bit. In your assignment, the base case is the case where n = 2, and in that case, you just need to find which of the four tiles is missing/painted (using DefectiveBoard.getDeficientRow and DefectiveBoard.getDeficientCol) and add the appropriate triomino to cover the other three tiles.
The recursive case. This is the case where you're not done dividing, so you need to divide (i.e., recurse), and (depending on the algorithm) may need to do a bit of conquering either before or after the recursion. In your assignment, the recursive case is the case where n > 2. In that case, you need to do two things:
Find which of the four quadrants has a missing/painted tile, and add the appropriate triomino to cover one tile from each of the other three quadrants.
Recurse, calling yourself four times (one for each quadrant).
A good starting point is to write the "Is this the base case?" check, and to implement the base case.
After that, if you don't see how to write the recursive case, one approach is to temporarily write a "one above the base" case (n = 4), and see if you can generalize it. If not, you might then temporarily write a "two above the base" case (n = 8), and so on. (Once you've got your recursive algorithm working, you would then remove these special cases, since they're fully covered by the general recursive case.)
Well this is somewhat of a harder problem to solve. However, I'd say you have the skills given how much code you wrote so I wouldn't be self conscious about it.
I don't have a complete solution formulated, but I think if you start at the the removed tile and put a trominos on either side of it. Then keep putting trominos on either side of the last trominos. You're "spooning" the tromino you last placed on the board. Once you do that to the edge of the board. All that's left is tromino shaped locations. Here is an example of what I mean (X is the dropped tile ie the gap, Y are the trominos):
_ _ _ _
|_|_|_|_|
|_|Y|Y|_|
|_|Y|X|Y|
|_|_|Y|Y|
_ _ _ _
|Y|Y|_|_|
|Y|Y|Y|_|
|_|Y|X|Y|
|_|_|Y|Y|
Once the board is filled to the edges you can essentially start dropping trominos like bombs on the rest of the board. I have a feeling there is a pattern here where you fill in the diagonal trominos while filling in the 2nd part at the same time that is repeatable. But if you can't find that then create a recursive routine that spoons the gap to the edges then transitions to adding trominos in diagonal patterns. The hint there is you have to do the transition in the first stack frame only.
Good luck.
Greetings. I've completed a project for school with all but one requirement.
The requirement is:
Notice that the SeaCreature class defines four constants for the various directions. Make sure to use them.Your code should not depend upon the specific values assigned to these constants, although you may assume they will always be of type int.
I don't see the value in this. The constant values assigned are logical and allow for easy use of Random to return a direction. If the values assigned were four non consecutive numbers that would really complicate the code.
Below is the original SeaCreature class mentioned in the assignment, and then the code for one of my creatures that makes use of Random. Other than assigning new values to NORTH, SOUTH, EAST, WEST in each class that involves random movement, is there a cleaner way to return the cardinal directions as opposed to their values of 0-3?
Thank you in advance for your advice, and please ask if any clarification is needed.
import java.util.*;
/**
* Defines the attributes and behaviors common to all SeaCreatures in order to participate
* in the SeaCreature simulation.
*
* Each SeaCreature is represented by a char.
* Each SeaCreature can answer back its char when asked.
* Each SeaCreature can answer its next move, NORTH, SOUTH, EAST, WEST.
*
*/
public abstract class SeaCreature {
private char ch;
/** defined constant to facilitate random movement*/
public static final Random rand = new Random();
/** defined constant to move one unit NORTH */
public static final int NORTH = 0;
/** defined constant to move one unit SOUTH */
public static final int SOUTH = 1;
/** defined constant to move one unit EAST */
public static final int EAST = 2;
/** defined constant to move one unit WEST */
public static final int WEST = 3;
/**
* Construct a SeaCreature object with the given character representation
* #param c the character for this SeaCreature
*/
public SeaCreature (char c){
ch = c;
}
/**
* Answers back the character representation for this SeaCreature
* #return this SeaCreature's initial
*/
public char getChar(){
return ch;
}
/** Answers back the next move for this SeaCreature.
* Must be overridden by subclasses
* #return NORTH, SOUTH, EAST, or WEST
*/
public abstract int getMove();
}
My SeaLion class:
/**
* Defines the attributes and behaviors specific to SeaLions in order to participate
* in the SeaCreature simulation.
*
* #author Justin Ashburn
* #version 6/5/2011
*/
public class SeaLion extends SeaCreature {
/** defined char to represent a SeaLion*/
private static final char SEALION = 'L';
/** defined steps before SeaLion cycle repeats*/
private static final int CYCLE_LENGTH = 3;
/** defined steps before SeaLion's first direction*/
private static final int DIRECTION_ONE_LENGTH = 2;
private int directionOne;
private int count;
/**
* Construct a SeaLion object with the given character representation
*/
public SeaLion(){
super(SEALION);
// establishes an initial direction
directionOne = rand.nextInt(4);
count = 0;
}
/** Moves like the 'Knight' chess piece. ie. Picks a random direction, moves 2 times
* in that direction, and then randomly chooses a direction perpendicular to the first
* and moves in that direction once.
*
* #return 0, 1, 2, or 3
*/
public int getMove() {
int direction;
int directionTwo;
// continues with direction one for the appropriate length
if (count < DIRECTION_ONE_LENGTH) {
count ++;
direction = directionOne;
}
// if directionOne was east or west chooses a new north or south direction for last move
else if (count < CYCLE_LENGTH && directionOne > 1) {
directionTwo = rand.nextInt(2);
direction = directionTwo;
// resets count and establishes new direction in next cycle
count = 0;
directionOne = rand.nextInt(4);
}
// if directionOne was north or south chooses a new east or west direction for last move
else {
directionTwo = rand.nextInt(2) + 2;
direction = directionTwo;
// resets count and establishes new direction in next cycle
count = 0;
directionOne = rand.nextInt(4);
}
return direction;
}
}
What you need is a simple mapping from integers between 0 and 3 to the values of the 4 named constants ... without making any assumptions about what those values are.
How could you implement that?
Hint: What simple Java data structure maps from (zero to length - 1) to something else?
I think I would do something like this:
private static final int AXES[][] = {
{NORTH,SOUTH},
{EAST,WEST}
};
...
private int directionOne;
private int directionTwo;
private int count;
...
public SeaLion(){
super(SEALION);
// establishes an initial direction
nextCycle();
}
...
public int getMove() {
int direction;
if (count < DIRECTION_ONE_LENGTH) {
direction = directionOne;
} else {
direction = directionTwo;
}
++count;
if (count == CYCLE_LENGTH) {
nextCycle();
}
return direction;
}
...
private void nextCycle() {
int axis1 = random.nextInt(2);
int axis2 = 1 - axis1;
directionOne = AXES[axis1][random.nextInt(2)];
directionTwo = AXES[axis2][random.nextInt(2)];
count = 0;
}
You could let NORTH, SOUTH, WEST, and EAST be either direction or heading, as following:
Heading:
public static final int NORTH = 0;
public static final int SOUTH = 180;
public static final int EAST = 90;
public static final int WEST = 270; // Or -90
Direction:
public static final int NORTH = 90;
public static final int SOUTH = 270; // Or -90
public static final int EAST = 0;
public static final int WEST = 180;
I am modifying a graph implementation to compute the all pairs shortest path matrix using Floyd's algorithm. The graph has both adjacency linked list and matrix implementations. For now I am using adjacency matrix because it its needed for this algorithm.
abstract public class GraphMatrix<V,E> extends AbstractStructure<V> implements Graph<V,E>{
/**
* Number of vertices in graph.
*/
protected int size; // allocation size for graph
/**
* The edge data. Every edge appears on one (directed)
* or two (undirected) locations within graph.
*/
protected Object data[][]; // matrix - array of arrays
/**
* Translation between vertex labels and vertex structures.
*/
protected Map<V,GraphMatrixVertex<V>> dict; // labels -> vertices
/**
* List of free vertex indices within graph.
*/
protected List<Integer> freeList; // available indices in matrix
/**
* Whether or not graph is directed.
*/
protected boolean directed; // graph is directed
/**
* Constructor of directed/undirected GraphMatrix. Protected constructor.
*
* #param size Maximum size of graph.
* #param dir True if graph is to be directed.
*/
protected GraphMatrix(int size, boolean dir)
{
this.size = size; // set maximum size
directed = dir; // fix direction of edges
// the following constructs a size x size matrix
data = new Object[size][size];
// label to index translation table
dict = new Hashtable<V,GraphMatrixVertex<V>>(size);
// put all indices in the free list
freeList = new SinglyLinkedList<Integer>();
for (int row = size-1; row >= 0; row--)
freeList.add(new Integer(row));
}
.
.
.
public Object[][] AllPairsShortestPath()
{
//First, data array needs to be copied to a new array so that it is not corrupted.
Object[][] weight_matrix = data.clone();
for(int k = 0; k < size; k++)
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
{
if((weight_matrix + weight_matrix[k][j])<weight_matrix[i][j])
{
//New shorter path is found
}
}
}
}
return weight_matrix;
}
My question is how can I reference the weight_matrix elements so that they can be compared?
Here is the edge class that is in the Object matrix:
public class Edge<V,E>
{
/**
* Two element array of vertex labels.
* When necessary, first element is source.
*/
protected V here, there; // labels of adjacent vertices
/**
* Label associated with edge. May be null.
*/
protected E label; // edge label
/**
* Whether or not this edge has been visited.
*/
protected boolean visited; // this edge visited
/**
* Whether or not this edge is directed.
*/
protected boolean directed; // this edge directed
/**
* Construct a (possibly directed) edge between two labeled
* vertices. When edge is directed, vtx1 specifies source.
* When undirected, order of vertices is unimportant. Label
* on edge is any type, and may be null.
* Edge is initially unvisited.
*
* #post edge associates vtx1 and vtx2; labeled with label
* directed if "directed" set true
*
* #param vtx1 The label of a vertex (source if directed).
* #param vtx2 The label of another vertex (destination if directed).
* #param label The label associated with the edge.
* #param directed True iff this edge is directed.
*/
public Edge(V vtx1, V vtx2, E label,
boolean directed)
{
here = vtx1;
there = vtx2;
this.label = label;
visited = false;
this.directed = directed;
}
/**
* Returns the first vertex (or source if directed).
*
* #post returns first node in edge
*
* #return A vertex; if directed, the source.
*/
public V here()
{
return here;
}
/**
* Returns the second vertex (or source if undirected).
*
* #post returns second node in edge
*
* #return A vertex; if directed, the destination.
*/
public V there()
{
return there;
}
/**
* Sets the label associated with the edge. May be null.
*
* #post sets label of this edge to label
*
* #param label Any object to label edge, or null.
*/
public void setLabel(E label)
{
this.label = label;
}
/**
* Get label associated with edge.
*
* #post returns label associated with this edge
*
* #return The label found on the edge.
*/
public E label()
{
return label;
}
/**
* Test and set visited flag on vertex.
*
* #post visits edge, returns whether previously visited
*
* #return True iff edge was visited previously.
*/
public boolean visit()
{
boolean was = visited;
visited = true;
return was;
}
/**
* Check to see if edge has been visited.
*
* #post returns true iff edge has been visited
*
* #return True iff the edge has been visited.
*/
public boolean isVisited()
{
return visited;
}
/**
* Check to see if edge is directed.
*
* #post returns true iff edge is directed
*
* #return True iff the edge has been visited.
*/
public boolean isDirected()
{
return directed;
}
/**
* Clear the visited flag associated with edge.
*
* #post resets edge's visited flag to initial state
*/
public void reset()
{
visited = false;
}
/**
* Returns hashcode associated with edge.
*
* #post returns suitable hashcode
*
* #return An integer code suitable for hashing.
*/
public int hashCode()
{
if (directed) return here().hashCode()-there().hashCode();
else return here().hashCode()^there().hashCode();
}
/**
* Test for equality of edges. Undirected edges are equal if
* they connect the same vertices. Directed edges must have same
* direction.
*
* #post returns true iff edges connect same vertices
*
* #param o The other edge.
* #return True iff this edge is equal to other edge.
*/
public boolean equals(Object o)
{
Edge<?,?> e = (Edge<?,?>)o;
return ((here().equals(e.here()) &&
there().equals(e.there())) ||
(!directed &&
(here().equals(e.there()) &&
there().equals(e.here()))));
}
/**
* Construct a string representation of edge.
*
* #post returns string representation of edge
*
* #return String representing edge.
*/
public String toString()
{
StringBuffer s = new StringBuffer();
s.append("<Edge:");
if (visited) s.append(" visited");
s.append(" "+here());
if (directed) s.append(" ->");
else s.append(" <->");
s.append(" "+there()+">");
return s.toString();
}
}
I guess
((weight_matrix + weight_matrix[k][j])<weight_matrix[i][j])
is not what you want. IIRC, Floyd's as follows:
((weight_matrix[i][k] + weight_matrix[k][j])<weight_matrix[i][j])
IF YOUR weight_matrix were a matrix of weights (take a look here for more floyd). Size, in this implementation, would be the number of vertices you got on the graph.
If each edge had a weight, you could do
(( ((Edge)weight_matrix[i][k]).getValue() + ((Edge)weight_matrix[k][j]).getValue()) < ((Edge)weight_matrix[i][j]).getValue())
If all edge weights are equal, you could tell getValue() to return 1 always, and voilá.