Recursion -- how to do an action only at the end - java

I have a binary search tree where each node (GameEntry class) represents one "game play" (a name/score pair). The tree is organized by name (not score). I'm trying to write a method for the tree to print a list of its top ten scores (with the corresponding name). I thought of traversing the tree recursively, putting a node in an array (ScoreBoard class) if (and only if) it's a high score. It works, except my problem was that the scoreboard would print every step of the way in the recursion.
public void printTopTen()
{
ScoreBoard board = new ScoreBoard(10); // new scoreboard with capacity of 10
printTopTenRecur(this.root, board);
}
// Auxillary method for printTopTen()
private void printTopTenRecur(GameEntry node, ScoreBoard board)
{
if (node == null)
{
return;
}
printTopTenRecur(node.getLeft(), board);
board.add(node); // adds the node to the scoreboard if it's a high score
System.out.println(board);
printTopTenRecur(node.getRight(), board);
}
The only thing I could think of was to create an attribute (called board) on the class and then print out the attribute after the recursion is done. But I'm getting the compile time error void cannot be converted to String. I'm not sure how else to do it.
public String printTopTen()
{
ScoreBoard board = new ScoreBoard(10); // new scoreboard with capacity of 10
printTopTenRecur(this.root, board);
return System.out.println(this.board);
}
// Auxillary method for printTopTen()
private void printTopTenRecur(GameEntry node, ScoreBoard board)
{
if (node == null)
{
return;
}
printTopTenRecur(node.getLeft(), board);
board.add(node); // adds the node to the score board if it's a high score
this.board = board; // assign local board to the board on the tree
printTopTenRecur(node.getRight(), board);
}

I'm not a great fun of recursion, especially not it java, the main reason is that you risk a stack overflow if you go too deep. Other languages deals with this problem allowing tail calls to be implicitly transformed into a while loop (like scala for example).
That being said, recursion without return value sounds really odd to me, while the suggestion of moondaisy addresses your problem I would rather return the score instead of relying on a field.
private ScoreBoard printTopTenRecur(GameEntry node, ScoreBoard board){
if(node == null )
return board;
board.add(node);
ScoreBoard leftBoard = printTopTenRecur(node.getLeft(), board);
ScoreBoard rightBoard = printTopTenRecur(node.getRight(), leftBoard);
return rightBoard;
}
public void printTopTen(){
ScoreBoard board = new ScoreBoard(10); // new scoreboard with capacity of 10
// No need to return anything if you want to just print the result
System.out.println(printTopTenRecur(this.root, board));
}
A side note:
ScoreBoard leftBoard = printTopTenRecur(...) is pretty useless like that, board is mutable so passing it sufficient.
When I think recursive I also think immutable, so I would rather have liked a ScoreBoard newBoard = board.update(node); returning a new updated ScoreBoard, like this:
ScoreBoard currentBoard = board.update(node);
ScoreBoard leftBoard = printTopTenRecur(node.getLeft(), currentBoard);
ScoreBoard rightBoard = printTopTenRecur(node.getRight(), leftBoard);
This way printTopTenRecur is a function without side effects, so a proper function.

But I'm getting the compile time error void cannot be converted to String
You are getting that error because System.out.println(this.board); is not a String and have stated that printTopTen should return a String.
If all that you want to do is printing the board at the end of the recursion you could do this:
public void printTopTen()
{
ScoreBoard board = new ScoreBoard(10); // new scoreboard with capacity of 10
printTopTenRecur(this.root, board);
System.out.println(this.board);
}
This will show whatever you have defined in the toString method of the ScoreBoard class.
If what you want to do is return the String you can do it like this:
public String printTopTen()
{
ScoreBoard board = new ScoreBoard(10); // new scoreboard with capacity of 10
printTopTenRecur(this.root, board);
return this.board.toString();
}

Related

Class which removes objects from array in main

