How to shuffle a deck of cards memorised in an array? - java

I was developing a simple application that It is simple game of cards, and I had created an array which contains all the card of the game but the problem is that I don't know why I can't shuffle this array?
I tried to use the RANDOM but I didn't succeed.
public class Mazzo {
private Carta[] carteNelMazzo ;
public Mazzo(){// create the deck
carteNelMazzo = creaMazzo();
mescolaMazzo(carteNelMazzo);
}
/**methods of the deck */
public Carta PescaCarta (){
return (carteNelMazzo==null||(carteNelMazzo.length>0)) ? pescaCarta(carteNelMazzo) : null;
}
public Carta pescaBriscola(){
return (carteNelMazzo==null||(carteNelMazzo.length>0)) ? carteNelMazzo[carteNelMazzo.length-1] : null;
}
/**
* #param carte deve avere lunghezza maggiore uguale ad 1
* #return la prima carta del mazzo
*/
private Carta pescaCarta(Carta[] carte){
Carta[] nuoveCarte=new Carta[carte.length-1];
Carta pescata= carte[0];
System.arraycopy(carte,1,nuoveCarte,0,carte.length);
carte = nuoveCarte;
return pescata;
}
private Carta[] creaMazzo(){
ArrayList<Carta> nuovoMazzo=new ArrayList<>();
for(int i =0; i<4; i++){
// selezione del seme
for(int j = 0;j<10;j++){
// creation of the card from another calss
Carta nuovaCarta= new Carta(Carta.SEME.values()[i],j);
nuovoMazzo.add(nuovaCarta);
}
}
return (Carta[]) nuovoMazzo.toArray();
}
//shuffle deck
private void mescolaMazzo(Carta[] carte){
Random rand = new Random();
int elements = (int) (40 * Math.random());
int elements = carteNelMazzo.length;
}
}
At the end I want this array with all the cards remix at random.

This here:
int elements = (int) (40 * Math.random());
int elements = carteNelMazzo.length;
doesn't shuffle anything. It assigns a random number to a local variable which is then thrown away. ( I actually think this shouldn't even compile, as you declare the same local variable twice in the same scope )
What you need instead: to create a function that maps your 40 indexes to new values, like:
0, 1, 3, ... 39
becomes
14, 2, 7, ...
An easy way to get there: Collections.shuffle(someList);.
For more ideas (also using arrays directly), see here.
But as you are probably doing this to learn things, I suggest you carefully digest what I told you upfront. Start by thinking how you would could shuffle a list of cards "manually" (not by touching them, but when you are told the order they have how you could "mentally" re-order them). From there, think how you could instruct a computer to do that.

use:
Collections.shuffle(<<arrayname>>);

You can try something like this:
private void shuffleCards (Card[] cards) {
for (int i = 0; i < cards.length; i++) {
Card temp = cards[i];
//random index of the array
int rnd = Math.floor(Math.random() * cards.length);
cards[i] = cards[rnd];
cards[rnd] = temp;
}
}
PS.: if this code throws an ArrayIndexOutOfBoundsException change the line
int rnd = Math.floor(Math.random() * cards.length); to int rnd = Math.floor(Math.random() * (cards.length - 1));

Here's one I learned many years ago.
int[] cards = IntStream.rangeClosed(0, 51).toArray();
Random r = new Random();
for (int i = cards.length - 1; i >= 0; i--) {
int idx = r.nextInt(i + 1);
int card = cards[idx];
cards[idx] = cards[i];
cards[i] = card;
}
And then there's always the Collections.shuffle() class.

Related

How do I rerun a static integer array?

