Generating attack for java game - java

I am creating an 'advanced' text adventure game on java to get into learning more about class useage and whatnot.
I am trying to work out the logic of attacking and this is what I have so far:
What I want to do is have another random smaller multiplier for different things, like intel is a stat the character will have, what would be the best way to add a multiplyer?
public int magicAttack()
{
int randomMultiplyer = randomGenerator.nextInt(10);
double extraMultiplyer = randomGenerator.nextDouble();
System.out.println((character.basedmg/*10*/ + character.strength) * randomMultiplyer);
return (character.basedmg/*10*/ + character.magic) * randomMultiplyer;
}
Here are the classes Im using
Character.java and AttackManager.java
So with the above code that I pasted here, I dont want to be overly technical with how it works, simply that it works reasonably well. I want to add another multiplyer (which I have started as you can see from the double 'extraMultiplyer' and I wanted it to maybe just add 0.6, so multiplying it by 1.6 but I am not sure how to get that with random.

If you are using Java utils.Random, nextDouble() returns a value between 0.0 and 1.0.
Multiplying by the difference of your desire max and min value (range) and adding your min value, you will get you a value between min and max.
Random r = new Random();
double multiplier = (max - min) * r.nextDouble() + min;
If you want 0 to 0.6,
double multiplier = 0.6 * r.nextDouble();

Related

Calculating sin function with JAVA BigDecimal -monomial is going bigger(?)

I'm making sin function with BigDecimal in JAVA, and this is as far as I go:
package taylorSeries;
import java.math.BigDecimal;
public class Sin {
private static final int cutOff = 20;
public static void main(String[] args) {
System.out.println(getSin(new BigDecimal(3.14159265358979323846264), 100));
}
public static BigDecimal getSin(BigDecimal x, int scale) {
BigDecimal sign = new BigDecimal("-1");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal i = BigDecimal.ONE;
BigDecimal num = null;
BigDecimal result = x;
//System.err.println(x);
do {
x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
num = x.divide(divisor, scale + cutOff, BigDecimal.ROUND_HALF_UP);
result = result.add(num);
//System.out.println("d : " + divisor);
//System.out.println(divisor.compareTo(x.abs()));
System.out.println(num.setScale(9, BigDecimal.ROUND_HALF_UP));
} while(num.abs().compareTo(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
System.err.println(num);
System.err.println(new BigDecimal("0.1").pow(scale + cutOff));
return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
}
It uses Taylor series :
picture of the fomular
The monomial x is added every iteration and always negative number.
And the problem is, absolute value of x is getting bigger and bigger, so iteration never ends.
Is there and way to find them or better way to implement it from the first place?
EDIT:
I made this code from scratch with simple interest about trigonometric functions, and now I see lots of childish mistakes.
My intention first was like this:
num is x^(2k+1) / (2k+1)!
divisor is (2k+1)!
i is 2k+1
dividend is x^(2k+1)
So I update divisor and dividend with i and compute num by sign * dividend / divisor and add it to result by result = result.add(num)
so new and good-working code is:
package taylorSeries;
import java.math.BigDecimal;
import java.math.MathContext;
public class Sin {
private static final int cutOff = 20;
private static final BigDecimal PI = Pi.getPi(100);
public static void main(String[] args) {
System.out.println(getSin(Pi.getPi(100).multiply(new BigDecimal("1.5")), 100)); // Should be -1
}
public static BigDecimal getSin(final BigDecimal x, int scale) {
if (x.compareTo(PI.multiply(new BigDecimal(2))) > 0) return getSin(x.remainder(PI.multiply(new BigDecimal(2)), new MathContext(x.precision())), scale);
if (x.compareTo(PI) > 0) return getSin(x.subtract(PI), scale).multiply(new BigDecimal("-1"));
if (x.compareTo(PI.divide(new BigDecimal(2))) > 0) return getSin(PI.subtract(x), scale);
BigDecimal sign = new BigDecimal("-1");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal i = BigDecimal.ONE;
BigDecimal num = null;
BigDecimal dividend = x;
BigDecimal result = dividend;
do {
dividend = dividend.multiply(x).multiply(x).multiply(sign);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
num = dividend.divide(divisor, scale + cutOff, BigDecimal.ROUND_HALF_UP);
result = result.add(num);
} while(num.abs().compareTo(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
}
The new BigDecimal(double) constructor is not something you generally want to be using; the whole reason BigDecimal exists in the first place is that double is wonky: There are almost 2^64 unique values that a double can represent, but that's it - (almost) 2^64 distinct values, smeared out logarithmically, with about a quarter of all available numbers between 0 and 1, a quarter from 1 to infinity, and the other half the same but as negative numbers. 3.14159265358979323846264 is not one of the blessed numbers. Use the string constructor instead - just toss " symbols around it.
every loop, sign should switch, well, sign. You're not doing that.
In the first loop, you overwrite x with x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);, so now the 'x' value is actually -x^3, and the original x value is gone. Next loop, you repeat this process, and thus you definitely are nowhere near the desired effect. The solution - don't overwrite x. You need x, throughout the calculation. Make it final (getSin(final BigDecimal x) to help yourself.
Make another BigDecimal value and call it accumulator or what not. It starts out as a copy of x.
Every loop, you multiply x to it twice then toggle the sign. That way, the first time in the loop the accumulator is -x^3. The second time, it is x^5. The third time it is -x^7, and so on.
There is more wrong, but at some point I'm just feeding you your homework on a golden spoon.
I strongly suggest you learn to debug. Debugging is simple! All you really do, is follow along with the computer. You calculate by hand and double check that what you get (be it the result of an expression, or whether a while loop loops or not), matches what the computer gets. Check by using a debugger, or if you don't know how to do that, learn, and if you don't want to, add a ton of System.out.println statements as debugging aids. There where your expectations mismatch what the computer is doing? You found a bug. Probably one of many.
Then consider splicing parts of your code up so you can more easily check the computer's work.
For example, here, num is supposed to reflect:
before first loop: x
first loop: x - x^3/3!
second loop: x - x^3/3! + x^5/5!
etcetera. But for debugging it'd be so much simpler if you have those parts separated out. You optimally want:
first loop: 3 separated concepts: -1, x^3, and 3!.
second loop: +1, x^5, and 5!.
That debugs so much simpler.
It also leads to cleaner code, generally, so I suggest you make these separate concepts as variables, describe them, write a loop and test that they are doing what you want (e.g. you use sysouts or a debugger to actually observe the power accumulator value hopping from x to x^3 to x^5 - this is easily checked), and finally put it all together.
This is a much better way to write code than to just 'write it all, run it, realize it doesn't work, shrug, raise an eyebrow, head over to stack overflow, and pray someone's crystal ball is having a good day and they see my question'.
The fact that the terms are all negative is not the problem (though you must make it alternate to get the correct series).
The term magnitude is x^(2k+1) / (2k+1)!. The numerator is indeed growing, but so is the denominator, and past k = x, the denominator starts to "win" and the series always converges.
Anyway, you should limit yourself to small xs, otherwise the computation will be extremely lengthy, with very large products.
For the computation of the sine, always begin by reducing the argument to the range [0,π]. Even better, if you jointly develop a cosine function, you can reduce to [0,π/2].

Find the modo value

I have given a log value Y , i want to calculate the anti log of Y i.e
ans = (Math.pow(10,Y))%mod
where mod = 1e9+7 and the anti log of Y will always be integer i.e Y is calculate as follow Y= log(a) a is very large integer of range 10^100000
So for given Y i need to calculate ans ? How to do that considering the mod operation.
My Approach
double D = Y -(int)Y
long Pow = (long)Y
for(int i=1;i<=Pow;i++) ans = (ans*10)%mod;
ans = (ans*Math.pow(10,D))%mod
But it's not correct can someone suggest be efficient approach here ? BigDecimal can be useful there ?
For Example:
Y = 16.222122660468525
Using the straight forward method and rounding off i.e Math.log(10,Y) give me 1667718169966651 but using loops it's give me 16677181699666510. I am not using mod now just explaining that there is an error.
Here Y is small so direct method works and we can take mod easily. if Y is range of 10000 it will not work and overflow so we have to used mod.
I guess it's should work
double D = Y -(int)Y
long Pow = (long)Y
for(int i=1;i<=Pow;i++) ans = (ans*10)%mod;
ans = (ans*Math.pow(10,D))
ans = Math.round(ans)
ans%=mod
There is an error in your judgement here - the loop method is not at fault.
The value of a in your example has 17 integer digits. From this stackoverflow post, a double has ~16 significant digits of precision. Thus both the loop and direct calculations are in fact being limited by lack of precision.
(Just to confirm, using a high precision calculator, the value of a is 16677181699666650.8689546562984070600381634077.... Thus both of your values are incorrect - unless you copied them wrongly?)
Thus your loop method is not the problem; you just need a
higher-precision method to do the last step (calculating pow(10, frac(Y))).
As a side note, there is a more efficient way of doing the loop part - this post has more details.

For loop won't add terms for some reason

So, I was putting my knowledge of for loops to the test by attempting to create the mathematical constant π using a series with user-defined accuracy:
public double pi(int accuracy) {
for (int i = 1; i <= accuracy; i++) {
rawPi += 1 / (i * i);
}
return Math.sqrt(rawPi * 6);
}
Now, you would think that this would get closer and closer to π as int accuracy shoots up, but it doesn't. It just stays at the square root of 6, meaning that private double rawPi gets to 1 and never goes any higher, meaning no terms are being added in my series (represented as a for loop) and I have absolutely no idea what the problem could be. Any ideas?
Try to change this:
rawPi += 1 / (i * i);
to
rawPi += 1.0 / (i * i);
or as commented by "Patricia Shanahan" , use this for better accuracy and to avoid integer overflow on i*i:
1/((double)i*i)

How do I generate random numbers within a range

computerTotal = (int) Math.ceil(Math.random() * 21);
Can someone show me how to get 16 - 21 random number I keep getting errors when i try to implement the Math.floor function... As you can see i'm not very good at putting functions within functions.
Many Thanks!
If Java, use the Random Class.
Random r = new Random();
int myRand = 16+ r.nextInt(6); //16+[0-6) = 16-21
For creating random numbers between (including) min and max, you can do this:
Math.floor(Math.random() * (max - min + 1)) + min
Edit: The JAVA tag was added only after I suggested this; before it had no tags hinting at a specific language at all – so that there might be better/already implemented methods for this in language X is well possible. This is a very generic approach.

Skewing java random number generation toward a certain number

How, in Java, would you generate a random number but make that random number skewed toward a specific number. For example, I want to generate a number between 1 and 100 inclusive, but I want that number skewed toward say, 75. But I still want the possibility of getting other numbers in the range, but I want more of a change of getting numbers close to say 75 as opposed to just getting random numbers all across the range. Thanks
Question is a bit old, but if anyone wants to do this without the special case handling, you can use a function like this:
final static public Random RANDOM = new Random(System.currentTimeMillis());
static public double nextSkewedBoundedDouble(double min, double max, double skew, double bias) {
double range = max - min;
double mid = min + range / 2.0;
double unitGaussian = RANDOM.nextGaussian();
double biasFactor = Math.exp(bias);
double retval = mid+(range*(biasFactor/(biasFactor+Math.exp(-unitGaussian/skew))-0.5));
return retval;
}
The parameters do the following:
min - the minimum skewed value possible
max - the maximum skewed value possible
skew - the degree to which the values cluster around the mode of the distribution; higher values mean tighter clustering
bias - the tendency of the mode to approach the min, max or midpoint value; positive values bias toward max, negative values toward min
Try http://download.oracle.com/javase/6/docs/api/java/util/Random.html#nextGaussian()
Math.max(1, Math.min(100, (int) 75 + Random.nextGaussian() * stddev)))
Pick a stddev like 10 and play around until you get the distribution you want. There are going to be slightly more at 1 and 100 though than at 2 or 99. If you want to change the rate at which it drops off, you can raise the gaussian to a power.

Categories

Resources