I'm working on an object-oriented program in Java that allows you to keep track of a horde of zombies. A zombie can be identified either by a unique id number or a single name, and we want to note how many limbs each zombie currently possesses. Zombies may leave the horde either by their own accord or removed by a zombie hunter.
Currently I'm trying to work on the zombie hunter class, I need it to remove objects from an array of zombies in main after it meets a certain condition, and the other classes should be done I believe:
zombieHorde.java
public class ZombieHorde{
int hordeSize = 0;
public ZombieHorde(int hordeSize){
Zombie zombies = new Zombie[hordeSize];
hordeSize++;
}
}
zombie.java
import horde;
public class Zombie {
int hordeSize = 0;
public Zombie(String name, int limbs) {
this.name = name;
this.limbs = limbs;
}
public int loseLimbs() {
limbs--;
}
public int getLimbs() {
return limbs;
}
public void leaveHorde() {
hordeSize--;
}
}
main.java
// accuracy to determine if a zombie hunter kills its mark,
// then if it does I can decrease the horde size and get rid
// of the object/kill the zombie, use random for determining
// # of limbs, and if zombies join a horde, etc.
// main class creates a horde, creates zombies and adds them
// to a horde, and the zombie hunter object
// could also have multiple Hordes, ZombieHunters!
import Zombie;
import ZombieHorde;
import ZombieHunter;
public class MyZombieGame{
public static void main(String[] args){
// creates horde
ZombieHorde h = ZombieHorde(hordeSize);
// create zombies and add them to array
Zombie myZombie = Zombie(Chuck, 4);
// create zombie hunter to remove from array?
}
}
And zombiehunter.java
import horde;
public class ZombieHunter{
public void shootAt(name){
}
}
What I'm thinking is I could have an accuracy assigned to a zombie hunter, and then compare that to a random number, and if the accuracy is higher, then the zombie hunter hits its mark and kills a zombie, then I remove a zombie object from the ZombieHorde array in main! If that makes sense, although I'm a little tripped up by them leaving on their own accords, any ideas would be awesome about an approach to this and how I should go about removing the objects from the array.
I'm brand new to Java so there might be some errors I apologize if this is the case! Just looking for a push in the right direction!
You might want to concider using some sort of map (i.e. a Hashmap) instead of an array.
public class ZombieHorde{
//note that class attributes are usually private
private int hordeSize = 0; //actually no need for hordSize here, you could just use .size();
private HashMap<String, Zombie> zombieHorde;
public ZombieHorde(){
//instanciate Hashmap
this.zombieHorde = new HashMap<String, Zombie>();
}
public void addToHorde(Zombie zombie){
//assuming there is a get name method implemented
this.zombieHorde.put(zombie.getName, zombie);
this.hordeSize++;
}
public void removeFromHorde(Zombie zombie){
//assuming there is a get name method implemented
this.zombieHorde.remove(zombie.getName);
this.hordeSize--;
}
}
On a map you can use functions like add and remoive which makes it useful for usecases like this. If you wanna know the hordeSize you can also just use zombieHodre.size()
(Not sure if my code is 100% correct but you should get the idea).

Card - Deck - Hand Java Project

