Java, two objects, one cannot be resolved in methods, other can - java

Having an issue with two objects I've declared. One is working fine, the p1, while the other, p2, cannot be resolved as a symbol of my methods.
The two objects are located in main, while the methods are located in a Player class. I've tried moving variables and the objects around, but to no avail, as it causes other issues with scope.
Is this an issue with a scope? But then why is one object seen in the methods and one isn't? New to the whole object-oriented stuff as well, and it's throwing me for a loop.
The error is "cannot resolve symbol 'p2' "
The below code is the main method so far, then one of the methods that have the p2 error.
Thank you in advance for any assistance.
public static void main(String[] args) {
Player p1 = new Player(name1); // instantiation of player 1 object; given first player's name
Player p2 = new Player(name2); // instantiation of player 2 object; given second player's name
}
public void attack1(Player p1) { // first method in which player 2 attacks player 1
Random rnd = new Random(); // instantiation of new random object
int dmg = rnd.nextInt(26) - 1; // setting of variable dmg to = a random number between 0 and 25
if (dmg >= 0 && dmg <= 15) { // if statement checking if dmg is between 0 and 15
p1.health = p1.health - dmg; // if dmg is between 0 and 15, reduce value from player 1 health
System.out.printf("%s attacked %s and %s's health is now %d.", p2.name, p1.name, p1.name, p1.health); // print to screen results of attack1
} else if (dmg > 15) { // if dmg value is greater than 15, player 2 misses player 1
System.out.printf("%s attacked %s and missed.", p2.name, p1.name); // print to screen results of missed attack1
}

The problem is that p2 is not defined in the scope of the function attack1. Either pass both p1 and p2 to attack1 or make p1 and p2 instance variables of your class.
public void attack1(Player p1, Player p2) { // first method in which player 2 attacks player 1
Random rnd = new Random(); // instantiation of new random object
int dmg = rnd.nextInt(26) - 1; // setting of variable dmg to = a random number between 0 and 25
if (dmg >= 0 && dmg <= 15) { // if statement checking if dmg is between 0 and 15
p1.health = p1.health - dmg; // if dmg is between 0 and 15, reduce value from player 1 health
System.out.printf("%s attacked %s and %s's health is now %d.", p2.name, p1.name, p1.name, p1.health); // print to screen results of attack1
} else if (dmg > 15) { // if dmg value is greater than 15, player 2 misses player 1
System.out.printf("%s attacked %s and missed.", p2.name, p1.name); // print to screen results of missed attack1
}
As a side note, I would suggest that you remove attack1 and (presumably) attack2 and instead write a method public void attack(Player source, Player target) to reduce the amount of duplicated code.
public void attack(Player source, Player target) {
Random random = new Random();
int damage = random.nextInt(26) - 1;
if(damage >= 0 && damage <= 15) {
target.health -= damage;
System.out.printf("%s attacked %s and %s's health is now %d.", source.name, target.name, target.name, target.health);
} else if(damage > 15) {
System.out.printf("%s attacked %s and missed.", source.name, target.name);
}
}

Related

How to randomize two players to "X" and to "O?

I'm making a tic tac toe game and I have randomily assign player 1 one to either "X" or "O" and same with player 2. I have no clue how to start the code
It should make player one either X or O and make player 2 whatever is left over from player 1
You can generate a random number between for example 0 and 1 by using a random object or the Math.Random() function.
Based on the random number you can select via if and else, which letter "X"/"O" the first player will get.
The second player can then be assigned what is left.
Have look on Math.Random:
Math.random() explanation
public class RandomTicTacToeSymbols {
public static void main(String args[]) {
String[] symbols = {"X" , "O"};
int randomIndex = (int) Math.round( Math.random());
String playerOneSymbol = symbols[randomIndex];
String playerTwoSymbol = symbols[(randomIndex+1) % 2];
System.out.println(String.format("Player 1 -> %s - Player 2 -> %s", playerOneSymbol, playerTwoSymbol) );
}
}

Simple Java Program Isn't Getting Intended Output

import java.util.Random;
public class Player {
int att;
int str;
int def;
int hp;
int attackRoll;
int defenceRoll;
int maxHit;
//A player has variable attack, strength, defence, and hp stats
//attack = determines accuracy, strength = determines damage, defence = determines ability to block hits
public Player(int attack, int strength, int defence, int hitpoints)
{
attack = att;
strength = str;
defence = def;
hitpoints = hp;
/*
attackRoll and defenceRoll are used by the 2 players to determine probability
of successfully scoring a hit, in m sample testing attRoll will always be
higher than defRoll; they are integer numbers used in below method
*/
attackRoll = (this.att + 3)*(90+64);
defenceRoll = (this.def + 3)*(0+64);
maxHit = (int) ((0.5) + ((this.str + 0 + 8.0)*(86.0+64.0))/(640.0));
//maxHit determines the maximum number player can deal each attack
}
//this determines if p1 successfully lands a hit on p2, true if so, false if not
//accuracy is calculated as a probability, ie .7 probability of hitting
//in which case there is .7 probability of being true and .3 of being false
public static boolean hit(Player p1, Player p2)
{
double accuracy;
if (p1.attackRoll > p2.defenceRoll)
{
accuracy = 1.0 - ((double)(p2.defenceRoll+2.0)/(2*(p1.attackRoll+1.0)));
}
else
{
accuracy = (double) (p1.attackRoll/(2*(p2.defenceRoll+1.0)));
}
Random r = new Random();
System.out.println("Accuracy: " + accuracy);
return r.nextDouble() <= accuracy;
//idea is that if accuracy is .7 for example, nextDouble() generates
//between 0-1.0 so the probability that nextDouble() is <= .7 is .7, what we want
}
//calculates damage p1 does to p2, if hit returns true
public static void attack(Player attacker, Player defender)
{
int damage = 0;
if(!hit(attacker, defender)) return; //if the attacker missed, damage is 0, defender doesn't lose hp
//if p1 successfully landed a hit on p2 as determined in previous method
else if(hit(attacker, defender))
{
Random r = new Random();
damage = r.nextInt(attacker.maxHit+1); //p1 deals (0 to maxHit) damage on p2 from that attack
defender.hp -= damage; //p2 loses that much hp
}
}
public static void main(String[] args) {
int p1wins = 0; //counts number of times p1 won
int p2wins = 0; //counts number of times p2 won
int firstCounter = 0; //counts the number of times p1 went first, should be near 50% as its randomly decided
int secondCounter = 0; //couonts the number of times p2 went first, should be near 50%
for (int i = 1; i <= 10000; i++) //10000 trials of p1 and p2 battling
{
Player p1 = new Player(99, 99, 99, 99); //set p1's attack, strength, defence, hp to 99
Player p2 = new Player(99, 99, 99, 40); //p2 only has 40 hp, therefore p2 should lose most of the time
Random r = new Random();
int first = r.nextInt(2); //determines which player attacks first
if(first == 0) firstCounter++;
if(first == 1) secondCounter++;
while((p1.hp>0) && (p2.hp>0)) //the fight goes on until one player dies (hp is <= 0)
{
if(first == 0) //if player 1 attacks first
{
attack(p1, p2); //player 1 attacks player 2
if(p2.hp <= 0) break; //if player 2's hp goes 0 or below from that attack, he dies and there's no more fighting
attack(p2, p1); //then p2 attacks p1, and repeat
if(p1.hp <= 0) break;
}
else if (first == 1) //if player 2 attacks first
{
attack(p2, p1); //player 2 attacks player 1
if(p1.hp <= 0) break;
attack(p1, p2);
if(p2.hp <= 0) break;
}
}
if(p1.hp <= 0) p2wins++;
else if(p2.hp <= 0) p1wins++;
}
System.out.println("p1 won " + p1wins + " times."); //prints number of times p1 wins
System.out.println("p2 won " + p2wins + " times.");
System.out.println(firstCounter); //prints number of times p1 went first, should be near 50% with large sample size
System.out.println(secondCounter);
}
}
The above code is a program that simulates 2 players fighting.
The main idea is to understand that a player has 4 stats (attack, strength, defense, hp) and that if two players fight with the same stats (ie 99,99,99,99 both), then the probability that anyone will win is naturally about 50%.
The problem I'm encountering is that the program makes p2 win every single game, even with stats that are obviously vastly inferior
(ie p1 having 99 att, 99 str, 99 def, 99 hp p2 having 99 att, 99 str, 99 def, but 20 hp), thus p2 would die much sooner in most trials, but a run of 10000 fights displays p2 winning all 10000 of them, which is obviously wrong and not intended. I can't figure out why p2 is winning 100% of the time.
You have an error at the beginning of the Player constructor.
Assignments' order are wrong. The correct way is:
att = attack;
str = strength;
def = defence;
hp = hitpoints;
Otherwise, p1.hp and p2.hp are always 0.

Locking user input and counting amount of time loop happens

I'm new to this so sorry if I am a bit confusing
So this is my code, its a game based around 2 players adding 1 or 2 to the variable "counter" the one who puts the final 1 or 2 adding all the numbers up to 21 wins.
So what I would like to have help with is that I want to lock the user input to only be able to select 1 or 2, not anything else because that would break the rules of the game. Also I would like to have a way to determine who won, player 1 or player 2. Like counting the amount of times the loop happens, so I can distinguish if player 1 or 2 one.
Any help would be appreciated! Thanks!
package hemtenta;
import java.util.Scanner;
public class Hemtenta {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int counter = 0;
int addcounter = 0;
int sum;
System.out.println("Welcome to 21");
System.out.println("The game revolves about you or your opponent getting to 21 ");
System.out.println("You both start on the same number 0, ");
System.out.println("adding 1 or 2 to see which one of you will put the final number adding it all up to 21 and winning.");
System.out.println("Think smart!");
while(counter <= 20) {
System.out.println("Please choose to add 1 or 2");
addcounter = input.nextInt();
counter += addcounter;
System.out.println("We are now on a total of " + (counter));
}
if (counter==21) {
System.out.println("Congratulations x! you won");
}
else {
System.out.println("Something went wrong! Try again");
}
}
}
You could look towards adding a
while (addcounter != 1 && addcounter != 2) {
// Prompt for values
}
To check that the value input by the user is either a 1 or a 2. If it isn't, then don't accept it and continue prompting till a valid input is registered.
And a
int turnCounter = 0;
...
// Within the loop
turnCounter += 1;
...
// At the end
if (turnCounter % 2 == 0) {
//Player Y wins
} else {
//Player X wins
}
To identify the turns, since turn 1s will be by player X, and turn 2s will be player Y. All turns by player Y will be in multiples of 2.

RandomWalk solution issue

PROBLEM
I am working on a code where I am simulating a dog walking in a city - trying to escape the city. The dog makes random choices of which way to go to at each intersection with equal probability.If stuck at a dead end the dog will come directly back to the middle of a big city and start all over again. The dog will do this again and again until it gets out of the city or until it gets tired after T number of trials. But by the time the the dog starts again from the middle(N/2,N/2) on each try, it will have forgotten all the intersections it had visited in the previous attempt.
IDEA
The idea is to mimic a code given in our textbook and come up with the solution. We were given input N, T - where N is the number of north-south and east-west streets in the city and T is the number of times the dog will try to get out of the city before it gives up. We have to draw it out, using StdDraw. We have been given how to make random movements - generate a number between 0 and 4 - up: 0 right: 1 down: 2 left: 3
My Approach
import java.util.Random;
public class RandomWalk {
private static final Random RNG = new Random (Long.getLong ("seed",
System.nanoTime()));
public static void main(String[] args) {
int N = Integer.parseInt(args[0]); // lattice size
int T = Integer.parseInt(args[1]); // number of trials
int deadEnds = 0; // trials resulting in a dead end
StdDraw.setCanvasSize();
StdDraw.setXscale(0,N);
StdDraw.setYscale(0,N);
// simulate T self-avoiding walks
for (int t = 0; t < T; t++) {
StdDraw.clear();
StdDraw.setPenRadius(0.002);
StdDraw.setPenColor(StdDraw.LIGHT_GRAY);
for(int i=0;i<N;i++){
StdDraw.line(i, 0, i, N);
StdDraw.line(0, i, N, i);
}
StdDraw.setPenColor(StdDraw.RED);
StdDraw.setPenRadius(0.01);
boolean[][] a = new boolean[N][N]; // intersections visited
int x = N/2, y = N/2; // current position
// repeatedly take a random step, unless you've already escaped
while (x > 0 && x < N-1 && y > 0 && y < N-1) {
int t_x = x;
int t_y=y;
// dead-end, so break out of loop
if (a[x-1][y] && a[x+1][y] && a[x][y-1] && a[x][y+1]) {
deadEnds++;
break;
}
// mark (x, y) as visited
a[x][y] = true;
// take a random step to unvisited neighbor
int r = RNG.nextInt(4);
if (r ==3) {
//move left
if (!a[x-1][y])
t_x--;
}
else if (r == 1 ) {
//move right
if (!a[x+1][y])
t_x++;
}
else if (r == 2) {
//move down
if (!a[x][y-1])
t_y--;
}
else if (r == 0) {
//move up
if (!a[x][y+1])
t_y++;
}
StdDraw.line(t_x, t_y, x, y);
x = t_x;
y = t_y;
}
System.out.println("T: "+t);
}
System.out.println(100*deadEnds/T + "% dead ends");
}
}
ISSUE
Given N - 15, T - 10, -Dseed=5463786 we should get an output like - http://postimg.org/image/s5iekbkpf/
I am getting - see http://postimg.org/image/nxipit0pp/
I don't know where I am going wrong. I know this is very specific in nature, but I am really confused so as to what I am doing wrong. I tried all 24 permutations of 0,1,2,3 but none of them gave the output desired. So, I conclude that the issue in in my code.
check your StdDraw.java with:
http://introcs.cs.princeton.edu/java/stdlib/StdDraw.java.html
your code should be fine, I got the expected result

How to write a probability algorithm that can be maintained easily?

Supposed I want to create a game. At the start of the game, the player will pick a monster.
It's easy to picks the monster fairly.
// get all monsters with equal chance
public Monster getMonsterFair(){
Monster[] monsters = {new GoldMonster(), new SilverMonster(), new BronzeMonster()};
int winIndex = random.nextInt(monsters.length);
return monsters[winIndex];
}
And picks the monster unfairly.
// get monsters with unequal chance
public Monster getMonsterUnFair(){
double r = Math.random();
// about 10% to win the gold one
if (r < 0.1){
return new GoldMonster();
}
// about 30% to winthe silver one
else if ( r < 0.1 + 0.2){
return new SilverMonster();
}
// about 70% to win the bronze one
else {
return new BronzeMonster();
}
}
The problem is that, when I add a new monster to the game, I have to edit the if-else.
Or I change the chance of winning GoldMonster to 0.2, I have to change all 0.1 into 0.2
.It's ugly, and not easily maintained.
// get monsters with unequal change & special monster
public Monster getMonsterSpecial(){
double r = Math.random();
// about 10% to win the gold one
if (r < 0.1){
return new GoldMonster();
}
// about 30% to win the silver one
else if ( r < 0.1 + 0.2){
return new SilverMonster();
}
// about 50% to win the special one
else if ( r < 0.1 + 0.2 + 0.2){
return new SpecialMonster();
}
// about 50% to win the bronze one
else {
return new BronzeMonster();
}
}
How can this probability algorithm can be refactored so that the codes can be maintained easily when new monster is added and the chances of winning monsters are adjusted?
Basically what #Egor Skriptunoff said. This should scale easily. You could use a collection of Class<Monster> if you didn't want to use an enum.
enum Monster {
GOLD(1),
SILVER(3),
BRONZE(6) // pseudo probabilities
private int weight;
// constructor etc..
}
public Monster getMonsterSpecial() {
List<Monster> monsters = new ArrayList<>();
for(Monster monsterType : Monster.values()) {
monsters.addAll(Collections.nCopies(monsterType.getWeight(), monsterType));
}
int winIndex = random.nextInt(monsters.length);
return monsters.get(winIndex);
}
You could perhaps make the enum Monsters plural, and have it point to a Class<? extends Monster> if you still want to instantiate monster classes. I just tried to make the example clearer.
I would uses a total weight which increases with each monster added.
private final Random rand = new Random();
public Monster getMonsterSpecial() {
int weight = rand.nextInt(1+2+2+5);
if ((weight -= 1) < 0) return new GoldMonster();
if ((weight -= 2) < 0) return new SilverMonster();
if ((weight -= 2) < 0) return new SpecialMonster();
// 50% chance of bronze
return new BronzeMonster();
}
This is based off of Peter's answer, just more maintainable. All you have to do is add a new monster to the array and add the weight to the total weight - this can easily be extended to happen during runtime if you wish (thus, never mind making code changes, you don't even need to restart the program to add a monster (assuming the rest of your program allows this)).
Monster class:
Have an int weight variable for each monster.
If the weights are 1,2 and 7, the respective probabilities will be 10%, 20% and 70% (calculated as 100*x/(1+2+7)).
Globals:
Random rand = new Random();
int totalMonsterWeight;
Monster[] monsters; // set this up somewhere
Global weight initialization:
totalMonsterWeight = 0;
for (Monster monster: monsters)
totalMonsterWeight += monster.getWeight();
Get-monster function:
public Monster getMonster()
{
int weight = rand.nextInt(totalMonsterWeight);
for (Monster monster: monsters)
if ((weight -= monster.getWeight()) < 0)
return monster.getClass().newInstance();
}
The above is a lazy way (probably not the best way) to return a new instance during each call. The right way is probably using a Factory pattern.

Categories