here's the array I want to rerun:
public static int[] rollDice(int dice[]) {
// generate 5 random numbers / update dice array
for (int i = 0; i < dice.length; i++) {
dice[i] = (int)(Math.random() * 6 + 1);
}
return dice;
}
If I want to reset this array and find new random numbers how would I do that? I tried rollDice() only to get an error.
There is no point in returning the array, since you already have a reference to the array when you call the method rollDice().
Arrays are sent by reference and not by value, which means you are not working with a copy like you do with ints, instead you are modifing the original array.
Change the return type to void and remove the return and your code should work as intended.
You can get every time a new dynamic length array with random numbers, and you can access by call rollDice(integer value).
public static int[] rollDice(int length) {
final int dice[] = new int [length];
// generate array with random values
for (int i = 0; i < length; i++) {
dice[i] = (int)(Math.random() * length + 1);
}
return dice;
}
You would have to have a class member like this:
public static final int[] dice = new int[5];
Then to roll/reroll the dice use your method, else just access dice.
public static void rollDice() {
// generate 5 random numbers / update dice array
for (int i = 0; i < dice.length; i++) {
dice[i] = (int)(Math.random() * 6 + 1);
}
}
Interesting fact: Java has no static function variables as C and C++ does. In those languages it could look like this:
(I wrote it like a java Function for you Java guys)
public static int[5] rollDice(boolean reroll) {
static final int[] dice = new int[5];
if (reroll) for (int i = 0; i < dice.length; i++) {
dice[i] = (int)(Math.random() * 6 + 1);
}
return dice;
}
As you can see, static variables can be embedded into those functions. If you ask me, it's a huge minus, Java doesn't support this as I use it all the time to hide those from the class namespace.

How to merge arrays in Java Fork-Join multithreaded program?