I know everyone gets skeptical whenever people put homework on here but I've run out of options and could really use some direction. I have a project where I have to create a deck of cards and allow the user to pick the size of the hand and then fill that hand with random cards and display that to the user. I've found plenty of answers using ArrayLists but mine requires an array and I've tried everything I know and my code is either completely wrong or throws a bunch of errors.
So here are the problems I have:
1) The addCard method in the Hand class can be used to add one Card object at a time to the hand array until it is full. It should increment the cardsInHand counter each time a Card object is added to the Hand as long as there is room for the Card to fit into the Hand.
Here is the code for the Hand class:
public class Hand
{
private int handSize; //Holds the size of the hand
private int cardsInHand; //Holds the number of cards allowed in the hand
private Card[] hand; //Array of card objects
public Hand()
{
this.handSize = 5;
this.cardsInHand = 0;
this.hand = new Card[52];
}//end Default Constructor
public Hand(int handSize)
{
this.handSize = handSize;
}//end Parameterized Constructor
public Hand(Hand handIn)
{
this.handSize = handIn.handSize;
this.cardsInHand = handIn.cardsInHand;
this.hand = handIn.hand;
}//end Copy Constructor
public void addCard(Card card)
{
hand[card]; //--> throws a type mismatch exception (change card param to an int)
}//end addCard()
public int getHandSize()
{
return handSize;
}
public void setHandSize(int handSize)
{
this.handSize = handSize;
}
public int getCardsInHand()
{
return cardsInHand;
}
public void setCardsInHand(int cardsInHand)
{
this.cardsInHand = cardsInHand;
}
public Card[] getHand()
{
return hand;
}
public void setHand(Card[] hand)
{
this.hand = hand;
}
public String toString()
{
String msg = "";
return msg;
}//end toString()
}//end class
My addCard method is just all janky and I could really use some help trying to fill it so my program works. Any help or even a pointing in the right direction would be appreciated!
My addCard method is just all janky and I could really use some help trying to fill it so my program works. Any help or even a pointing in the right direction would be appreciated
Sometimes the best thing to do is stop, turn the screen off, get a pen and piece of paper and just nut it out without any code. Try to understand the problem and get the logic straight in your head.
Basically, you have a series of buckets into which you can put a Card. Before you can put a Card in a bucket, you need to know if you have any free buckets available.
If there are, you need to add the Card to the next available bucket (which should be pointed to by cardsInHand) and increment cardsInHand
Your error is because you're trying reference a "bucket" using a Card, but you can only reference a "bucket" by an index (number) so...
hand[card];
should be more like...
hand[cardsInHand] = card;
but only after you've determined if there is a free "bucket" available, and you should increment cardsInHand AFTER this statement
I'd also be worried about your constructors
public Hand(int handSize)
{
this.handSize = handSize;
}//end Parameterized Constructor
isn't initialising hand, so that's going to be null. A better solution might be to use existing constructors where possible to build a common "initialisation" path
public Hand() {
this(5);
}//end Default Constructor
public Hand(int handSize) {
this.handSize = handSize;
this.cardsInHand = cardsInHand;
this.hand = new Card[handSize];
}//end Parameterized Constructor
Also
public Hand(Hand handIn)
{
this.handSize = handIn.handSize;
this.cardsInHand = handIn.cardsInHand;
this.hand = handIn.hand;
}//end Copy Constructor
is worrying, as it's possible for some external class to make a change to handIn's hand and that change will be reflected by this instance as well (as they are pointing to the same array).
A "copy" constructor should be making a "copy" of the data. Realistically, this should probably be a "deep" copy, so any changes to Card don't mess with the Hand as well, but I'll start with a simple "shallow" copy to get you started
public Hand(Hand handIn) {
this.handSize = handIn.handSize;
this.cardsInHand = 0;
this.hand = new Card[this.handSize];
// Yes, I know there is a better way to do this, but
// I want the OP to learn something
for (int index = 0; index < handIn.hand.length; index++) {
Card card = handIn.hand[index];
if (card != null) {
hand[cardsInHand] = card;
cardsInHand++;
}
}
}//end Copy Constructor
#MadProgrammer already give better answer, I only want to chime a little. Knowing the OP project assignment using Java I want to comment a little about the Hand class design.
The task clearly said that user can pick hand with custom size, then the user will add card into the hand until the hand is full. Thus, I would propose the Hand class design like below.
public class Hand {
private int size; // Hold the amount of card can be hold by hand.
private int counter; // Count how many card added.
private Card[] cards; // The card on hand.
public Hand(int size) {
this.counter = 0;
this.size = size;
this.cards = new Card[size];
}
public void addCard(Card card) {
if (this.counter > this.size) {
throw new IllegalStateArgument("The hand is full of card!");
}
this.cards[this.counter] = card;
this.counter++;
}
public String show() {
StringBuilder result = new StringBuilder("The card on hand is: \n");
for (int i=0; i<this.size; i++) {
result.append(this.cards[i].toString()).append("\n");
}
return result.toString();
}
}
In my opinion the Hand class more easy to understand and achieve the goals of the Hand purpose from the task. However, just use this as reference and write code that you understand well.

Java element of a new List using a Set

