I'm working on a text-based adventure game and I'm trying to externalise as much of the setup as possible so that I can work with a friend who wants to write the storyline. I have three classes so far. A room class with a title, description, and an array of Exits. Also an Exit class with the following constructor.
public Exit(int direction, Room connection);
Exits also have public int variables referring to the different directions:
public static final int NORTH = 0;
This is all so I can set up an exit on a room by saying:
Room r = new Room("Title","Description");
Room r2 = new Room("Title", "Description");
r.addExit(new Exit(Exit.NORTH, r2);
This would make an exit on the room r that is on the north side and leads to the room r2. Now for the externalisation I'm trying to make a .txt file where I can simply put the current room number, the exit direction (string), and the room number it leads to.
I can do this just fine as far as reading the file goes but where I'm struggling is when I'm setting up the direction, I can't say
Exit. /*String read from file*/
So how can I access those public integers from the Exit class using a string from the txt file?
Try using an enum instead.
public enum ExitDirection { NORTH = 0, … };
ExitDirection foo = ExitDirection.valueOf (stringFromFile);
…else, you'll just have to bite the bullet with something like
if (stringFromFile.equals("NORTH")) { foo = NORTH; }
else if (stringFromFile ... (ad nauseum)
The quick and dirty fix is to implement a method to do string comparison and return the appropriate constant. But you should also consider using an enum as suggested by BRPocock, it's a much cleaner way to do it.
int directionFromStr(String str) {
// Putting the string constant on the left side of the expression guards against null input
if ("NORTH".equalsIgnoreCase(str)) return Exit.NORTH;
if ("SOUTH".equalsIgnoreCase(str)) return Exit.SOUTH;
if ("EAST".equalsIgnoreCase(str)) return Exit.EAST;
if ("WEST".equalsIgnoreCase(str)) return Exit.WEST;
// You could also return -1 or something like that
throw new IllegalArgumentException("bad direction");
}
Related
I don't have idea how to add to array enum. I made constructor using fields with enum and its works, but I don't know how to make it in constructor without field. I hope that you understand what Im thinking about. In my code I comment where I think i have problem.
I've got:
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
System.out.println("name of producer:");
String producername = Main.sc.nextLine();
System.out.println("name of model:");
String modelname = Main.sc.nextLine();
System.out.println("ram:");
int ram = Main.sc.nextInt();
System.out.println("cpu:");
String cpu = Main.sc.nextLine();
cpu = Main.sc.nextLine();
System.out.println("components:");
System.out.println("how many components do you want to add?");
int z = Main.sc.nextInt();
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = //<-- how to add enum in array?
}
setProducerName(producername);
setModelName(modelname);
setRam(ram);
setCpu(cpu);
setComponents(com);
}
My constructor using field is like that and it works.
public Laptop(String ProducerName, String ModelName, int Ram, String Cpu, Components... components) {
super();
this.ProducerName= ProducerName;
this.ModelName= ModelName;
this.Ram= Ram;
this.Cpu= Cpu;
this.components= new Components[components.length];
this.components= Arrays.copyOf(components, components.length);
}
Please help.
You could get the enum value by its name.
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
...
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = Components.valueOf(Main.sc.nextLine());
}
...
}
I'm not 100% clear what you're asking, but you can get an array filled with your enum constants from the enum itself: Components.values() will return an array of all the enum constants. It will essentially return:
new Components[]{Components.WIFI, Components.BLUETOOTH,
Components.CAMERA, Components.SSD}
Side recommendation: don't use Scanner inside of your Laptop constructor, and in fact, get all user interface code out of all constructors and instance methods of that class. All user interface code belongs elsewhere.
So I'm fairly new with programming having done it for maybe just under a year at this point. I'm even more new with Java (I did C++ before). So I have variables like numberHealthPotions, health, attackDamage, and so on, in a class named Fighting. But then in my main class, there are points in the game in which the character picks up a weapon, picks up a potion, or is wounded. I just need a way to say in my main class he was wounded then change the value of the health of the character or whatever.
This is just a snipet of my code to give you an idea...
else if(inputHKitchen.equalsIgnoreCase ("examine")){
System.out.println("Examine what?");
examineWhat = in.nextLine();
if(examineWhat.equalsIgnoreCase("drawer")){
System.out.println("\tYou found a knife!");
attackDamage = 50;
System.out.println("\tYour attack damage has been increased!\n");
System.out.println(houseKitchen);
}
If your variable is static, then it might be
//note this variable must be public or protected
Player.HEALTH = 0;
if its not static, then
Player p = new Player();
p.HEALTH = 0;
I would write a series of public methods for the character that manage these various values.
For example, in the class YourCharacter:
private int attackDamage;
public void addDamage(int value)
{
attackDamage += value;
}
Then in your snippet:
if (examineWhat.equalsIgnoreCase("drawer")){
yourCharacter.addDamage(50);
}
Lots of good game-writing advice for Java can be found at java-gaming.org
The purpose of the program is to calculate the volumes of different geometrical figures (Like a cylinder or a pyramid). I've started out by adding a list where the user can choose between the different figures.
The problem is that I don't know how to make the program know which formula to use. I need to be able to separate the choices instead of just making an int out of the answer.
private void btnAktiveraActionPerformed(java.awt.event.ActionEvent evt) {
String form = listForm.getSelectedValue().toString();
int fo = Integer.valueOf( form );
String höjd = txfHöjd.getText().toString();
int hö = Integer.valueOf( höjd );
String bredd = txfBredd.getText().toString();
int br = Integer.valueOf( bredd );
String radie = txfRadie.getText();
int ra = Integer.valueOf(radie);
String djup = txfDjup.getText();
int dj = Integer.valueOf(djup);
double ACyl = 3.14*ra*ra*hö;
double APyr = (br*dj*hö)/2;
double AKub = br*dj*hö;
double ARät = br*dj*hö;
txfHöjd.setEnabled(false);
txfBredd.setEnabled(false);
txfDjup.setEnabled(false);
txfRadie.setEnabled(false);
listForm.setEnabled(false);
}
private void btnBeräknaActionPerformed(java.awt.event.ActionEvent evt) {
// I know this code won't work, its just a reminder.
if (answer == Cyinder){
System.out.print("volymen är: "+ACyl+" cm^3");
}
}
I don't understand your question very clearly. I would suggest to make a plan to solve your problems.
make a list of figures that program will calculate
make a list of methods to count volumes of those figures
create individual classes, variables etc...
create methods
create main method with user input
You mentioned you don't know which formula to use. I assume there won't be many formulas in your program. I would create an individual method for each individual figure i.e. piramidFormula(), cilinderFormula()...
There is no point to refer to polimorphism when I think your level of programming is very basic at this stage.
I hope that will help you a little bit.
You need a list to hold the things, you seem to understand this just fine.
You need a way to select things. Selection is typically not exactly the same thing as the list, you need a class to be responsible for the "selection" behaviour.
Each thing has a routine that can calculate the volume. That means it will need input parameters. This is where it starts to get tricky, because if you want all of your things to be in the same list, you need to decide how to manage the different input parameters for the different types in the list.
public List<VolumeCalculations> volumeCalculations ...
public interface VolumeCalculation {
public double getVolume();
}
public class CubleCalcuation implements VolumeCalculation {
private double side = 0;
public void setSide(double value) {
this.side = value;
}
#Override
public double getVolume() {
return side*side*side;
}
}
the other volume calculations are left as an exercise to you.
Then you need to put them all in the list
volumeCalculations.add(new CubeVolumeCalculation());
...
But when you select the calculation, you will need "something" to ask for the right input.
public interface CalculationInputGather {
public void setCalcualtion(VolumeCalcuation value);
public void askForInputs();
}
which the one for the CubleCalcuation might look like
public CubeInputGather implements CalculationInputGatherer {
#Override
public void setCalculation(VolumeCalcualtion value) {
if (value instanceof CubeCalcuation) {
this.volume = value;
}
throw new IllegalArgumentException("value must be a CubeCalculation");
}
public void askForInputs() {
System.out.println("enter the side value:");
// read the value
volume.setSide(value);
}
}
then when you know the selected item in the list, you can use a Map of Calcuations to their input gatherers to lookup the right input gatherer for the selected calcuation.
If you already have the list for the user to choose from, maybe consider a map instead. You can have all your shapes as the keys of the map and then the formulas for volume as the values of the map. The list of shapes can be provided to the user via the keySet and their response can be matched back against the map to find the formula.
EDIT: You have your formulas for each shape inside an action event. You'll need to move those into a separate class
public static class Formulas() {
// list all formulas here
private String cylinder = "3.14*r*r*h";
}
Then when you hit the action you can either create a new instance of the Formulas class and use any convenience methods you might write in there.
I have a Sudoku puzzle solver that requires us to use recursion.. The problem is my boolean to check for available space is supposed to update the current position by reference and it is not. What would cause this?
public boolean solve()
{
Coordinate current = new Coordinate();
if (findEmptyGridSlot(current)) { // THE ERROR IS HERE ********** THIS IS SHOWING (0,0) STILL ******************
for (int number = 1; number <= 9; number++)
if (canPlaceNumber(current, number)) {
grid[current.getRow()][current.getColumn()] = number;
if (solve())
return true;
grid[current.getRow()][current.getColumn()] = 0;
} return false;
}else
return true;
}
private boolean findEmptyGridSlot(Coordinate coordinate)
{
boolean found = false;
try{
while (!found)
{
if (grid[coordinate.getRow()][coordinate.getColumn()] == 0)
found = true;
else
coordinate = coordinate.next(); // *****This is supposed to update the current coordinate ******
}
}catch (Exception e){
//CREATE No Empty Cells Exception
}
return found;
}
public Coordinate next()
{
Coordinate result = new Coordinate(row, column);
result.column++;
if (result.column > MAX_COORDINATE)
{
result.column = MIN_COORDINATE;
result.row++;
if (result.row > MAX_COORDINATE) result = null;
}
return result;
}
Java passes by value. This means you are getting a copy of the reference to coordinate. If you point that copy to a new object (i.e. coordinate = coordinate.next) you are only changing the local copy. Now, on the other hand, if you changed an attribute of the object your variable refers to (e.g. coordinate.x = foo or coordinate.setX(foo)) that change will be visible to the caller of your method.
jpm is correct, but I misread the first time so i'm going to try to clarity
private boolean findEmptyGridSlot(Coordinate coordinate)
A reference is passed by value. Think in these terms "coordinate" is a box that holds a piece of paper, on the piece of paper an address is written. coordinate is a box that belongs to only this method and it has its own piece of paper (many pieces of paper may have the same address written on them)
We can look in this box and 'post' things to the address written on the piece of paper, however when we say
coordinate=something
this means write on a new piece of paper the address of 'something'. Throw away the old piece of paper.
This action in no way affects the original 'house' that the first piece of paper had the address on. When my friend Jon updates his address book it doesn't matter what he writes, I still live in my house.
So, if coordinate has some easy substructure (eg x and y) you can 'post' an instruction to change x and y to be equal to the "next" one.
Or as a hack you can enclose a Coordinate inside annother object so you can post an instruction to it to change what the hack class points to
Test Code refered to in comments:
public class Test {
public static void main(String args[]){
String bareMinObject="start";
changeString(bareMinObject);
System.out.println(bareMinObject); //Prints start, change string has no effect
}
public static void changeString(String input){
String temp="end";
input=temp;
}
}
I am creating a text based game and I am having some issues.. This is what I have so far. So far I have a Combat Class, and two Classes for two different Weapons. I am trying to assign hit points to the weapons themselves. But my biggest issue is in the Combat class. I am trying to create it to were there will be random weapon drops at random times and also random Weapons. So far in the Combat class I have this:
public class Combat {
final int chanceOfDrop = 3;
static Weapons[] wepArray = {new M4(), new M16()}
static boolean[] hasWeapon = {false, true};
public static int ranNumberGen(int chanceOfDrop) {
return (int) (Math.random()*1);
}
private void enemyDead() {
boolean canDrop = false;
if(ranNumberGen(chanceOfDrop)==0){
canDrop = true;
}
if(canDrop == true){
givePlayerWeapon(Weapon[Combat.ranNumberGen(Weapons.length)]);
}
private static void givePlayerWeapon(int w) {
hasWeapon[w] = true;
for w <(Weapons.length-1) {
if has weapon[w] {
System.out.println(wepArray[w].getWeaponName);
}
}
}
}
}
}
I have issues when I am creating the new M4(), and the new M16() it says Type mismatch: cannot convert form M4 to Weapons. I do have a class named Weapons, could that be the problem?
And here is my M4 Class, both M4 and M16 Classes are identical
public abstract class M4 {
private Integer weaponDamage = 5;
private Integer weaponAmmo = 25;
private String weaponName = "M4";
public M4(String name, int ammo, int damage) {
name = weaponName;
ammo = weaponAmmo;
damage = weaponDamage;
}
public String getWeaponName() {
return weaponName;
}
public Integer getAmmo() {
return weaponAmmo;
}
public Integer getDamage() {
return weaponDamage;
}
}
I don't think I have any issues here. Maybe my problem lies within this though. Although, I have a Weapons class, but nothing in it. Do I need that?
A few things to fix at first sight:
Create a generic Weapon class that defines some properties that apply to each weapon, like name, damage, ammo, scope multiplier, etc... Then create subclasses for Weapon, like M4 and M16, that specify the properties and eventually add weapon-specific properties.
Add brackets to this line:
System.out.println(wepArray[w].getWeaponName); // Change to getWeaponName()
Remove the abstract keyword from M4.
Fix the ranNumberGen method because it will always return 0 right now. Math.random() returns a float in the range [0,1[. This means that casting it to an int will always result in 0. Multiply it by n to have a random int in the range of [0, n[. You probably want this:
public static int ranNumberGen(int max) {
return (int) (Math.random() * max);
}
Change this line:
givePlayerWeapon(Weapon[Combat.ranNumberGen(Weapons.length)]);
to:
givePlayerWeapon(wepArray[Combat.ranNumberGen(wepArray.length)]);
The syntax of a for-loop is like this:
for (variable-initialization; condition; increment)
So in your case, you want:
for (int i = 0; i < hasWeapon.length; ++i)
{
if (hasWeapon[i]) System.out.println(wepArray[i].getWeaponName());
}
You might want to revisit your decision to use an inheritance-style heirarchy for game objects before it is too late.
In practice, I've found a component-entity model and/or prototype model to be much more effective. You could take a look at the code in my old Java roguelike game Tyrant for inspiration:
Weapon definitions: mikera/tyrant/Weapon.java (Github is down right now so can't find the exact link, but should be easy enough to Google)
The idea is that you make your objects by setting properties / composing compoenents in a Map-like game object rather than using static inheritance.
When you want to create a random weapon in this model, you can just get a list of all the possible weapon prototypes, and clone one of them at random to make a new weapon.
the mean of abstract in "public abstract class M4" is that you cannot make a new object with this class.
So you can put all commons fields of your weapons in the weapon class and make m4 and m16 extends the weapon and you code would compile.