I built a median filter and basically what it does it grabs an array of elements, filters it and returns a filtered array. Now, the sequential version works perfectly but on trying to make a Fork-Join version, I cannot get any result for arrays greater than my Sequential Threshold and it is also accompanied with ArrayIndexOutOfBounds errors.
Now, I'm not sure where I'm going wrong and after hours of research around Google and S.O, I am giving up and decided to post the question here.
Here's my code snippet that does the filtering Sequentially:
//Filter Algorithm.
private void filter(BigDecimal[] elements, int shoulder) {
//Add boundary values in beginning
for(int i=0; i<shoulder; i++){
filteredElements[i] = elements[i];
}
//Add boundary values at end
for(int i=arraySize-1; i>((arraySize-1) - shoulder); i--){
filteredElements[i] = elements[i];
}
//Add middle values to filteredElements array
for (int i = shoulder; i < elements.length-shoulder; i++) {
BigDecimal[] windowValue = prepareWindow(elements, shoulder, filterSize);
BigDecimal median = getMedian(windowValue);
filteredElements[i] = median;
}
}
/*
* Pre-condition: Get Windowed Array
* Post-Condition: Return Median
*/
private static BigDecimal getMedian(BigDecimal[] windowValue) {
Arrays.sort(windowValue);
return windowValue[(filterSize-1)/2];
}
/*
* Pre-condition: Get elements array, get shoulder value and length of filterSize. Notice that this is given name windowLength.
* Post-Condition: Return Windowed Array
*/
private static BigDecimal[] prepareWindow(BigDecimal[] elements, int shoulder, int windowLength) {
BigDecimal[] out = new BigDecimal[windowLength];
int outCounter = 0;
for(int i = position; i<position+filterSize; i++){
out[outCounter] = elements[i];
outCounter++;
}
position++;
return out;
}
//Return Filtered Array
public BigDecimal[] getFilteredArray(){
return filteredElements;
}
Now, the same sequential code applied in a Fork-Join does not work if the array is larger than the sequential threshold and I would like to know where I'm going wrong here.
Here's a snippet for my Parallel implementation:
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.concurrent.RecursiveTask;
public class Parallel extends RecursiveTask<BigDecimal[]>{
BigDecimal[] elements;
BigDecimal[] filteredElements; //Array that contains the filtered elements
int shoulder;
static int filterSize;
int begin;
int end;
static int position = 0;
static final int SEQUENTIAL_CUTOFF = 4;
public Parallel(BigDecimal[] elements, int filterSize, int begin, int end) {
this.elements = elements;
Parallel.filterSize = filterSize;
this.begin = begin;
this.end = end;
filteredElements = new BigDecimal[elements.length]; //Array that contains the filtered elements
shoulder = (filterSize - 1) / 2;
}
#Override
protected BigDecimal[] compute() {
if (end - begin <= SEQUENTIAL_CUTOFF) {
filter(elements, shoulder); //Run Filter Method
}else{
Parallel curLeft = new Parallel(elements, filterSize, this.begin, ((this.begin+this.end)/2));
Parallel curRight = new Parallel(elements, filterSize, ((this.begin+this.end)/2), this.end);
curLeft.fork();
curRight.compute();
curLeft.join();
}
return filteredElements;
}
//Filter Algorithm.
private void filter(BigDecimal[] elements, int shoulder) {
//Add boundary values in beginning
for(int i=0; i<shoulder; i++){
filteredElements[i] = elements[i];
}
//Add boundary values at end
for(int i=this.elements.length-1; i>((this.elements.length-1) - shoulder); i--){
filteredElements[i] = elements[i];
}
//Add middle values to filteredElements array
for (int i = shoulder; i < elements.length-shoulder; i++) {
BigDecimal[] windowValue = prepareWindow(elements, shoulder, filterSize);
BigDecimal median = getMedian(windowValue);
filteredElements[i] = median;
}
}
/*
* Pre-condition: Get Windowed Array
* Post-Condition: Return Median
*/
private static BigDecimal getMedian(BigDecimal[] windowValue) {
Arrays.sort(windowValue);
return windowValue[(filterSize-1)/2];
}
/*
* Pre-condition: Get elements array, get shoulder value and length of filterSize. Notice that this is given name windowLength.
* Post-Condition: Return Windowed Array
*/
private static BigDecimal[] prepareWindow(BigDecimal[] elements, int shoulder, int windowLength) {
BigDecimal[] out = new BigDecimal[windowLength];
int outCounter = 0;
for(int i = position; i<position+filterSize; i++){
out[outCounter] = elements[i];
outCounter++;
}
position++;
return out;
}
//Return Filtered Array
public BigDecimal[] getFilteredArray(){
return filteredElements;
}
}
Basically the Parallel implementation uses the sequential methods I made but I can't get it to work. Below is a list of errors I'm getting(I added the lines that are causing the errors to make reading easier. Most of the errors are in the sequential methods and I don't understand why):
Caused by: java.lang.ArrayIndexOutOfBoundsException: 8
at Parallel.prepareWindow(Parallel.java:80) > out[outCounter] = elements[i];
at Parallel.filter(Parallel.java:55) > BigDecimal[] windowValue = prepareWindow(elements, shoulder, filterSize);
at Parallel.compute(Parallel.java:29) > filter(elements, shoulder); //Run Filter Method
at Parallel.compute(Parallel.java:34) > curRight.compute();
Would really appreciate if someone could help with a meaningful answer.
Thanks.
We cannot see the whole code, but I see that somehow two compute() are called in parallel and they call prepareWindow() concurrently.
The big problem is that position is a static variable and both thread are incrementing the same reference, pushing it out of bounds.

How can I display an array from a void method?

I am a beginner with java and am trying to make a game of Yahtzee and am required to take a random dice roll as an array from a void method. Could someone explain to me why this wont work?
import java.util.Arrays;
public class YatzeeGame {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] diceRolls = new int[5];
diceRolls = throwDice(diceRolls);
System.out.println(display(diceRolls));
}
public static void throwDice(int [] dice) {
int [] roll = {(int)(Math.random()*6+1),
(int)(Math.random()*6+1),(int)(Math.random()*6+1),
(int)(Math.random()*6+1),(int)(Math.random()*6+1),
(int)(Math.random()*6+1)};
dice = roll;
}
public static String display(int [] dice) {
String str = Arrays.toString(dice);
str = str.replace("[", "");
str = str.replace("]", "");
str = str.replace("," , " ");
return str;
}
They want you to replace the array, which doesn't happen if you just assign it. Note that returning the array is still considered a better way. Extra tricky: in your existing code you make one array of size 5 and the other of size 6. Since you're calling it zahtzee we'll use 5.
public static void throwDice(int [] dice) {
for (int x = 0; x < 5; x++)
dice[x] = (int)(Math.random()*6+1);
}
There's quite a few things wrong in your code.
In the throwDice method, dice is a local variable, therefore changing it to roll, which is another local variable, doesn't affect anything outside that method.
Also your return type is void, so you cannot set any variable using the method.
You could have a method that returns an int[]:
public static int[] throwDice() {
int[] roll = new int[6];
for (int i = 0; i < 6; i++) {
roll[i] = (int) (Math.random() * 6) + 1;
}
return roll;
}
Then use it like:
int[] diceRolls = throwDice();
Explanation of why it's not working:
What you're trying to do: Change dice (the parameter you passed in) to equal to roll. Essentially, (if i'm not wrong here) you're trying to change diceRolls using throwDice.
What you're actually doing: You've passed in diceRolls and said "here, let's call it dice". Then, at the end of your function, you've essentially said "dice doesn't mean diceRolls anymore. dice now means roll". Which means that diceRolls still hasn't changed.
You need to change the actual values of dice instead of changing what dice is.
eg:
public static void throwDice(int[] dice) {
// change the actual values of dice, instead of changing dice
dice[0] = (int) (Math.random() * 6 + 1);
dice[1] = (int) (Math.random() * 6 + 1);
dice[2] = (int) (Math.random() * 6 + 1);
dice[3] = (int) (Math.random() * 6 + 1);
dice[4] = (int) (Math.random() * 6 + 1);
}

