I am working on a project for an introductory CompSci course in java and I am stuck. We have to fill out the methods for a rock, paper, scissor game called stick, fire, water. I thought I filled it out correctly, but every time I run it, my program says it is a tie. It displays both my choice and the computer choice, but it says it is a tie and it doesn't increment the rounds played (or either my score or the computer's score, but since it is a tie that would not happen anyways, although I am sure it is still messed up).
/* This class ecapsulates the state and logic required to play the
Stick, Water, Fire game. The game is played between a user and the computer.
A user enters their choice, either S for stick, F for fire, W for water, and
the computer generates one of these choices at random- all equally likely.
The two choices are evaluated according to the rules of the game and the winner
is declared.
Rules of the game:
S beats W
W beats F
F beats S
no winner on a tie.
Each round is executed by the playRound method. In addition to generating the computer
choice and evaluating the two choices, this class also keeps track of the user and computer
scores, the number of wins, and the total number of rounds that have been played. In the case
of a tie, neither score is updated, but the number of rounds is incremented.
NOTE: Do not modify any of the code that is provided in the starter project. Additional instance variables and methods
are not required to make the program work correctly, but you may add them if you wish as long as
you fulfill the project requirements.
*/
public class StickWaterFireGame {
// TODO 1: Declare private instance variables here:
Random rand = new Random();
int numRounds = 0;
int playerScore = 0;
int computerScore = 0;
boolean playerWins = false;
boolean isTie = false;
/* This constructor assigns the member Random variable, rand, to
* a new, unseeded Random object.
* It also initializes the instance variables to their default values:
* rounds, player and computer scores will be 0, the playerWins and isTie
* variables should be set to false.
*/
public StickWaterFireGame() {
// TODO 2: Implement this method.
Random rand = new Random();
numRounds = 0;
playerScore = 0;
computerScore = 0;
playerWins = false;
isTie = false;
}
/* This constructor assigns the member Random variable, rand, to
* a new Random object using the seed passed in.
* It also initializes the instance variables to their default values:
* rounds, player and computer scores will be 0, the playerWins and isTie
* variables should be set to false.
*/
public StickWaterFireGame(int seed) {
// TODO 3: Implement this method.
Random rand = new Random(seed);
numRounds = 0;
playerScore = 0;
computerScore = 0;
playerWins = false;
isTie = false;
}
/* This method returns true if the inputStr passed in is
* either "S", "W", or "F", false otherwise.
* Note that the input can be upper or lower case.
*/
public boolean isValidInput(String inputStr) {
// TODO 4: Implement this method.
if (inputStr.equalsIgnoreCase("S") || inputStr.equalsIgnoreCase("W") || inputStr.equalsIgnoreCase("F")) {
return true;
}
else {
return false;
}
}
// Returns the choice of the computer for the most recent round of play
public String getComputerChoice(){
// TODO 5: Implement this method.
return getRandomChoice();
}
// Returns true if the player has won the last round, false otherwise.
public boolean playerWins(){
// TODO 6: Implement this method.
if (playerWins) {
return true;
}
else {
return false;
}
}
// Returns the player's cumulative score.
public int getPlayerScore(){
// TODO 7: Implement this method.
return playerScore;
}
// Returns the computer's cumulative score.
public int getComputerScore(){
// TODO 8: Implement this method.
return computerScore;
}
// Returns the total nuber of rounds played.
public int getNumRounds(){
// TODO 9: Implement this method.
return numRounds;
}
// Returns true if the player and computer have the same score on the last round, false otherwise.
public boolean isTie(){
// TODO 10: Implement this method.
if (computerScore == playerScore) {
return true;
}
else {
return false;
}
}
/* This "helper" method uses the instance variable of Random to generate an integer
* which it then maps to a String: "S", "W", "F", which is returned.
* This method is called by the playRound method.
*/
private String getRandomChoice() {
// TODO 11: Implement this method.
String randomChoice = "";
Random rand = new Random();
int randomInput = rand.nextInt(3) + 1;
if (randomInput == 1) {
randomChoice = "S";
}
if (randomInput == 2) {
randomChoice = "W";
}
if (randomInput == 3) {
randomChoice = "F";
}
return randomChoice;
}
/* This method carries out a single round of play of the SWF game.
* It calls the isValidInput method and the getRandomChoice method.
* It implements the rules of the game and updates the instance variables
* according to those rules.
*/
public void playRound(String playerChoice) {
// TODO 12: Implement this method.
int numRounds = 0;
int playerScore = 0;
int computerScore = 0;
boolean playerWins = false;
boolean isTie = false;
String computerChoice = getRandomChoice();
if (!isValidInput(playerChoice)) {
++computerScore;
++numRounds;
}
else {
if (computerChoice.equalsIgnoreCase(playerChoice)) {
++numRounds;
}
if (computerChoice.equals("S") && playerChoice.equalsIgnoreCase("W")) {
++computerScore;
++numRounds;
}
if (computerChoice.equals("S") && playerChoice.equalsIgnoreCase("F")) {
playerWins = true;
++playerScore;
++numRounds;
}
if (computerChoice.equals("W") && playerChoice.equalsIgnoreCase("S")) {
playerWins = true;
++playerScore;
++numRounds;
}
if (computerChoice.equals("W") && playerChoice.equalsIgnoreCase("F")) {
++computerScore;
++numRounds;
}
if (computerChoice.equals("F") && playerChoice.equalsIgnoreCase("S")) {
++computerScore;
++numRounds;
}
if (computerChoice.equals("F") && playerChoice.equalsIgnoreCase("W")) {
playerWins = true;
++playerScore;
++numRounds;
}
}
}
} ```
Look at this method. You are redelaring three variables when you set them to 0. I think you just want to assign them.
public void playRound(String playerChoice) {
// TODO 12: Implement this method.
int numRounds = 0;
int playerScore = 0;
int computerScore = 0;
boolean playerWins = false;
boolean isTie = false;
String computerChoice = getRandomChoice();
There are numerous suspicious things about your code, but the specific issues you describe are likely related to the fact that your playRound() method declares local variables shadowing most of the class's instance variables:
int numRounds = 0;
int playerScore = 0;
int computerScore = 0;
boolean playerWins = false;
boolean isTie = false;
That method manipulates those local variables rather than the like-named instance variables, and the effects can be seen only inside that method, for the duration of one execution of it. Just removing those local-variable declarations should move you forward.
Related
I'm a high schooler in apcs and I'm trying to practice these for the test. The code should return whether a new object was created. Also, the moveUp method doesn't allow me to call it using the scoreboard list (e.g. "scoreboard.move(int x)". Please explain why I'm wrong, but don't solve it.
public boolean newScore(String name, int score)
{
/* Implement your answer to part (b) here */
for (int ind = 0; ind < scoreboard.size(); ind++) {
Player player = scoreboard.get(ind);
if (player.getName().equalsIgnoreCase(name)) {
player.updateScore(score);
moveUp(scoreboard.indexOf(player));
return true;
} else {
Player p = new Player(name, score);
scoreboard.add(p);
p.updateScore(score);
moveUp(scoreboard.indexOf(p));
return false;
}
}
}
I need to deny access to a function until a specific value is reached. For example, have the function sleep for values 5-10 on a variable and then perform it's action on 11, where the variable is manually incremented by 1 by the user. How can I set this up?
This is for a turn-based resource management game, running Java. I've tried setting the method to only run when a boolean value is true, and have it false when it should not be running.
Control switch statement
case "farm":
if (farmAvailable = true) {
farmAvailable = false;
a.foodManagement(foodGenerator, food, storageBunker, day,
farmAvailable);
} else if (farmAvailable = false) {
System.out.println("Farming in progress...");
}
break;
Function being controlled
public int foodManagement(int generator, int currentStorage, int
storageBunker, int day, boolean available) {
int food = generator * 12;
if (available == true) {
int rest = day + 5;
available = false;
while (rest < day) {
if (currentStorage + food > (storageBunker * 25)) {
currentStorage += food;
food = currentStorage - (storageBunker * 25);
System.out.println("Food storage full.");
available = true;
return food;
} else {
available = true;
return food;
}
}
} else {
return 0;
}
return 0;
}
This method should not run when farmAvailable is false, however nothing happens when you prompt the program to do so.
***I tried searching but I just can't understand what comes up. Sorry.
I am working on a server/client project for school. I am at my wit's end and I am about to give up. I do not have notes from class so I need some help. First I will post the directions I was given, then my current code, then my problem.
SERVER DIRECTIONS:
The Triangle class must have the following instance variables: side_a, side_b, side_c. Create a static variable to keep track of the number of Triangle objects created. Also create a static variable to hold the total of the perimeters of all Triangle objects created.
A three parameter constructor of the Triangle class should assign a trio of input values to the instance variables of the object. If not a valid triangle set all of the sides to 1. Create a separate private method called isValid(). The sum of any two sides of a triangle must be greater than the third in order to represent a valid triangle. No side may be 0 or negative. The constructor should also add 1 to the count and also call a method to calculate and then add the perimeter for that object to an accumulator.
The Triangle class must have the following methods as stated above:
public boolean is_right() public boolean is_isoc()
public boolean is_equil() public boolean is_scal()
public String toString() – returns the values for the 3 sides of the Triangle
You should also add a method to the Triangle class called calc_perim. This method will use the sides of the Triangle object to calculate the perimeter for that object.
addTotalPerim. This method will call calc_perim and add the perimeter for that object to an accumulator.
reduceTotalPerim. This method should subtract the perimeter for that object from the accumulator.
SERVER CODE:
public class Triangle {
private int side_a, side_b, side_c;
private static int count;
**//PROBLEM 1: Java tells me 'perim' is not used.**
private static int perim;
private boolean valid;
public Triangle(int s1, int s2, int s3)
{
side_a = s1; side_b = s2; side_c = s3;
**//PROBLEM 2: Java tells me 'v' is not used.**
boolean v = isValid();
if (v = false)
{side_a = 1; side_b = 1; side_c = 1;}
Triangle.count++;
calc_perim(s1,s2,s3);
addTotalPerim();
reduceTotalPerim();
}
private int calc_perim()
{
int perimeterCalc = side_a + side_b + side_c;
return perimeterCalc;
}
private void addTotalPerim()
{
Triangle.perim += calc_perim();
}
private void reduceTotalPerim()
{
Triangle.perim -= calc_perim();
}
private boolean isValid()
{
boolean valid1;
if (side_a < 1)
{ valid1 = false;}
else if (side_b < 1)
{ valid1 = false;}
else if (side_c < 1)
{ valid1 = false;}
else if ((side_a + side_b) < side_c || (side_a + side_b) == side_c)
{ valid1 = false;}
else
{ valid1 = true;}
return valid1;
}
public boolean is_right()
{
boolean right;
if (((side_a * side_a) + (side_b * side_b)) == (side_c * side_c))
right = true;
else
right = false;
return right;
}
public boolean is_isoc()
{
boolean isoc;
if (side_a == side_b)
isoc = true;
else if (side_a == side_c)
isoc = true;
else if (side_b == side_c)
isoc = true;
else
isoc = false;
return isoc;
}
public boolean is_equil()
{
boolean equil;
if (side_a == side_b && side_a == side_c)
equil = true;
else
equil = false;
return equil;
}
public boolean is_scal()
{
boolean scal;
if (side_a == side_b || side_a == side_c || side_b == side_c)
scal = false;
else
scal = true;
return scal;
}
public String toString()
{
return "Side 1: " + side_a + " Side 2: " + side_b + " Side 3: " + side_c;
}
}
Sorry about formatting but this site has a terrible way of formatting code, unless I'm misunderstanding something...
SERVER PROBLEMS:
What is the correct way to add/subtract the perimeter obtained via method calc_perim to varible perim? The directions say to call the calc_perim method in the constructor but I can't figure out how, so I just made it do its calculations on its own.
In the constructor, after calling method isValid(), why am I told by Java that variable 'v' is not used? Did I call isValid() incorrectly? >>>>> How do I call a method in the constructor? <<<<<
Other than that major issue, the server class works fine.
Suggestions:
Within Triangle class, initialize the static variables.
private static int count = 0;
private static int perim = 0;
Within Triangle constructor, change,
if (v = false)
to
if (v == false)
Change calc_perim as:
private void addTotalPerim()
{
perim += calc_perim();
}
private void reduceTotalPerim()
{
perim -= calc_perim();
}
Why you call reduceTotalPerim() after addTotalPerim(), didn't get this clear.
isValid function should check all combinations like a+b>c, b+c>a, c+a>b, if any one fails should be invalid
The "is not used" message from the Java compiler is technically a warning, not an error, so you could run your program even with the message still in effect if you really wanted to. But your instincts are correct- it's a bad idea to ignore those messages.
In this case, your code has a serious problem. You're calling v = false, which means that you're assigning a value of false to v. Change it to v == false. By using ==, you're doing a comparison, which is what you really want.
public String tictactoe(String game)
{
game = game.toUpperCase();
char[][] board = new char[3][3];
int loc = 0;
for( char r = 0; r < board.length; r++ )
{
for( char c = 0; c < board[r].length; c++)
{ board[r][c] = game.charAt(loc);
loc++;
}
}
if ((board[0][0] =='X' && board[0][1] =='X' && board[0][2] =='X') ||
(board[1][0] =='X' && board[1][1] =='X' && board[1][2] =='X') ||
(board[2][0] =='X' && board[2][1] =='X' && board[2][2] =='X'))
return("Player 1 wins horizontally!");
else if ((board[0][0] =='O' && board[0][1] =='O' && board[0][2] =='O') ||
(board[1][0] =='O' && board[1][1] =='O' && board[1][2] =='O') ||
(board[2][0] =='O' && board[2][1] =='O' && board[2][2] =='O'))
return("Player 2 wins horizontally!");
else if ((board[0][0] =='X' && board[1][0] =='X' && board[2][0] =='X') ||
(board[0][1] =='X' && board[1][1] =='X' && board[2][1] =='X') ||
(board[0][2] =='X' && board[1][2] =='X' && board[2][2] =='X'))
return("PLayer 2 wins vertically!");
else if ((board[0][0] =='O' && board[1][0] =='O' && board[2][0] =='O') ||
(board[0][1] =='O' && board[1][1] =='O' && board[2][1] =='O') ||
(board[0][2] =='O' && board[1][2] =='O' && board[2][2] =='O'))
return("Player 2 wins vertically!");
return "Tie!";
}
Above is my code for this method. It reads in a 9 letter string for a tic-tac-toe game and then puts it one by one into a 2D array. I unfortunately have to use this method because this is unfortunately what we're learning, and I've continuously had to bother my teacher about this...
The if statements check each row and column for a winner (I realize it does not check the horizontals). My issue here is nothing is being returned, even though it is supposed to return a string. As I have said I have to use 2D-arrays here. The goal is to check a tic-tac-toe game and return whom as won.
Consider replacing each instance of this
if(board[0][0] =='X' && board[0][1] =='X' && board[0][2] =='X') ||
...
With this function:
public boolean isRowFilledWith(int row_index, char x_or_o) {
return (board[row_idx][0] == x_or_o &&
board[row_idx][1] == x_or_o &&
board[row_idx][2] == x_or_o);
}
Now, to see if the top-most row contains all x-s, call it with
if(isRowFilledWith(0, 'X') ||
...
This will make your code a lot more concise, easier to read and easier to debug.
Try doing:
System.out.println(fooObject.tictactoe("XXXXXXOOO");
inside your main argument (public static void main(String[] args)
I suspect you've confused return and System.out.println. The console will not print anything if returned. Instead, returning is what is thrown at the computer after the function is called. Try printing the result of calling the function...THAT is what is returned to the computer and is only going to be visible if you print it. There may not be any error in your code.
First off, to directly answer your question:
Your function works fine, I locally tested it. I tried both horizontal, and vertical, with both x and o. It must be something you are doing with the caller.
The biggest problem with this code is clarity. You can do quite a bit about clarity by separating the logic into groups.
Clarity can be achieved by making application specific objects.
If you have an object to represent a move, a game, and the marker... you can drastically simplify you code and most of all make it easy to read and debug.
I went ahead and implemented tic tac toe just to kinda explain what I mean by clarity.
Any time you start having massive if else chains and block return statements you may need to take the extra time to break up the problem.
This is fully compililable and I think if you debug through it a few times you will find it is much easier to spot mistakes.
It is also easy to ajust the game... Right now, we have 2 players and a 3 by 3 game.
However, we have extra constructors to adjust the size of the game and to give the gamers some options on what they want thier tic tac toe game to look like.
The major reason to do this is for clarity and debugging.
It is always easier to find issues if you have problem specific methods and problem specific objects.
Below is a fully compilable console application for tic tac toe. In its current form, it plays 100 random 3 by 3 games and prints the results of all 100 games.
The application is also capable of taking your string input as console input and processing the moves.
Notice that we are still using two dimensional arrays, but we hidden away the complexity of using them by encapsulating the array in the Board object.
We also gave a move object so we can store moves to play later. This was useful in creating the loop to play many games, as all the facts about the move are contained in a single object.
Since we created three separate methods for validating the move input. We have a much clearer explanation of what we are validating and why we are doing it.
Most debuggers will also show the objects toString method, so by embedding the game display within the toString() we are allowed to see what the board looks like when we are debugging.
The trick to making clean code that doesn't require alot of comments is to attempt to split out any complexity to its own unit.
You probably will cover more about units of work later, but just keep it in mind, the more simple a method, the more reusable it is. The more single purpose a class is, the better and clearer it is.
My Example:
Mark.java
-This enum is the representation of the mark used by a player to signify their move.
public enum Mark{
X, Y;
}
TicTacToe.java
-This class is your main class
it handles gathering user input, cleaning it, processing it, and displaying the output to the user
Notice that I am not doing game display anywhere else but the main method. this keeps all display issues localized to one spot. The advantage to breaking up your code into specific objects is knowing where to fix something when it breaks.
package com.clinkworks.example;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.clinkworks.example.Move;
import com.clinkworks.example.Board;
import com.clinkworks.example.Mark;
public class TicTacToe {
//this variable is simply used for output. Since we cant save CAT in the mark enum, we
// use it to hold cats games.
private static final String catsGameIdentity = "CAT";
//this map contains the counts of wins for each symbol
//it also keeps track of ties and stores it in the map as "CAT"
//soo.. gamesToWinsMap.get("CAT") will produce the amount of ties.
private static final Map<String, Integer> gamesToWinsMap = new HashMap<String, Integer>();
public static void main(String[] args){
String game = args[0].toUpperCase(); //better ways to do this and no validation here.. but it will work
Board board = new Board();
//holds our current place in the string passed in from teh console
int currentStringLocation = 0;
for(int row = 0; row < 3; row++){ //loop through the rows
for(int column = 0; column < 3; column++){ //for each row loop through the columns
if(gameOver(board)){ // we don't care about the rest of the input if the game was won
break;
}
//convert the symbol to a string for use in teh ValueOf function in the enum class
String symbol = "" + game.charAt(currentStringLocation); //better than String.valueOf imho
//allow spaces to represent un marked places
if(" ".equals(symbol)){
currentStringLocation++; //this accounts for spaces in our input
break;
}
//convert the string to a Mark enum... over use of strings is a very very bad practice
Mark nextMarkToPlace = Mark.valueOf(symbol);
Move move = new Move(row, column, nextMarkToPlace); //we create a move object that encapsulates the complexity of placing the mark on the game board
board.play(move); //the game already knows how to play itself, just let it
currentStringLocation++; //increment the posision.
}
}
//since you may not have won the game, or gave a complete string for a cats game,
// lets at least display the board for debugging reasons.
if(board.movesLeft() > 0){
System.out.println("Board isn't finished, but here is what it looks like basd on your input: ");
System.out.println(board);
}
}
//call me main if you want to see what I do
public static void main2(String[] args) {
//lets play 100 games and see the wins and ties
playGames(100);
System.out.println("Number wins by X: " + gamesToWinsMap.get(Mark.X.name()));
System.out.println("Number wins by O: " + gamesToWinsMap.get(Mark.O.name()));
System.out.println("Number of ties: " + gamesToWinsMap.get(catsGameIdentity));
}
public static void playGames(int count) {
//play a new game each iteration, in our example, count = 100;
for (int i = 0; i < count; i++) {
playGame();
}
}
public static void playGame() {
//create a new game board. this initalizes our 2d array and lets the complexity of handling that
// array be deligated to the board object.
Board board = new Board();
//we are going to generate a random list of moves. Heres where we are goign to store it
List<Move> moves = new ArrayList<Move>();
//we are creating moves for each space on the board.
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
moves.add(new Move(row, col));
}
}
//randomize the move list
Collections.shuffle(moves);
//do each move
for (Move move : moves) {
board.play(move);
if(gameOver(board)){
break;
}
}
}
public static boolean gameOver(Board board){
if (board.whoWon() != null) {
System.out.println("Player with the mark: " + board.whoWon() + " won the game!");
System.out.println(board);
Integer winCount = gamesToWinsMap.get(board.whoWon().name());
winCount = winCount == null ? 1 : winCount + 1;
gamesToWinsMap.put(board.whoWon().name(), winCount);
return true;
} else if (board.movesLeft() == 0) {
System.out.println("It was a cats game!!");
System.out.println(board);
Integer catCount = gamesToWinsMap.get(catsGameIdentity);
catCount = catCount == null ? 1 : catCount + 1;
gamesToWinsMap.put(catsGameIdentity, catCount);
return true;
}
return false;
}
Move.java
-This class is responsible for ensuring that only integers are passed to the game board
and for telling the game board who is doing the move (optional)
package com.clinkworks.example;
import com.clinkworks.example.Mark;
public class Move {
private int row;
private int column;
private Mark forcedMark;
public Move(int row, int column) {
this.row = row;
this.column = column;
}
//the board already knows who should be next. only use this constructor to override
// what symbol to put on the game board
public Move(int row, int column, Mark markToPlace){
this.row = row;
this.column = column;
forcedMark = markToPlace;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
public Mark getMark(){
return forcedMark;
}
}
Board.java
-This is where all the state of the board is managed, who is the next player, who won, and
is there any moves left to play. It also ensures that only valid moves are played.
package com.clinkworks.example;
import com.clinkworks.example.Mark;
import com.clinkworks.example.Move;
public class Board {
private final int rowSize;
private final int columnSize;
private final Mark[][] gameBoard;
private Mark currentMark;
private Mark winningMark;
/**
* This constructor defaults the starting player to X with a 3 by 3
* game.
*/
public Board() {
gameBoard = new Mark[3][3];
currentMark = Mark.X; // X always goes first ;P
winningMark = null;
this.rowSize = 3;
this.columnSize = 3;
}
/**
* This constructor defaults the starting player to X, and lets the
* board size be adjusted
*/
public Board(int rowSize, int columnSize) {
gameBoard = new Mark[rowSize][columnSize];
currentMark = Mark.X; // X always goes first ;P
winningMark = null;
this.rowSize = getRowSize();
this.columnSize = columnSize;
}
/**
* this constructor allows the players to choose who goes first on a 3
* by 3 board.
*
* #param firstPlayer
*/
public Board(Mark firstPlayer) {
gameBoard = new Mark[3][3];
currentMark = firstPlayer; // Let the player choose
winningMark = null;
rowSize = 3;
columnSize = 3;
}
/**
* this constructor allows the players to choose who goes first and to
* choose the size of the board.
*
* #param firstPlayer
*/
public Board(Mark firstPlayer, int rowSize, int columnSize) {
gameBoard = new Mark[getRowSize()][columnSize];
currentMark = firstPlayer; // Let the player choose
winningMark = null;
this.rowSize = rowSize;
this.columnSize = columnSize;
}
/**
*
* #return the amount of empty spaces remaining on the game board, or if theres a winning player, zero.
*/
public int movesLeft() {
if(whoWon() != null){
return 0;
}
int moveCount = 0;
for (int x = 0; x < getRowSize(); x++) {
for (int y = 0; y < getColumnSize(); y++) {
moveCount += getMarkAt(x, y) == null ? 1 : 0;
}
}
return moveCount;
}
/**
* If someone won, this will return the winning player.
*
* #return the winning player
*/
public Mark whoWon() {
return winningMark;
}
/**
* This move allows the next player to choose where to place their mark.
* if a move is played without a player given, it will use the current player variable
*
* as a side affect, the next player in rotation is chosen.
*
* #param Move
* #return if the game is over, play will return true, otherwise false.
*/
public boolean play(Move move) {
if (!validMove(move)) {
// always fail early
throw new IllegalStateException("Cannot play " + currentMark + " at " + move.getRow() + ", " + move.getColumn() + "\n" + toString());
}
doMove(move);
boolean playerWon = isWinningMove(move);
if (playerWon) {
winningMark = currentMark;
return true;
}
togglePlayer();
boolean outOfMoves = movesLeft() <= 0;
return outOfMoves;
}
public Mark lastMarkPlayed() {
return currentMark;
}
public int getRowSize() {
return rowSize;
}
public int getColumnSize() {
return columnSize;
}
public Mark getCurrentPlayer() {
return currentMark;
}
public Mark getMarkAt(int row, int column) {
return gameBoard[row][column];
}
private void doMove(Move move) {
if(move.getMark() != null){
currentMark = move.getMark();
}
gameBoard[move.getRow()][move.getColumn()] = getCurrentPlayer();
}
private void togglePlayer() {
if (currentMark == Mark.X) {
currentMark = Mark.O;
} else {
currentMark = Mark.X;
}
}
/**
* A valid move is a move where the row and the column are within boundries
* and no move has been made that the location specified by the move.
*/
private boolean validMove(Move move) {
boolean noMarkAtIndex = false;
boolean indexesAreOk = move.getRow() >= 0 || move.getRow() < getRowSize();
indexesAreOk = indexesAreOk && move.getColumn() >= 0 || move.getColumn() < getColumnSize();
if (indexesAreOk) {
noMarkAtIndex = getMarkAt(move.getRow(), move.getColumn()) == null;
}
return indexesAreOk && noMarkAtIndex;
}
private boolean isWinningMove(Move move) {
// since we check to see if the player won on each move
// we are safe to simply check the last move
return winsDown(move) || winsAcross(move) || winsDiagnally(move);
}
private boolean winsDown(Move move) {
boolean matchesColumn = true;
for (int i = 0; i < getColumnSize(); i++) {
Mark markOnCol = getMarkAt(move.getRow(), i);
if (markOnCol != getCurrentPlayer()) {
matchesColumn = false;
break;
}
}
return matchesColumn;
}
private boolean winsAcross(Move move) {
boolean matchesRow = true;
for (int i = 0; i < getRowSize(); i++) {
Mark markOnRow = getMarkAt(i, move.getColumn());
if (markOnRow != getCurrentPlayer()) {
matchesRow = false;
break;
}
}
return matchesRow;
}
private boolean winsDiagnally(Move move) {
// diagnals we only care about x and y being teh same...
// only perfect squares can have diagnals
// so we check (0,0)(1,1)(2,2) .. etc
boolean matchesDiagnal = false;
if (isOnDiagnal(move.getRow(), move.getColumn())) {
matchesDiagnal = true;
for (int i = 0; i < getRowSize(); i++) {
Mark markOnDiagnal = getMarkAt(i, i);
if (markOnDiagnal != getCurrentPlayer()) {
matchesDiagnal = false;
break;
}
}
}
return matchesDiagnal;
}
private boolean isOnDiagnal(int x, int y) {
if (boardIsAMagicSquare()) {
return x == y;
} else {
return false;
}
}
private boolean boardIsAMagicSquare() {
return getRowSize() == getColumnSize();
}
//prints out the board in a nice to view display
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
for(int y = 0; y < getColumnSize(); y++) {
for(int x = 0; x < getRowSize(); x++) {
Mark mark = getMarkAt(x, y);
String markToPrint = "";
if (mark == null) {
markToPrint = " ";
} else {
markToPrint = mark.name();
}
stringBuffer.append("|").append(markToPrint);
}
stringBuffer.append("|\n");
}
return stringBuffer.toString();
}
}
}
I used the following code in my class with the intention of doing one round of recursion (specifically creating an object within an object of the same type). Well, that one round of recursion is now like 200 rounds of recursion... So that messes a lot of stuff up. The following code is where I call the recursion:
//Find Solute
try{if(iterations == 0){ //RECONDITION::: iterations is equal to zero at start of program and is static!
remaining = Whitespace.removePreceding(remaining);
String unused = remaining.substring(0);
InterpretInput solute = new InterpretInput(remaining);
solute.begin();
solute.fixSoluteAmount();
soluteAmount = solute.getSolventAmount();
isSolution = true;
++iterations;
}}catch(Exception ex){
}
finally{
System.out.println("Debugging point D");
findNumber();
fixSolventAmount();
fixSoluteAmount();
}
You'll find "Debugging point D" above, this is printed a ton of times so it apparently is going after the recursion with a bunch of objects, and the rest of the code is screwed up because of this. I just need someone experienced to point out how this is flawed as one iteration of recursion.
If you need the entire class, I'll also copy / paste that bellow, but it's almost 200 lines... so yeah... (I know I shouldn't make classes that long but this object needed a lot of stuff in it).
import java.util.ArrayList;
public class InterpretInput {
/**
* #param remaining - The string that was input, what's left to analyze
*/
/** Variables */
private String remaining; //The string input by the user, containing what's left to analyze
private static int iterations = 0;
//Solvent Info
private double solventAmount; //The amount of the solvent expressed as final in MOLES
private M solventAmountMeas; //The measurement used in solventAmount
private double solventConc; //The concentration of the solvent
private M solventConcMeas; //The measurement used in solventConc
private E[] solventCompound; //The compound of the solvent
private E[] water = {E.H, E.H, E.O};
//Solute Info
private double soluteAmount; //The amount of solute in the solution
//Type of Data
private boolean isElement = false; //Determines if the information input is only an element
private boolean hasAmount = false; //Determines if the information input has an amount of solvent
private boolean isSolution = false; //determines if the information input is a solution
private int identificationNumber;
/** Constructor */
public InterpretInput (String remain){
remaining = remain;
}
/** Mutator Methods
* #throws Exception */
public void begin() throws Exception{
//Find Measurement
FindMeasurements measureObject = new FindMeasurements(remaining);
while (measureObject.exists() == true){
measureObject.determineNumber();
measureObject.determineMeasurement();
double solventAmountTemp = measureObject.getAmount();
M solventAmountMeasTemp = measureObject.getMeasurement();
if( (solventAmountMeasTemp.getType()) == 3 ){
isSolution = true;
solventConc = solventAmountTemp;
solventConcMeas = solventAmountMeasTemp;
}else{
hasAmount = true;
solventAmount = solventAmountTemp;
solventAmountMeas = solventAmountMeasTemp;
}
remaining = measureObject.getRemaining();
}
//Find Compound
FindCompound comp = new FindCompound(remaining);
comp.getCompound();
solventCompound = comp.getValue();
remaining = comp.getRemaining();
if (solventCompound.length == 1)
isElement = true;
//Find Solute
try{if(iterations == 0){
remaining = Whitespace.removePreceding(remaining);
String unused = remaining.substring(0);
InterpretInput solute = new InterpretInput(remaining);
solute.begin();
solute.fixSoluteAmount();
soluteAmount = solute.getSolventAmount();
isSolution = true;
++iterations;
}}catch(Exception ex){
}
finally{
System.out.println("Debugging point D");
findNumber();
fixSolventAmount();
fixSoluteAmount();
}
}
public void fixSoluteAmount() throws Exception {
fixSolventAmount();
}
public void fixSolventAmount() throws Exception {
switch (identificationNumber){ //VIEW findNumber TO SEE INDEX OF THESE CASES
case 1:{
//In this situation, there would be nothing to change to begin with
break;
}
case 2:{
//In this situation, there would be nothing to change to begin with
break;
}
case 3:{
solventAmount *= solventAmountMeas.ofBase();
switch (solventAmountMeas.getType()){
case 1:{ //volume
if (!solventCompound.equals(water))
throw new Exception();
else{
solventAmount *= 1000; //Convert 1000g for every 1L
double molarMass = 0;
for (E e : solventCompound)
molarMass += e.atomicMass();
solventAmount /= molarMass; //convert to moles
}
}
case 2:{ //mass
double molarMass = 0;
for (E e : solventCompound)
molarMass += e.atomicMass();
solventAmount /= molarMass; //convert to moles
}
}
}
case 4:{
if(solventAmountMeas.equals(M.m)){
throw new Exception(); //I AM TAKING OUT THIS FEATURE, IT WILL BE TOO DIFFICULT TO IMPLEMENT
//BASICALLY, YOU CANNOT USE MOLALITY IN THIS PROGRAM ANYMORE
}
}
case 5:{
if(solventAmountMeas.equals(M.m))
throw new Exception(); //I AM TAKING OUT THIS FEATURE, IT WILL BE TOO DIFFICULT TO IMPLEMENT
//BASICALLY, YOU CANNOT USE MOLALITY IN THIS PROGRAM ANYMORE
double molarMass = 0;
for (E e : solventCompound)
molarMass += e.atomicMass();
solventAmount /= molarMass; //convert to moles
}
}
}
public void findNumber(){
/**
* 1 = Element
* 2 = Compound
* 3 = measured amount of compound
* 4 = specific concentration of solution
* 5 = Measured amount of specific concentration of solution
* */
if(isElement==true)
identificationNumber = 1;
else if(isSolution == false && hasAmount == false)
identificationNumber = 2;
else if(isSolution == false && hasAmount == true)
identificationNumber = 3;
else if(isSolution == true && hasAmount == false)
identificationNumber = 4;
else
identificationNumber = 5;
}
/** Accessory Methods */
public double getSolventAmount(){
return solventAmount;
}
public double getSoluteAmount(){
return soluteAmount;
}
public double getConcentration(){
return solventConc;
}
public E[] returnCompound(){
return solventCompound;
}
}
Your Begin function appears to call itself prior to incrementing the iterations variable. This will cause an infinite recursion. See my HERE notes in the code below.
//Find Solute
try{if(iterations == 0){
remaining = Whitespace.removePreceding(remaining);
String unused = remaining.substring(0);
InterpretInput solute = new InterpretInput(remaining);
// HERE - calls itself again, prior to incrementing
// iterations variable
solute.begin();
solute.fixSoluteAmount();
soluteAmount = solute.getSolventAmount();
isSolution = true;
// HERE - iterations is incremented, but too late
++iterations;
}}catch(Exception ex){
}
To resolve the recursion issue, you should increment iterations prior to the begin call.
The code here is pretty messy; it's a little difficult to figure out what the goal is. What are you trying to do with the string in InterpretInput, and why does it take such a complex solution (recursively built objects) as opposed to a loop or even just a recursive method?
Beyond that, however, it doesn't appear that there should be any way for your recursion to break. The only valid way for it to do so is if iterations != 0, which is never true because the ONLY time iterations is ever incremented is after the recursive call. Thus, I think the only reason the program terminates at all is that you overflow the stack, but the exception is caught by the empty catch block. Try printing something out in that block; I bet that's where the code is going even if you don't expect it to.