I have been trying to build a Dungeons & Dragons inspired text based adventure game in Java. I am relatively new to coding/programming.
I have built a separate method that I am building the dice rolling function inside of, and then calling it inside the main when I need the method.
The method that I have made proceeds as follows:
public static int roll(int sides, int amount1){
numSides = sides;
amount = amount1;
return ThreadLocalRandom
.current()
.nextInt(lowestRoll,numSides);
}
sides
indicates of sides I have for each of the dice so that way I can use multiple dice types in one method. I basically want to be able to return the ThreadLocalRandom
multiple times depending on a conditional. I know that you cannot return something multiple times in a method which is why I have came here because I need a loophole to figure this method out.
I think that what I'm looking for would look approximately like this but I'm not sure:
if (amount > 1){
return ThreadLocalRandom * amount
.current()
.nextInt(lowestRoll,numSides);
}
This is not the right syntax(obviously) but any help with this method would be appreciated.
Now, the program runs correctly, I would just have to call the method multiple times instead of using the sides parameter.
CodePudding user response:
In Java, you cannot return several values from one function, but you can return an Object which will hold several values. Here is a basic implementation of such function and a respective unit test for it:
public List<Integer> roll(int sides, int amount){
int lowestRoll = 1;
List<Integer> results = new ArrayList<>();
ThreadLocalRandom random = ThreadLocalRandom.current();
for (int ii = 0; ii < amount; ii ) {
results.add(random.nextInt(lowestRoll, sides));
}
return results;
}
@Test
void testRoll() {
assertThat(roll(6, 1).size()).isEqualTo(1);
assertThat(roll(6, 3).size()).isEqualTo(3);
}
Please, make sure that you have adjusted the actual roll method logic to your needs.
CodePudding user response:
Specific game dice can be basically anything but typically they are just a cube with six faces consisting of one to six dots or numbered 1 to 6. I don't know what DnD has for dice but this can apply to any type of dice or be easily modified to accommodate whatever.
The idea is a method that allows you provide the number of dice to roll and the number of Faces (sides) that will be on each die. Since the dice are specific to the game, the number of faces (sides) can be hard-coded into the method but in this case, the method could be used for any dice game since the number of faces is also provided to the method. The value of the returned die values could relate to a specific index (-1) of a specific Array to provide specific meaning:
public static int[] rollDice(int numberOfDice, int numberOfDieFaces){
int[] die = new int[numberOfDice];
for (int d = 0; d < die.length; d ) {
die[d] = java.util.concurrent.ThreadLocalRandom.current().nextInt(1, numberOfDieFaces 1);
}
return die;
}
To roll a single die with six faces:
int[] dice = rollDice(1, 6);
System.out.println(Arrays.toString(dice));
To roll two dice with eight faces:
int[] dice = rollDice(2, 8);
System.out.println(Arrays.toString(dice));
To roll five dice with six faces:
int[] dice = rollDice(5, 6);
System.out.println(Arrays.toString(dice));
ect, ect, ....
CodePudding user response:
tl;dr
Make a class to represent a die. Write a roll
method, and another method that rolls repeatedly to return a list like that discussed in other Answer.
new Die( 6 ).rollRepeatedly( 3 )
[5, 6, 1]
Details
The Answer by Igor Kanshyn is correct, and directly answers your Question. I will look at the bigger picture, to show an object-oriented way to address the multiple types of dice you want to support.
Make class Die
By the way, the singular of dice is die. Precise naming helps to make your programming more clear.
We define a class to represent a die. The constructor for this class takes an argument to define the number of its sides.
public Die ( final int sides )
{
this.sides = sides;
}
And the class needs a method roll
to randomly pick a face (a side).
The last-rolled face needs to be kept as state on the object. So we have a property currentFace
on our class, kept as read-only to outsiders.
public int roll ( )
{
this.currentFace = ThreadLocalRandom.current().nextInt( 1 , ( this.sides 1 ) ); // Add one because the `bound` parameter is *exclusive*.
return this.currentFace;
}
And we should add overrides for some of the methods inherited from the Object
superclass. These methods are equals
, hashCode
, and toString
.
And let's add a method to roll multiple times. This method returns an unmodifiable List
of the results.
Put all that code together.
package work.basil.example.game;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.IntStream;
public class Die
{
// -------| Final state |-----------------------
public final UUID id; // Identify each die existing in the game.
public final int sides;
// -------| Properties |-----------------------
private int currentFace;
// -------| Business logic |-----------------------
public int roll ( )
{
this.currentFace = ThreadLocalRandom.current().nextInt( 1 , ( this.sides 1 ) );
return this.currentFace;
}
public List < Integer > rollRepeatedly ( final int countRolls )
{
// Validate argument.
if ( countRolls < 1 ) { throw new IllegalArgumentException( "Count of rolls must be a positive number, bigger than zero. Message # 404cd68f-034a-47de-91dc-adbdbfb0801b." ); }
// Generate the specified amount of rolls.
List < Integer > results = IntStream.rangeClosed( 1 , countRolls ).map( ( int n ) -> this.roll() ).boxed().toList();
return results;
}
// -------| Constructors |-----------------------
public Die ( final int sides )
{
// Validate argument.
if ( sides < 2 ) { throw new IllegalArgumentException( "Count of sides must be a positive number, more than one. Message # b9586272-2f2c-4618-993d-2d2ccbb8f489." ); }
this.sides = sides;
this.id = UUID.randomUUID();
this.roll(); // Initialize.
}
// -------| Getters |-----------------------
public int getCurrentFace ( ) { return currentFace; }
// ---------| `Object` overrides |----------------------------
@Override
public boolean equals ( Object obj )
{
if ( obj == this ) { return true; }
if ( obj == null || obj.getClass() != this.getClass() ) { return false; }
var that = ( Die ) obj;
return Objects.equals( this.id , that.id );
}
@Override
public int hashCode ( ) { return Objects.hash( id ); }
@Override
public String toString ( )
{
return "Die{"
"id=" id
", sides=" sides
", currentFace=" currentFace
'}';
}
}
Let's exercise that class.
System.out.println( new Die( 6 ).rollRepeatedly( 3 ) );
[5, 6, 1]
If not comfortable with streams, you can replace the IntStream
line in the rollRepeatedly
method with a conventional for
loop.
List < Integer > results = new ArrayList <>();
for ( int nthRoll = 1 ; nthRoll <= countRolls ; nthRoll )
{
int roll = this.roll();
Integer integer = roll; // Wrapping a primitive `int` within an `Integer` object.
results.add( integer );
}
CodePudding user response:
Assuming amount
is the number of rolls of a sides
sided dice and you want to return the sum of those rolls:
public static int roll(int sides, int amount) {
int result = 0;
for (int i = 0; i < amount; i ) {
result = ThreadLocalRandom.current().nextInt(sides) 1;
}
return result;
}
If you prefer a one-liner:
public static int roll(int sides, int amount) {
return Stream.generate(ThreadLocalRandom::current)
.limit(amount)
.mapToInt(tlr -> tlr.nextInt(sides) 1)
.sum();
}
CodePudding user response:
Have a look at RxJava. It looks like you need to use an emitter pattern.