Java Loops and Random numbers

Hi I am having some problems with using random numbers inside of loops.
private void SetMines()
{
Random randRowGen = new Random();
Random randColGen = new Random();
int mineCount = 0;
int numMines = (ROWS * COLUMNS)* (int)0.156;
while(mineCount <= numMines)
{
int randRow = randRowGen.nextInt(ROWS)+1;
int randCol = randColGen.nextInt(COLUMNS)+1;
grid[randRow][randCol] = new Character('*');
mineCount++;
}
}
Here is my method it is going through an array size 25 * 25 and picking random spots and putting "mines" there. The only problem is it only selects one location to put a "mine" in and it needs to put 97 mines in random spots.
Any help will be appreciated thanks!!
Your numMines calculation will always return 0, because when you cast a double that is less than 1 to an int, it will be set to 0, which means that the statement in your while loop will only be run a single time, hence only a single mine being placed.
The problem isn't Random, it's int numMines = (ROWS * COLUMNS)* (int)0.156;. Have you checked what that value is? It's 0, because (int) 0.156 equals 0.
Perhaps you want int numMines = (int) ((double) 0.156 * ROWS * COLUMNS);. The problem with integer maths is that you can lose a LOT of precision.
Make your computer suffer and make it drop all those mines.
Remember. The definition of "computation" is "to force a machine do a boring job that nobody else would like to do" :-)
public static void main(String[] args) {
int rows = 25;
int cols = 25;
boolean[][] mines = new boolean[rows][cols];
while(mineCount(mines) < 97){
dropMine(mines);
}
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
System.out.print("[");
if (mines[i][j]){
System.out.print("*");
}else{
System.out.print(" ");
}
System.out.print("] ");
}
System.out.println();
}
}
private static void dropMine(boolean[][] mines) {
int x = (int)(Math.random()*25);
int y = (int)(Math.random()*25);
mines[x][y] = true;
}
private static int mineCount(boolean[][] mines) {
int count = 0;
for(int i=0;i<25;i++){
for(int j=0;j<25;j++){
if (mines[i][j]){
count++;
}
}
}
return count;
}

How to create a number generator that will only pick a number 1 time?

