java.lang.IllegalArgumentException: n must be positive in deck class - java

I'm making a card game and I'm getting the error that n must be positive. I did some research and it means that (cards.size) is equal or less than 0 I believe, but I don't understand how to make my code work, something must be wrong.
Code:
public class Deck
{
public ArrayList <Card> cards;
Deck()
{
cards = new ArrayList<>();
for (int a = 0; a < 52; a++)
{
cards.add(new Card(a));
}
}
public Card PlayerCardDraw ()
{
Random generator = new Random ();
int index = generator.nextInt (cards.size ());
return cards.remove (index);
}
How can I fix my array list so i don't get this error? it relates back to Card so I'll post that code too, I know something isn't right in my Card class but I don't know if that's the problem or not.
public class Card
{
int c = 52;
int cardpath[] = new int[c];
Card ()
{
}
public Card(int c)
{
this.c = c;
}
public int getCardPath()
{
return cardpath[c];
}
}
Error message:
java.util.Random.nextInt(Unknown Source) at Cards.Deck.PlayerCardDraw(Deck.java:21)
line 21 is int index = generator.nextInt (cards.size ());
EDIT: I did what Nankumar Tekale said and it's saying what you guys predicted: It's drawing more than 52 cards. What I don't understand is the error is popping up at
for (int i = 0 ; i < 4 ; i++)
{
C = deck.P1CardDraw ();
card [cardNum].draw (i*75+100, 400); //Error line
cardNum++;
}
my P1CardDraw() class
public ArrayList < Card > p1Hand;
public ArrayList < Card > P1CardDraw ()
{
p1Hand = new ArrayList < > ();
p1Hand.add (PlayerCardDraw ());
return p1Hand;
}

Well looking at your Deck class, You have intialized cards in constructor so there should not be such an exception(as cards size is 52).
But one thing is possible to get an exception which is cards is declared public and you may have modified it outside class directly. So arraylist cards is of size 0 and you get IllegalArgumentException exception for your method Random.nextInt(int).
Make cards private.
If you have withdrawn all cards then size of arraylist would become 0, which may cause an exception. Add check for 0 as :
public Card PlayerCardDraw ()
{
Random generator = new Random ();
if(cards.size() > 0) {
int index = generator.nextInt (cards.size());
return cards.remove (index);
} else {
return null;
}
}

You might be calling PlayerCardDraw method even before a card is added to the list. Means cards.size() must be returning a zero. So it is illegal to generate a random int using a zero seed. Hence is the error.
Refer to:
Random.nextInt( n )

My guess is that you keep calling PlayerCardDraw more than 52 times.
Each time, a card is removed from the deck, so the 53:d time, you are trying to draw a card from an empty deck (ie. a deck of size 0) which causes generator.nextInt(cards.size()); to throw an exception.
However it is not easy to say.
When you are having problems like this and want help, always show the full stack trace of the exception. Also, since we cannot see line numbers in code on stackoverflow, be sure to indicate in the code exactly at which line the exception occurs.

Related

How to debug my poker game recursion logic?

public static ArrayList<Hand> getPossibleHands(Hand h) {
ArrayList<Hand> allPossible = new ArrayList<Hand>();
addNext(allPossible, h);
return allPossible;
}
public static void addNext(ArrayList<Hand> poss, Hand h) {
if (h.cards.size() == 5)
poss.add(h);
else
for (int i = 0; i < 52; i++) {
Card c = Card.makeCard(i);
if (!h.contains(c))
h.add(c);
addNext(poss,h);
}
}
The code above is supposed to essentially take an incomplete poker board (anywhere from 0-4 cards) and return all possible complete boards (5 cards). The logic that I feel like it should follow is as follows: recurse through every combination of adding valid (not on the board already) cards until the size of the board is equal to 5 in which case it will add the board to the list and skip over the rest of the function.
However upon using a print statement at the beginning of the function I see that hand sizes of greater than 5 or being created. Since the first part of the function should catch all hands at 5 and terminate it there, I don't see how the code executes at the rest of the function.
Your class should receive stack overflow with an empty hand.
You send new Card(0) to the hand. This is added.
Then you call add next again - and the 'for' starts from 0 again. Checks adds 1. Then starts from 0 - it is there, does not add anything and starts over. Where it starts from 0. Does not do anything. Starts from 0. Ad infinum -> StackOverFlow.
You also need to reset to previous state of the hand every time you finish with 5 cards and backtrack.
If you want a recursive solution you can try :
private static ArrayList<Hand> getPossibleHands(Hand h) {
ArrayList<Integer> except;
if (h.cards == null) except = new ArrayList<>();
else
except = h.cards.stream().map(c -> (c.getCard())).collect(Collectors.toCollection(ArrayList::new));
ArrayList<Hand> allPossible = new ArrayList<>();
addNext(allPossible, h, except);
return allPossible;
}
private static void addNext(ArrayList<Hand> poss, Hand h, ArrayList<Integer> except) {
//assuming hands 0-4 - we don't need to check on entry, only when we add
Hand localHand = h.copy();
for (int i = 0; i < 52; i++) {
if (except.contains(i)) continue;
Card c = Card.makeCard(i);
if (!localHand.contains(c)) {
addNext(poss, localHand.copy(), copyExcept(except, i));
localHand.add(c);
if (localHand.cards.size() == 5) {
poss.add(localHand);
break;
}
}
}
}
private static ArrayList<Integer> copyExcept(ArrayList<Integer> except, int i) {
ArrayList<Integer> clonedExcept = new ArrayList<>(except);
clonedExcept.add(i);
return clonedExcept;
}
import java.util.ArrayList;
public class Hand {
ArrayList<Card> cards = new ArrayList<>();
public boolean contains(Card c) {
for (Card card : cards) {
if (card.getCard() == c.getCard())
return true;
}
return false;
}
public void add(Card c) {
cards.add(c);
}
Hand copy() {
Hand temp = new Hand();
for (Card c : cards) {
temp.add(new Card(c.getCard()));
}
return temp;
}
}
class Card {
private int card;
public Card(int card) {
this.card = card;
}
public static Card makeCard(int i) {
return new Card(i);
}
public int getCard() {
return card;
}
}
Initially, h is (presumably) empty. So addNext will loop through all possible cards, and since none of them are in the hand, add each card to the hand, regardless of how many cards are currently in the hand.
It looks to me like your for loop is eventually adding whole deck to hand.
In your loop you run 52 iterations. On each iteration you (conditionally) add a card to the hand and then you call your function recursively. But after that recursive call has returned, you go to the next iteration and again add a card to the hand.
So that '5 card restriction' does not restrict anything here.

Java for loop ArrayList, indexoutofboundsexception

public static void main(String[] args){
........................
for(int i = 0; i<play.size(); i=i+1){
System.out.println("the Winner is; " +Winners(play).get(i).name);
}
}
This is the main method. i didnt write down Everything here, because its unnecesary. basically what i am doing, is that i am Calling Winners method that takes ArrayList<Game> as argument. play is of type ArrayList<Game>. on that i want to get the elements stored inside and get their name. so that the winners name is shown on screen. i for loop it because there can be several winners. depends on how many shares the same score.
private static ArrayList<Game> Winners(ArrayList<Game> gamers){
ArrayList<Game> winner = new ArrayList<Game>();
for(int i = 1; i==gamers.size(); i=i+1){
if(gamers.get(i).getPoints()>gamers.get(i-1).getPoints()){ winner.clear();
winner.add(gamers.get(i));
}
else if(gamers.get(i).getPoints()<gamers.get(i-1).getPoints()){ winner.clear();
winner.add(gamers.get(i-1));
}
else if(gamers.get(i).getPoints()==gamers.get(i-1).getPoints()){ winner.clear();
winner.add(gamers.get(i));
winner.add(gamers.get(i-1));
}
}
return winner;
}
the Winners method returns an Arraylist<Game>, which is where the gamer or gamers with top score are stored.
i loop through each on of the gamers and compare their points to each other. the one who has the most score gets stored in the Winner arraylist.
i clear the winner arraylist all the time some elements goes inside, because i only want the top Points stored there.
My issue is, i dont know if i am doing it correct. because i am getting error on
on the System.out.println("the Winner is; " +Winners(play).get(i).name);.
it says index 0 size 0 (indexoutofboundsexception)
for(int i = 1; i==gamers.size(); i=i+1)
It means the loop will terminate when i==gamers.size() is false. At the first time when i=1, but gamers.size() is greater than 1. It never enters the loop. And returns empty list. When you trying to get one element from an empty list, you are getting the exception.
But I think you want to check i < gamers.size(). It might be:
for(int i = 1; i < gamers.size(); i++)
Again, you don't need winner.clear() in each if block. Rather you could:
private static ArrayList<Game> Winners(ArrayList<Game> gamers) {
ArrayList<Game> winner = new ArrayList<Game>();
for (int i = 1; i < gamers.size(); i++) {
winner.clear();
if (gamers.get(i).getPoints() > gamers.get(i - 1).getPoints()) {
winner.add(gamers.get(i));
} else if (gamers.get(i).getPoints() < gamers.get(i - 1).getPoints()) {
winner.add(gamers.get(i - 1));
} else { // last check when points are equal
winner.add(gamers.get(i));
winner.add(gamers.get(i - 1));
}
}
return winner;
}
N.B: There is an issue in the approach of your Winners() method. You are iterating over gamers and adding a winner to the list. But every time you are clearing the list. That means you will get only the winner from last two players. Previous winners will be cleared. I think you need to recheck it.
As you are clearing the list, the size of winner list won't be same as the size of play. As a result, you will also get exception in this code.
for(int i = 0; i < play.size(); i=i+1) {
System.out.println("the Winner is; " + Winners(play).get(i).name);
}
One fix could be:
ArrayList<Game> winnersList = Winners(play);
for(int i = 0; i < winnersList.size(); i++) {
System.out.println("the Winner is; " + winnersList.get(i).name);
}

Java array -(parallel array)

I am struggling with Arrays (java)
Since this is the first time to learn about java in my life, I have no idea how to start it. I have just learned how to declare arrays and so on. However, this is too complicated for me. I think I can get guidelines if I see this answer. Can anybody help me out?
the prog
Read the java.util.Scanner (API). Your code works. You can do what you want with the scores, just read them from the file and cast them to the appropriate data types (integers) for calculating average scores etc.
The variables are strings, so you must cast them to numbers to make your calculation.
You can use arraylist ArrayList<TeamMember> as an instance variable of TeamMembers for your Teams or a collection with primitive types for the team but I think best is if you make classes for Team, TeamMember and Score that you instanciate in your Bowling class. You can find this information anywhere.
import java.util.Scanner;
//...
Team usa = new Team();
Team mexico = new Team();
TeamMember person = new TeamMember(usa); //Harry plays for the US
...
Scanner in = new Scanner(System.in);
int num = in.nextInt();
If you know that every third input is a score then you can check modulo 3 (% 3) to know which iteration is divisible by 3. .
I have done about 40% of your request, i think that's enough for you to go on. You should be able to finish it on your own.
If you have further question,just leave a comment.
( There are some hidden bugs for you,to handle it you should have an understanding of scope first, just for your learning. )
import java.io.*;
import java.util.*;
// declaration of the class
public class Bowling2 {
// declare arrays below
String Team, Member;
int Score, Scorew, Scoreb;
int[][] teamw = new int[10][3];
int[][] teamb = new int[10][3];
// declaration of main program
public static void main(String[] args) throws FileNotFoundException {
// 1. connect to input file
Scanner fin = new Scanner(new FileReader("bowling.txt"));
// 2) initialize array accumulators to zero
int i, j, Scoreb, Scorew = 0 ;
// 3) display a descriptive message
System.out.println(
"This program reads the lines from the file bowling.txt to determine\n"
+ "the winner of a bowling match. The winning team, members and scores\n"
+ "are displayed on the monitor.\n");
// 4) test Scanner.eof() condition
while (fin.hasNext()) {
// 5) attempt to input next line from file
Member = fin.next();
Team = fin.next();
Score = fin.nextInt();
// 6) test team color is blue
if (Team.toString() == "blue" ){
// 7) then store blue member and score
teamb[i][0] = Member;
teamb[i][1] = Team;
teamb[i][2] = Score;
// 8) increase blue array accumulator
sumArray("blue");
i++;
}
// 9) else store white member and score
else {
teamw[j][0] = Member;
teamw[j][1] = Team;
teamw[j][2] = Score;
// 10) increase white array accumulator
sumArray("white");
j++;
}
}
// 11) if blue team score is larger
// 12) then display blue team as winner
// 13) else display white team as winner
// 14 disconnect from the input file
fin.close();
}
// implement method `sumArray()` below
/* 1. initialize accumulator to 0
2. loop over initialized array indices
3. increase accumulator by indexed array element
4. return accumulator
*/
public double sumArray(string color) {
if (color == "blue") {
for (int k = 0;k < teamb.length(); k++) {
//do the calculation here, and return it
}
}else {
for (int h = 0;h < teamw.length(); h++) {
//do the calculation here, and return it
}
}
}
// implement method `printArray()` below
/* 1. display the team name as the winner
2. loop over initialized array indices
3. display member and score for that array index
*/
}

How to set the Text in TextFields to the numbers of an Array

I need to set each TextField in my JFrame to the corresponding number in a pre-generated array of numbers but I do not know how.
This is what I need it to look like:
Here is the ActionListener Class that I am working with:
public class RandListener implements ActionListener
{
private final JTextField[] tF;
public RandListener(JTextField[] tF)
{
this.tF = tF;
}
#Override
public void actionPerformed(ActionEvent e)
{
int [] rArray = new int[10];
Random rNum = new Random();
for(int k = 0; k < rArray.length; k++)
{
rArray[k] = rNum.nextInt(100);
}
if(e.getActionCommand().equals("bRand"))
{
for(int k = 0; k < tF.length; k++)
{
tF[k].setText(/*I need to set the text of my TextFields to the numbers in the array*/);
}
}
if(e.getActionCommand().equals("bMaxMin"))
{
//I need to find the maximum and minimum of the Array here
}
}
}
Read up on how Strings in Java work. Basically, if you would want to turn the number into a string:
tF[k].setText(/*I need to set the text of my TextFields to the numbers in the array*/);
turns into:
tF[k].setText("" + rArray[k]);
I believe this is done automatically by Java; number boxing turns the primitive type into its respective wrapper (int -> Integer) and then then toString() is called on the Integer object which represents the primitive type.
Now, to find the minimum and maximum, you're going to have to think a little bit. This is an elementary problem companies will give to weed out bad candidates. Figure it out once on your own and you'll never forget it. Think of how you would do it as a human; you take the current biggest/smallest and compare it to whatever you're looking at currently.

Some issue with an enhanced for loop-SimpleDotCom

This is a modified example from the book, Head First Java. It's a kind of Battleship game where a 3 element array is being used as the battleship. The user has to guess these 3 locations. Currently, I've hard-coded the values of the ship location to 2,3,4. When the user guesses the correct location "Hit" is printed. If not then "Miss" is printed. If a user guesses all 3 locations then "Kill" is printed. But I have a problem. Currently if the user enters the same location multiple times, it still gives a hit. I tried to fix this by changing the value of a variable that has already been hit (int cell) to "-1". But for some reason this didn't fix it too. Please tell me what I am doing wrong.
public class Game {
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] location = {2,3,4};
SimpleDotCom firstGame = new SimpleDotCom();
firstGame.setLocation(location);
firstGame.checkYourself("2");
firstGame.checkYourself("2");
//firstGame.checkYourself("2");
}
}
public class SimpleDotCom {
int [] loc = null;
int numOfHits = 0;
void setLocation (int [] cellLocation){
loc = cellLocation;
}
void checkYourself(String userGuess){
int guess = Integer.parseInt(userGuess);
String result = "Miss";
for(int cell:loc){
if (guess == cell){
result = "Hit";
numOfHits++;
cell = -1;
break;
}
if (numOfHits==loc.length){
result = "Kill";
}
}
System.out.print("Result: " + result);
System.out.println(" ** Num of Hits: " + numOfHits);
}
}
When you loop over loc, you get an int cell for each location. The problem is that that variable doesn't have any connection to the array, it's only a copy. If you change it, nothing's going to happen to the original array. I suggest looping over loc with a traditional for(;;) and using the current array index within the loop's logic to set the right "cells" to -1.
because you are assigning -1 to local variable. not updating in array actually
for(int cell:loc){ // cell is local copy of element in array is you have array of primitive int
if (guess == cell){
result = "Hit";
numOfHits++;
cell = -1;
break;
}
if (numOfHits==loc.length){
result = "Kill";
}
}
You can use traditional for loop for this or use List which has methods for adding removing elements.
You need to update the array at the correct index, not simply change the value of the cell variable, which only references the array element at the current iteration state.
You should probably use a traditionnal for loop for that, since you cannot get the index for free from an enhanced for loop.
for (int i = 0; i < loc.length; i++) {
//code...
loc[i] = -1; //instead of cell = -1;
}

Categories

Resources