I've researched this and so far not found what I was looking for here on the site. I'm more or less trying my hand at a semi-basic text based adventure type game where the player chooses an option such as (l)ook, (w)ander, (s)leep, etc. I've created the class for Room, and have initialized it and all the rest, and descriptions and the like are set. Inside one of the options, you enter a cave, and I have not learned enough from others and my teacher to allow the description of the area you are in to change. The lines of code so far for this are as follows:
public void Gameloop(Room startRoom)
{
String input;
boolean notDead = false;
Room currentRoom = startRoom;
while(!notDead)
{
//Shows description of the room
input = JOptionPane.showInputDialog(null, currentRoom.getDescription() + " What do you do? \n(l)ook around\n(g)rab a stick\n(s)leep.");
that is for the start of the game where you are in a forest. The description shows properly and advancement through choices is all proper. The problem is with this area of code
if(input.equalsIgnoreCase("l"))
{
input = JOptionPane.showInputDialog(null,"You see trees and a cave. Do you want to go into the casve? \n(y)es \n(n)o");
if(input.equalsIgnoreCase("y"))
{
input = JOptionPane.showInputDialog(null,currentRoom.getDescription() + " Do you want to set up a camp?\n(y)es\n(n)o");
The problem specifically is that I have not learnt how to implement room changes at all, otherwise, the game basis would be sound and do-able, options would be more well thought out and an item system would later be implemented. Basically, how do I change the "room" the person is in. Note, this game has no GUI and is literally based on you typing a letter for each action
I would make use of the Strategy pattern here. Ill give you some pseudo code to get you started :), note this doesnt compile.
The idea is that you make a IRoom interface. This will allow you to make as many different kind of rooms as you like. Each room can define the actions that are possible in this room, so you can add certain actions to a forest room for example.
It also has a method that will make sure the room performs the action. This could result in a roomchange, thus it will return a new IRoom.
public class Game {
private IRoom currentRoom;
public void Gameloop(IRoom startRoom){
while(!notDead)
{
//Shows description of the room
input = JOptionPane.showInputDialog(null, currentRoom.getDescription() + " What do you do? " + dissplayPossibleActionsToUser(startRoom.getPossibleActionsInRoom()));
Action chosenAction = dericeActionFromImput(input);
currentRoom = startRoom.performAction(chosenAction);
}
}
}
public interface IRoom{
//Returns all the actions the current room provides
List<Actions> getPossibleActionsInRoom();
//Does the action
IRoom performAction(Action action);
}
public enum Actions{
LOOK, WANDER, SLEEP;
}
public class Forest implements IRoom{
public List<Actions> getPossibleActionsInRoom(){
return new ArrayList(Actions.wander);
}
public IRoom performAction(Action action){
if(action == wander){
return new HouseRoom();
}
}
}
Related
short description of what I am trying to do: I'm building a simple game where the user controls a vehicle and after some time more and more ghosts begin following the player, they follow the same trajectory as the player did with a delay.
To accomplish this I create an Array that contains the history of the player's location as a sequence of points. The problem, however, is that when I look at the data stored in this array I see that on all indices only the most recent location is stored.
First I create the array in a botManager class:
public class BotManager {
private ArrayList<Bots> bots;
private List<Point> history;
BotManager() {
history = new ArrayList<>();
bots = new ArrayList<>();
}
Then in the update method of the manager class I add the current location of the player to the array
public void update(Point currLoc) {
history.add(currLoc);
for (Bots bot : bots) {
bot.setLocationData(history);
bot.update();
}
}
A look at the update method in the main GameView class, in case I forgot something here
public void update() {
player.update(playerPoint);
botManager.update(playerPoint);
}
In the bots class' constructor I pass the history list (locationData) and determine its length to find out the delay in positioning. After which the following code handles the position of the bot.
#Override
public void update() {
loc = locationData.get(delay - 1);
this.rectangle = new Rect(loc.x - Constants.BOTSIZE/2, loc.y - Constants.BOTSIZE/2,
loc.x + Constants.BOTSIZE/2, loc.y + Constants.BOTSIZE/2);
}
To get back to the problem, whenever I check the contents of the history array, I find that it only contains one point on all indices, and its the most recent even when I moved the player, causing the ghost to always remain on top of me.
So my question here is, what am I doing wrong here?
Not clear from your posted code, but could it be, that you are just modifying the Point which you are adding instead renewing your object's Point objects?
Try
public void update(Point currLoc) {
history.add(new Point(currLoc)); // new Point object added here
for (Bots bot : bots) {
bot.setLocationData(history);
bot.update();
}
}
So I have this homework where I need to build a vending machine, and I assigned a coordinate to every product (A1, A2, A3..) and when the user enters the coin value I have to calculate if he can buy the product that he chose and if yes calculate the change, since i'm still new to programming I now have ended up with many statements like this
if ("a1".equals(choice)) {
System.out.println("You chose SNICKERS!");
if (money < 50) {
System.out.println("This is not enough money to buy this product");
} else if (money >= 50) {
System.out.println(" Price = 50 Your change = " + (money - 50));
}
}
where the only things changing are the coordinates (a1, a2, a3, a4, b1, b2 and so on) and the prices. What would be a better way to do this?
You could use a more OO approach.
Make a class called Product:
class Product {
private String name;
private int price;
public String getName() { return name; }
public int getPrice() { return price; }
public Product(String name, int price) {
this.name = name;
this.price = price;
}
}
Then, create a HashMap<String, Product> and add all your products and their coordinates in:
HashMap<String, Product> productMap = new HashMap<>();
productMap.put("A1", new Product("Snickers", 50));
productMap.put("A2", new Product("Something else", 40));
// do this for every coordinate...
Now, you can just use this code:
Product chosenProduct = productMap.get(choice);
System.out.println("You chose " + chosenProduct.getName() + "!");
if (money < chosenProduct.getPrice()) {
System.out.println("This is not enough money to buy this product");
} else {
System.out.println(" Price = " + chosenProduct.getPrice() + " Your change = " + (money - chosenProduct.getPrice()));
}
This is a common moment in programming and you're right to think there's a better way to go about it.
In your particular case, where you have a similar structure of code in many places, you should try using a function. Try writing a private function in the same class that takes in some of the parameters that change. Depending on the level of complexity you end up with you might end up with a large function with a lot of parameters which isn't great either. Regardless, writing a function is probably the first place you should go when you encounter this situation.
Secondarily, consider what this segment of code is doing. Making a generic function to replace the whole code segment might not be ideal but could you easily write a function to do a small part of it? If so, is it now easy to make the rest into another function? Keep track of any variances you have across your many similar code segments, if any, and try to create functions that address those variations.
Finally, depending on what is in scope for your current level of programming, you might be able to create data structure to help with the identification of the choice. For example, maybe you could make a map where you could store each of the choices and an associated object that contains all of the data you need to respond to the user (i.e. cost, item name, etc.). With that kind of approach you can pre-populate all of those options in a straightforward manner and have your code simply look up the set of data associated with the choice and call of function to print the necessary output.
Ultimately, how you go about this and future situations like it is highly dependent upon what your level of experience with programming, how many choices there are, and how complex the data associated with each choice is.
Continue to trust your instincts though, they will serve you well.
Switch case is the desired functionality.
switch(choice) {
case 'a' : <some code>
break;
case 'b': <some other code>
break;
default: <if none of the choices matched>
}
The only caveat is that your choice value has to be a char or an int
EDIT:
This was a bad answer from my side. Clearly, you need a more cleaner way to write your vending machine.
A good way to structure it would be to first create a Product class which can store the name and the price of the product.
class Product {
private String name;
private String price;
// Implement a constructor and an equals() method to equate two
// instances of product
}
You could then create a function (which could be used in your main()) which takes the text input from your user and map it to an actual product.
public static Main(String[] args) {
// ...
private Product processUserInput(String productName) {
// Add logic to process the string and return a Product
}
// ...
}
Then you could add a function that would process the Product and the amount the user has and return the change remaining or maybe -1 if the product costs more than the available amount.
public static Main(String[] args) {
// ...
private int processUserProductChoice(Product product, int amountAvailable) {
// Add logic to process the product and amount
// Probably use switch case now.
}
// ...
}
I have the following method:
private boolean reserveSeat(int selectedRow, int selectedSeat) {
if (show.getRows().get(selectedRow).getSeats().get(selectedSeat).getReservationStatus()) {
return false;
} else {
show.getRows().get(selectedRow).getSeats().get(selectedSeat).reserve();
setRowNumber(selectedRow);
setSeatNumber(selectedSeat);
return true;
}
}
which resides in a Reservation class. This class has a Show Object (show), A show has Rows (another object), Rows have Seats (another object).
My question is could this method be improved? I have read about LoD and worried that my dot signals a bad design though I think it is logical. It is the Seat object that knows if it is reserved or not. However is going from Show to Seat talking to strangers? or is it ok because of the way each object contains the next object?
Apologies if my questing is not clear. What seems to happen with me (probably because I am self taught) is I design stuff that works then I read some OOP design principles and think crap, it works but it is not good design!
Any advice appreciated.
Yes, that chain of calls is way too long.
If show is in charge of the seats,
then it would be better if it's fully in charge.
Right now it's not fully in charge,
because seats can be reserved without the show's knowing.
This fragmentation of responsibilities is strange.
You can put show fully in charge by not exposing Seat to the Reservation,
by hiding the seat status manipulations behind helper methods:
private boolean reserveSeat(int selectedRow, int selectedSeat) {
if (show.isSeatReserved(selectedRow, selectedSeat)) {
return false;
} else {
show.reserveSeat(selectedRow, selectedSeat);
setRowNumber(selectedRow);
setSeatNumber(selectedSeat);
return true;
}
}
Or, if you don't want show to be in charge of the seats,
then it should not be aware of the seats at all,
so then you would access seats not through show,
but another class that's in charge of that.
You're using show as a data object, and putting all the logic for handling that data in the class that contains it. This makes Show a data class and the enclosing class a god class.
The logic for handling data inside of show should really be inside the Show class itself (data is smart).
You could make a method in the Show class for reserving a seat. And equally, you could make a method in the Row class for reserving a seat.
Then one just passes on the message to the next until you get to Seat.
What if you changed the implementation of Show to use a 2D array for instance? That would break the code in your reservation class.
By doing these long chained calls, and not letting classes handle their own data. You are making the user classes dependent on the implementation the used data structures.
If you wanted to change one, you would have to update all the user classes, instead of just the one class that contains the data structure.
So thanks for the suggestions, the feedback really helped with my learning. So what I went on to do was the following, based on the relationsip--> A Reservation (now called Booking) has a Show, A Show has a Row, A Row has a Seat(s).
In the Booking class I now have this: Thanks #janos
private boolean reserveSeat(int selectedRow, int selectedSeat) {
if (show.isSeatReserved(selectedRow, selectedSeat)) {
System.out.println("Sorry, that seat has already been booked");
return false;
} else {
show.reserveSeat(selectedRow, selectedSeat);
setRowNumber(selectedRow);
setSeatNumber(selectedSeat);
System.out.println("This seat has now been booked.");
return true;
}
}
In the Show class I have this:
public boolean isSeatReserved(int selectedRow, int selectedSeat) {
if (getRow(selectedRow).getSeatStatus(selectedSeat)) {
return true;
} else
return false;
}
and in the Row class I have
public boolean getSeatStatus(int selectedSeat) {
return getSeat(selectedSeat).getReservationStatus();
}
I thought it may be useful to other people just starting out (like me) to show this graphically using before and after diagrams taken from the jarchitect tool which shows what a mess my code was in! I used the same logic to tidy up some other classes that "knew too much".
I have been asked to model a foodstore that contains different types of food. I should be able to add a given quantity of a food type by using the addFood method and remove food using the takeFood method. The addFood must take the form addFood(String, int) and the takeFood must take the form takeFood(String), i.e. addFood("Steak", 5) would add 5 items of steak to the foodstore. I have attempted to make this class and wondered whether this meets what I have been tasked to do. For the sake of this example I will only use 2 food items but in reality there is much more.
public class Foodstore {
public void addFood(String food, int quantity) {
addFood("steak", quantity);
addFood("hay", quantity);
}
public void takeFood(String food) {
takeFood("Steak");
takeFood("hay");
}
}
Thanks in advance
Your food store is missing a warehouse
Map<String,Integer> warehouse = new HashMap<>();
and, as it is, when you add food you're ignoring the food you were told to add, not a good idea.
These are just some starting point, reorganize your code and explore your warehouse when you add data to make sure you're doing well.
I don't think so, you would need some kind of register where you actually save the information, like a Map:
Map<String,Integer> register = new HashMap<>();
You would have to rewrite your functions sth like this (have not been able to type it in an editor, but just so that you get the idea of it):
public void addFood(String food, int quantity) {
if (register.containsKey(food)) {
Integer newAmount = register.get(food) + quantity;
register.put(food,newAmount);
}
else {
register.put(food,quantity);
}
}
PS. You are (mis)using recursion, and I don't think it's what you want in your case. Your function addFood calls itself again and again without an end.
I'm attempting to make a simple Blackjack game written in Java and consisting of a Blackjack (Tester), Card, Deck, Dealer, Player, and Game class.
My code is still very much incomplete, but I'm having difficulty determining, once I've created a deck of cards, which class I should be dealing the cards in and how I should be storing the Card objects in both the player and the dealer's hand (arrayLists).
For example, I thought I could solve the issue by using hand.add(deck.draw()); to the player class, thereby adding the Card drawn from my array cards to the arraylist hand. However, in order to do this I have to create a deck object in my player class, which is then different than the deck object that I create in my Game class. However, if I draw the card in the Game class using deck.draw(), I'm unsure of how to take that value and store it in the arraylist hand within my Player class.
Hopefully this is making sense!
Essentially, my question is if I use my deck.draw method in the Game class which returns a Card, how do I then take that Card and store it in my private arraylist hand in the Player class? Or is this the wrong approach entirely?
Thank you for any guidance you can provide!!!
First, seeing your code before your edit, I wanted to point out that I think you're doing pretty well for a new developer,keep at it!
I think you simply should keep following the path you're on...you've used domain language to name you're model (Deck, Card, Dealer, etc) and you've got a good start in naming the behavior of those classes based on the model too (draw). Stick with this...
Anyway, hope this helps below...it's pseudo-code (in this case, my way of saying I didn't write this on an IDE and I didn't validate the code...but it should be quite close) =)
Dealer should manage the Deck, so there should be an aggregate relationship there. Since the Dealer has the instance of the Deck (the Deck is backed by an array and its position is recorded by an int, no need for a Collection type) length of 52). On construction, the 52 Card instances are added to the array. The Deck indeed had draw, which increments the card position and returns the Card.
//this interface will make sense a little later
public interface HandManager {
Card draw();
}
public class Dealer implements HandManager {
private Card[] deck;
private int position;
#Override
public Card draw () {
try {
return deck[position];
} catch (ArrayOutOfBoundsException ex) {
//handle when you run out of cards in your deck...do you add another 52?
} finally {
position++;
}
}
}
The Dealer also has a draw method, that takes just a vararg on players (and deals he initial Hand to all players).
//also in Dealer
public void deal (Player... players) {
for (Player p : players) {
Hand hand = initializeHand(); //we'll get back to this in a bit
p.addHand(hand);
}
}
Meanwhile, the Player aggregates the Hand....they own and decide what they want to do with it. The Hand shouldn't really be a simple array because it should be able to easily grow, so a List or Set should do (a Set is probably more appropriate in theory...but because you probably don't need to enforce uniqueness here, there isn't need for that overhead really). But...to future proof it, so you can change it to a Set later if you want, you should program to the Collection interface (you should always try to program against the highest super class if you can, better for code maintenance).
public class Player {
private Hand hand;
//can be named "setHand" if you only want to support one Hand per player, named
//like this because it might be a fun exercise to enable n hands per player later
public void addHand (Hand hand) {
this.hand = hand;
}
}
public interface Hand {
/**
* Returns the cards currently in the hand.
*
* Changes to the returned array are <b>NOT</b> reflected in the hand.
*/
public Card[] getCards();
public void hit();
public void split();
public void fold();
}
Anyway, player acts on Hand, decides to hit, split, fold, etc. The neat thing here is that, in theory, a Player can mange n hands this way ;) Anyway...here is where some magic comes in which will keep your code cleaner: the 'communication' between Player and Dealer happen through the Hand instance. This allows Player to call the shots, but more importantly, allows your applications orchestration to focus not on passing commands from player to dealer and card from dealer to player...but the aspect it needs to: managing the turn based play and knowing when to end the game.
public class ManagedHand implements Hand {
private Collection<Card> cards;
private HandManager manager;
public Hand (HandManager manager, Card[] cards) {
this.manager = manager;
cards = Arrays.asList(cards); //to make this a set, simply pass this into a HashSet constructor =)
}
/**
* Returns the cards currently in the hand.
*
* Changes to the returned array are <b>NOT</b> reflected in the hand.
*/
public Card[] getCards() {
//bonus lesson: look up "defensive copy"
return cards.toArray(new Card[cards.size()]);
}
#Override
public void hit() {
if (isBust()) {
throw new BustException("Need to wait for next hand!");
}
//***RIGHT HERE, Dealer (the HandManager) gives the card on draw request****
cards.add(manager.draw());
}
#Override
public void split() {
if (isBust()) {
throw new BustException("Need to wait for next hand!");
}
//do split...beyond demo code scope =)
}
#Override
public void fold() {
//clean up, take money/car/happiness
}
#Override
public String toString() {
//pretty-print the current hand
}
}
//the initializeHand method is Dealer that I promised
public Hand initializeHand() {
Card[] initialHand = new Card[INIT_HAND_SIZE];
for (int i =0; i<INIT_HAND_SIZE; i++) {
initialHand[i] = draw();
}
//****Dealer registers itself as a HandManager to the Hand**********
return new ManagedHand(this, initialHand);
}
Since Dealer instantiates (creates) Hand, it had the opportunity to register a listener (itself, in this case) for Player actions on the Hand. Since the Player is given the instance of Hand, take action on the Hand...the Hand does the validation itself (ie checks if itself isn't bust before requesting more cards) in this implementation (just because it would be a more complex example to have Dealer do it) and the manager is "notified" when more cards are needed.
Side note: This could have been built out a little more, but in general, it kinda-sorta follows what is called the Observer Pattern. It might not be a perfect match for this pattern...but you should check it out...and read all about design patterns. Learning these early in your career, you'll quickly become a rockstar.
One approach would be to have a function in the Player class called something like AddCard
public class Player
{
private ArrayList<Card> hand;
public Player()
{
hand = new ArrayList<Card>();
}
public void AddCard(Card aCard)
{
hand.Add(aCard);
}
}
Since the cards in a player's hand have no inherent order to them, I think it makes more sense to use some kind of Set (such as a HashSet to store them) than an ordered structure like an ArrayList. I might write something like this. You'll see I've assumed that the draw method of the Deck class returns null if there are no cards left.
public class Player {
private Set<Card> hand;
private String name;
public Player(String name) {
this.name = name;
this.hand = new HashSet<Card>();
}
public boolean takeCard(Deck toTakeFrom) {
Card drawn = toTakeFrom.draw();
if (drawn != null) {
hand.add(drawn);
return true;
} else {
System.out.format("Sorry, %s, no cards remain in the deck.%n", name);
return false;
}
}
}