I am creating a concentration game.
I have an buffered image array where I load in a 25 image sprite sheet.
public static BufferedImage[] card = new BufferedImage[25];
0 index being the card back. and 1 - 24 being the values for the face of the cards to check against if the cards match.
What I am tying to do is this I will have 4 difficulties Easy, Normal, Hard, and Extreme. Each difficulty will have a certain amount of cards it will need to draw and then double the ones it chosen. for example the default level will be NORMAL which is 12 matches so it need to randomly choose 12 unique cards from the Buffered Image array and then double each value so it will only have 2 of each cards and then shuffle the results.
This is what I got so far but it always seems to have duplicates about 99% of the time.
//generate cards
Random r = new Random();
int j = 0;
int[] rowOne = new int[12];
int[] rowTwo = new int[12];
boolean[] rowOneBool = new boolean[12];
for(int i = 0; i < rowOneBool.length; i++)
rowOneBool[i] = false;
for(int i = 0; i < rowOne.length; i++){
int typeId = r.nextInt(12)+1;
while(rowOneBool[typeId]){
typeId = r.nextInt(12)+1;
if(rowOneBool[typeId] == false);
}
rowOne[i] = typeId;
j=0;
}
the 3 amounts I will be needing to generate is Easy 6, Normal 12, and Hard 18 extreme will use all of the images except index 0 which is the back of the cards.
This is more or less in the nature of random numbers. Sometimes they are duplicates. You can easily factor that in though if you want them to be more unique. Just discard the number and generate again if it's not unique.
Here's a simple method to generate unique random numbers with a specified allowance of duplicates:
public static void main(String[] args) {
int[] randoms = uniqueRandoms(new int[16], 1, 25, 3);
for (int r : randoms) System.out.println(r);
}
public static int[] uniqueRandoms(int[] randoms, int lo, int hi, int allowance) {
// should do some error checking up here
int range = hi - lo, duplicates = 0;
Random gen = new Random();
for (int i = 0, k; i < randoms.length; i++) {
randoms[i] = gen.nextInt(range) + lo;
for (k = 0; k < i; k++) {
if (randoms[i] == randoms[k]) {
if (duplicates < allowance) {
duplicates++;
} else {
i--;
}
break;
}
}
}
return randoms;
}
Edit: Tested and corrected. Now it works. : )
From what I understand from your question, the answer should look something like this:
Have 2 classes, one called Randp and the other called Main. Run Main, and edit the code to suit your needs.
package randp;
public class Main {
public static void main(String[] args) {
Randp randp = new Randp(10);
for (int i = 0; i < 10; i++) {
System.out.print(randp.nextInt());
}
}
}
package randp;
public class Randp {
private int numsLeft;
private int MAX_VALUE;
int[] chooser;
public Randp(int startCounter) {
MAX_VALUE = startCounter; //set the amount we go up to
numsLeft = startCounter;
chooser = new int[MAX_VALUE];
for (int i = 1; i <= chooser.length; i++) {
chooser[i-1] = i; //fill the array up
}
}
public int nextInt() {
if(numsLeft == 0){
return 0; //nothing left in the array
}
int a = chooser[(int)(Math.random() * MAX_VALUE)]; //picking a random index
if(a == 0) {
return this.nextInt(); //we hit an index that's been used already, pick another one!
}
chooser[a-1] = 0; //don't want to use it again
numsLeft--; //keep track of the numbers
return a;
}
}
This is how I would handle it. You would move your BufferedImage objects to a List, although I would consider creating an object for the 'cards' you're using...
int removalAmount = 3; //Remove 3 cards at random... Use a switch to change this based upon difficulty or whatever...
List<BufferedImage> list = new ArrayList<BufferedImage>();
list.addAll(Arrays.asList(card)); // Add the cards to the list, from your array.
Collections.shuffle(list);
for (int i = 0; i < removalAmount; i++) {
list.remove(list.size() - 1);
}
list.addAll(list);
Collections.shuffle(list);
for (BufferedImage specificCard : list) {
//Do something
}
Ok, I said I'd give you something better, and I will. First, let's improve Jeeter's solution.
It has a bug. Because it relies on 0 to be the "used" indicator, it won't actually produce index 0 until the end, which is not random.
It fills an array with indices, then uses 0 as effectively a boolean value, which is redundant. If a value at an index is not 0 we already know what it is, it's the same as the index we used to get to it. It just hides the true nature of algorithm and makes it unnecessarily complex.
It uses recursion when it doesn't need to. Sure, you can argue that this improves code clarity, but then you risk running into a StackOverflowException for too many recursive calls.
Thus, I present an improved version of the algorithm:
class Randp {
private int MAX_VALUE;
private int numsLeft;
private boolean[] used;
public Randp(int startCounter) {
MAX_VALUE = startCounter;
numsLeft = startCounter;
// All false by default.
used = new boolean[MAX_VALUE];
}
public int nextInt() {
if (numsLeft <= 0)
return 0;
numsLeft--;
int index;
do
{
index = (int)(Math.random() * MAX_VALUE);
} while (used[index]);
return index;
}
}
I believe this is much easier to understand, but now it becomes clear the algorithm is not great. It might take a long time to find an unused index, especially when we wanted a lot of values and there's only a few left. We need to fundamentally change the way we approach this. It'd be better to generate the values randomly from the beginning:
class Randp {
private ArrayList<Integer> chooser = new ArrayList<Integer>();
private int count = 0;
public Randp(int startCounter) {
for (int i = 0; i < startCounter; i++)
chooser.add(i);
Collections.shuffle(chooser);
}
public int nextInt() {
if (count >= chooser.size())
return 0;
return chooser.get(count++);
}
}
This is the most efficient and extremely simple since we made use of existing classes and methods.

Categories

Resources