I have the method changePlayer() that sets an element from the set players from the class Model as the value of the field currentPlayer of Model; since I can't get elements directly from a set, so I created a new ArrayList using that set.
What I want to know is that if that element created is still using the reference from the old one or has a new reference and therefore any change I make to it will not change the original element from the set created in Model.
public class Model extends Observable<Change> {
private Set<Player> players;
private Player currentPlayer;
public Model() {
players = new HashSet<Player>();
}
public void addPlayer(Player player) {
currentPlayer = player;
this.players.add(player);
}
public Set<Player> getPlayers() {
return Collections.unmodifiableSet(this.players);
}
public Player getCurrentPlayer() {
return currentPlayer;
}
public void setCurrentPlayer(Player currentPlayer) {
this.currentPlayer = currentPlayer;
}
}
public void changePlayer(Model game) {
Player player2 = new Player(0);//the id in this case is 0
//this is the part of the code where i create a list using the set
List<Player> playersList = new ArrayList<Player>(game.getPlayers());
for (int i = 0; i < playersList.size(); i++) {
... // some code that will set player2 by player2 = playersList.get(i)
}
// change the current player for the game
game.setCurrentPlayer(player2);
}
You're only creating a new List, but the references in the List are still the same references(the reference values are copied but the values still point to the same instances of Player, which is similar to no matter how many times of your passport number is copied, the number still identifies you). Thus, if you change the referenced Player in your method, you're actually changing the Player in your original Model, which is obvious, since you haven't created any new Player in your method body, have you? The Player instances won't just magically be copied since they are not primitive types. There will be only one exception that you're actually cloning all the Player instances, which is in your game.getPlayers(), you actually deep copied every Player. However, this is not what programmers would usually do.

Add card to hand in blackjack

How do I add a card to my hand when it says "addCardToHand" I tried card++; and hand++; neither worked. Is there a problem with my code, or did I just left something out? I feel like I need to add something but, I don't know what.
private AbstractCard[] hand;
private int winCount;
public AbstractPlayer() {
hand = new AbstractCard[0];
}
public AbstractPlayer(int score) {
}
public void addCardToHand( AbstractCard card ) {
AbstractCard[] NewHand = new AbstractCard[hand.length+1];
for ( int i = 0; i < NewHand.length; i++) {
NewHand[i] = hand[i];
}
}
public void resetHand() {
hand = new AbstractCard[0];
}
I think it's probably because hand[] has nothing in it. It gets created as an array with size 0, (no elements), and then when you add a card, you pull from the hand[] at index 0, but since the hand[] has no elements, it's not pulling from anywhere.
Basically, nowhere in your code does hand[] ever get to be an array with any elements in it, so when you take from hand[0] there's nothing there, because in hand = new AbstractCard[0];, [0] is the size of the array.
EDIT:
You might want to look into using an ArrayList (Oracle documentation) (Stack Overflow post), because they don't have a pre-defined size. In your case, you're adding elements as you go, so an ArrayList be very helpful. With an ArrayList, you won't have to constantly create new arrays.
You probably want to keep track of the next insert position for cards with some state like private int insertCursor = 0;
Your addCardToHand(AbstractCard) method can then simply be
public void addCardToHand(AbstractCard card) {
hand[insertCursor++] = card;
}

Java Inheritance - Getting a Parameter from Parent Class

