I am writing a noughts and crosses code that can take console arguments to decide which strategy to use (different AI classes). If the user selects 'ultimatecomputerplayer' then this is implemented as p1/p2 depending in which order they input this and the other strategy (could be 'humanplayer' etc.)
My problem is that the ultimate class needs to know which symbol it is, at the moment the game running class just assigns p1 to X and p2 to O but my ultimate class is written assuming it is X so this poses an issue.
This is the code that assigns the strategies and symbols:
NCGridV3 theGrid = new NCGridV3(gridSize, gridSize);
GameRunnerV3 theGame = new GameRunnerV3();
Scanner sc = new Scanner(System.in);
ArrayList <NCPlayer> ret = new ArrayList <NCPlayer>();
for (int i = 1; i < args.length; i++)
{
switch (args[i])
{
case "RandomComputerPlayer":
ret.add(new RandomComputerPlayer());
break;
case "SimpleComputerPlayer":
ret.add(new SimpleComputerPlayer());
break;
case "UltimateComputerPlayer":
ret.add(new UltimateComputerPlayer());
break;
case "HumanPlayer":
ret.add(new HumanPlayer(sc, theGame));
break;
}
}
NCPlayer p1 = ret.get(0);
NCPlayer p2 = ret.get(1);
p1.setMySymbol(SquareStatus.CROSS);
p2.setMySymbol(SquareStatus.NOUGHT);
I tried to assign the strategy's symbol like so:
public class UltimateComputerPlayer extends GenericPlayer implements NCPlayer
{
public UltimateComputerPlayer()
{
super();
}
#Override
public GridCoordinate getNextMove(NCGridV3 currentGrid)
{
SquareStatus symbol = GenericPlayer.getMySymbol();
But eclipse tells me I cant make a static reference to a non-static method.
Another option I tried was passing an integer into the UltimateComputer Class which would be 'i' from the loop in the game runner class, then having the symbol assign dependent on which place the class was called like so:
public UltimateComputerPlayer()
{
super();
SquareStatus mysymbol;
if (NC == 1)
mysymbol = NCGridV3.SquareStatus.CROSS;
if (NC == 2)
mysymbol = NCGridV3.SquareStatus.NOUGHT;
}
#Override
public GridCoordinate getNextMove(NCGridV3 currentGrid)
{
.......
But this variable is not assigned in the GridCoordinate class and I dont know how to make it.
Any help is greatly appreciated, Thanks.
The second option can't work because NC is not defined (at least I can't tell where it would be) and also you assign the symbol to a local variable SquareStatus mysymbol in your constructor, which is gone as soon as you leave the constructor. You firstly have to make mysymbol an instance variable (by moving it above the constructor). Then you have the choice to either use the setter after construction or add the number to the constructor
class UltimateComputerPlayer {
private SquareStatus mysymbol;
public UltimateComputerPlayer(int nc) {
super();
if (nc == 1)
mysymbol = NCGridV3.SquareStatus.CROSS;
if (nc == 2)
mysymbol = NCGridV3.SquareStatus.NOUGHT;
}
// [...]
}
However that seems to be a generic concept and should be moved up into the parent class. Also, I would avoid using magic numbers inside the class. Make the decision of what symbol to use outside the class and call the constructor with the symbol as parameter, rather than the number.
And as #VictorSorokin says, in your first solution, just call getMySymbol() instead of GenericPlayer.getMySymbol()
Related
I've run into a problem where I attempt to define a constructor in the first part of a switch/case statement, and then I can't run the code because the program can't get the definition later.
The idea behind passing the constructor information from a switch/case function is that the user chooses what to do, but for some options, one must be done before the other is possible (e.g. Create password and Check password).
If I try doing it this way, it throws a VarMayNotHaveBeenInitialized error (I get the sense the answer is in a try/catch statement, but I don't know enough about them to be sure). I've included some code that is what I've been essentially trying to do below. (The two classes are to best simulate the project I'm working on.)
Any help is appreciated! : )
TestMain.java:
package exitTest;
public class TestMain {
InitializeTest init;
public static void main(String[] args) {
while (true) {
String x = InitializeTest.askQuestion();
switch (x) {
case "set":
InitializeTest init = new InitializeTest();
break;
case "get":
if (init != null) {
init.showExample();
} else {
System.out.println("Error: init not initialized.");
} break;
}
}
}
}
InitializeTest.java:
package exitTest;
import java.util.Scanner;
public class InitializeTest {
static Scanner in = new Scanner(System.in);
public InitializeTest thing1;
public String example;
public static String askQuestion() {
System.out.println("set for set example\nget for check example");
String action = in.nextLine();
return action;
}
public InitializeTest() {
System.out.println("Input string:");
String example = in.nextLine();
}
void showExample() { System.out.println(example); }
}
You include the type when you're declaring variables, not when simply assigning to an existing one. When you write
InitializeTest init = new InitializeTest();
That makes a new init variable, unrelated to the previous one, which stores the newly constructed object. That new variable shadows the existing one, but it gets released after the switch block is over (variables in Java are block-scoped).
To put it to an analogy, it's as though you wanted to tell your friend Alice a secret. But when you went to her house, her neighbor whose name is also Alice happened to be there instead. If you tell that Alice your secret, then your friend doesn't find out. Even though the two happen to share a name, they don't share any memory.
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
So im making a program and a different class refers to an int in a different class:
if (Doihavetools==0 && Stone.StoneCounter>=10 && Wood.WoodCounter>=50){
but in the other class, the int is initialized before the value is "++"ed
int WoodCounter;
#Override
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
if (action.equals("Chop some wood")) {//ADD A .25 SECOND DELAY INBETWEEN CLICKS
Random Rand = new Random();
int W = Rand.nextInt(3) + 1;
if(W==2){
WoodCounter++;
}
Wood.setText("Click To Collect Wood : Wood:" + WoodCounter);
System.out.println(WoodCounter);
}
}
Is there a way so i can successfully initialize it and add to it at the same time? (i want to be able to continuously add to it)
Thanks in Advance,
Jack
I think what you want is for the variable to hold it's value. Try making another variable, a boolean, and before you initialize it, make a check to see if you have already done so. Also, declare this boolean in the class where
if (Doihavetools==0 && Stone.StoneCounter>=10 && Wood.WoodCounter>=50){
is present, at the top. (make it public)
so... then you can
if(initialized == false)
{
int WoodCounter;
initialized = true;
}
Either that, or just use Wood.WoodCounter instead of declaring a new variable.
You shouldn't declare a woodCounter variable unless you want to use it for something. Write wood.woodCounter to access the variable you seem to intend.
I am just a little bit confused as of what to do. I have Two Weapons Classes. One for the M16 and another for the M4. I then have those Classes implementing an interface named Armory. But I am having issues with the Combat class. In the combat class I have a Random number Generator that will generate a random number and depending on what number it is, will either give the player a weapon or do nothing. I will post the Code Below:
Interface:
public interface Armory {
public Integer weaponAmmo(int wepAmmo);
public Integer weaponDamage(int wepDamage);
public String weaponName(String wepName);
}
M4 Class(M4 and M16 Classes are the same except for damage and ammo amounts):
public class M4 implements Armory {
public Integer weaponAmmo(int wepAmmo) {
wepAmmo = 10;
return wepAmmo;
}
public Integer weaponDamage(int wepDamage) {
wepDamage = 2;
return wepDamage;
}
public String weaponName(String wepName) {
wepName = "M4";
return wepName;
}
And Finally, the Combat Class(This is where I am having Issues):
public class Combat {
final int chanceOfDrop = 3;
Weapons[] wepArray = {new M4(), new M16()}; //Issues here.. Don't really know how to implement this.
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(wepArray[Combat.ranNumberGen(wepArray.length)] } //Issues here also.
private static void givePlayerWeapon(int w) {
hasWeapon[w] = true;
for (int i = 0; i < hasWeapon.length; ++i)
{
if (hasWeapon[i]) System.out.println(( wepArray[i]).weaponName()); //And, last but not least, I am having Issues here
}
}
}
NOTE: I have a Weapons Class, But nothing is in it. I don't really know what to put in it.
Any Suggestions?
Thanks in advance:
Shandan
Several issues -
A. To put m16 and m14 elements in the weapons array , these classes must either extend (if Weapons is a class) or implmeent (if weapons is interface) Weapons.
Another option is to have a method of
Weapons toWeapons() in both M16 and M14 classes.
B. Correct me if I'm wrong (Not native english speaker - but Armory is a place that provides Weapons, so your choice of name is not good.
M16 and M14 should implement an interface named "Weapon" and this (In my humble opinion) should be the type of the array.
C. If I understood, you want to provide in some cases no weapon to the user -
One way to have this done, and not get into ugly if (to check existence or not) is to have a NoWeapon class implements Weapon (in your current code - implements Armory).
Its methods will have an applicative meaning of "do nothing".
For example -
weaponAmmo will always return 0.
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.