I'm trying to take one parameter from the parent class of Car and add it to my array (carsParked), how can i do this?
Parent Class
public class Car
{
protected String regNo; //Car registration number
protected String owner; //Name of the owner
protected String carColor;
/** Creates a Car object
* #param rNo - registration number
* #param own - name of the owner
**/
public Car (String rNo, String own, String carColour)
{
regNo = rNo;
owner = own;
carColor = carColour;
}
/** #return The car registration number
**/
public String getRegNo()
{
return regNo;
}
/** #return A String representation of the car details
**/
public String getAsString()
{
return "Car: " + regNo + "\nColor: " + carColor;
}
public String getColor()
{
return carColor;
}
}
Child Class
public class Carpark extends Car
{
private String location; // Location of the Car Park
private int capacity; // Capacity of the Car Park - how many cars it can hold
private int carsIn; // Number of cars currently in the Car Park
private String[] carsParked;
/** Constructor for Carparks
* #param loc - the Location of the Carpark
* #param cap - the Capacity of the Carpark
*/
public Carpark (String locations, int room)
{
location = locations;
capacity = room;
}
/** Records entry of a car into the car park */
public void driveIn()
{
carsIn = carsIn + 1;
}
/** Records the departure of a car from the car park */
public void driveOut()
{
carsIn = carsIn - 1;
}
/** Returns a String representation of information about the carpark */
public String getAsString()
{
return location + "\nCapacity: " + capacity +
" Currently parked: " + carsIn +
"\n*************************\n";
}
}
Last Question Method
public String getCarsByColor (String carColour)
{
for (int num = 0; num < carsParked.length; num++)
{
if ( carColour.equals(carsParked[num]) )
{
System.out.print (carsParked[num]);
}
}
return carColour;
}
I have this so far so that if "red" is put in the parameters, it would list all the cars with the color red and it's corresponding information but does not seem to work ~_~.
You seem to have the wrong relationship here: a car park is not a car. I would recommend against using inheritance in either direction between these classes. And Carpark should probably just have an array or collection of cars.
Also note that the parameter carsIn isn't necessary - just get the length of the array of cars (or size() if it's a Collection).
Edit: Okay, ignoring the inheritance part, it seems like it makes sense to add cars when driveIn is called, and remove them when driveOut is called.
driveIn should probably take a Car as an argument, so the method can access the parameter you want to store (personally I would just store Car references, but fine). Since we're going to be adding and removing these parameters, it'll be much easier to use a List that can resize itself instead of an array, like ArrayList. For example:
private final List<String> carsRegNosParked = new ArrayList<String>();
public void driveIn(Car car) {
carsRegNosParked.add(car.getRegNo());
}
It's less clear what driveOut should do. It could take a specific registration number to remove:
public void driveOut(String regNo) {
carsRegNosParked.remove(regNo);
}
Or it could just indiscriminately remove a car, say the first car added:
public void driveOut() {
if (!carsRegNosParked.isEmpty()) {
carsRegNosParked.remove(0);
}
}
Note the difference between remove(Object) and remove(int).
First change carsParked to a list. So:
private String[] carsParked;
becomes
private List<String> carsParked;
Then in you constructor initialize it to an empty list by doing:
carsParked = new ArrayList();
Then in your drive in method, make it take a car parameter and pull the param you want:
public void driveIn(Car car) {
carsParked.add(car.getRegNo());
}
Also you do not need to keep track of the number of cars this way. Since you could always do carsParked.size() to find out.
Now I would probably change that list to be List<Car> instead of string and just dump the whole car in there. Sure you may only need one item right now, but who knows down the road, maybe you will need something else.
EDIT:
Sure you could do it with an simple array. The issue with that is sizing. Say you initially create an array of size 5, when you go to add the 6 item you will need to create a new larger array, copy the original data, then add the new item. Just more work. Now if the idea is you have a carpark, and it can have X number of spots then you initilize your array to that size from the begining.
public Carpark (String locations, int room){
location = locations;
capacity = room;
//this creates an array with the max number of spots
carsParked = new String[capacity];
//also good idea to init
carsIn = 0; //initial number of cars parked
}
then in your driveIn() method:
public void driveIn(Car car) {
carsParked[carsIn] =car.getRegNo();
carsIn=carsIn+1;
}
now driveOut()
public void driveOut(Car car) {
//loop through the array until we find the car
for (int i=0; i < carsParked.length; i=i+1){
if (car.getRegNo().equals(carsParked[i])){
//we found the car, so set the space null
carsParked[i] = null;
carsIn=carsIn-1;
//stop looping now
break;
}
}
}
Looks nice doesn't it. Well no it is not. Now the driveIn will not work, since we have null spots scattered all over the place. How do we fix it:
public void driveIn(Car car) {
//loop through the array until we find a null spot,
//then park the car
for (int i=0; i < carsParked.length; i=i+1){
if (carsParked[i] == null){
//we found the car, so set the space null
carsParked[i] = car.getRegNo();
carsIn=carsIn+1;
//stop looping now
break;
}
}
}
It could still be improved further. I would probably still change String[] carsParked to Car[] carsParked as to not throw away information.
I would also change the driveIn and driveOut methods to return booleans to indicate if the successfully parked or un-parked a car.
Final Edit:
Okay, if you want to keep track of what cars are parked in the car park and which spot they are in you need to know enough about each car to make it unique. In your case you may only need regNo. So when you call driveIn or driveOut you have to pass that information so we can store it at the appropriate index (parking spot) in the array. Otherwise all you will know is a car was parked somewhere, or that a car left. Not which spots are open.
So in short the parameter Car car in those two methods contain the information needed to uniquely identify each car that is being parked, or is leaving. Without it the car park instance would have no clue who is currently parked, or where they are parked.

Categories

Resources