1

I'm making a card game, and I've arrived at the shufflin' time.

I've to shuffle a few cards (that are chosen before from the user, so they're not always the same amount) and then display them to the user one by one.

As I'm still developing the game's logic I'm displaying cards' name by changing a button text.

But I get stuck when I try to get the cards' name and set them as the button's text.

What happens is me gettin' a blank button or just with "Masons" or "Villager" String. Infact if I check the log I see that all the others cards(characters) get displayed as "null".

This is how I tried to achieve the goal (Yes I'm a newbie):

This is the head:

int demoniac;
int guard;
int masons;
int medium;
int mythomaniac;
int owl;
int villager;
int werehamster;
int all;
int i;
int t;
String[] characters = new String[24];
Button randomButton;

My method to addAll the cards(characters):

public void addAll(){
for(i = 0; i < all; i++){
    add(demoniac, "Demoniac");
    add(guard, "Guard");
    add(medium, "Medium");
    add(mythomaniac, "Mythomaniac");
    add(owl, "Owl");
    add(werehamster, "Werehamster");
    add(villager, "Villager");
    add(masons, "Masons");
   }

}

My method to add and manage the various types of cards(characters):

public int add(int character, String name){
    if(character != 0 && name == "Villager"){
        for(t = 0; t < character; t++){
            i+=t;
            characters[i] = name;}
    }
    else if(character == 2 && name == "Masons"){
        characters[i] = name;
        i++;
        characters[i] = name;
        Toast.makeText(randomSelection.this, "works", Toast.LENGTH_SHORT).show();
    }else if(character != 0){
        characters[i] = name;
    }
    return i;
}

To randomize:

 public void randomize(){
    Collections.shuffle(Arrays.asList(characters));
    for (int s = 1; s < characters.length; s++)
    {
        System.out.println(characters[s]);
    }

}

The method to display a different card(character) each time the user clicks the button:

public void show(View view){
    for (int s = 1; s < characters.length; s++)
    {
        randomButton.setText(characters[s]);
    }
}

EDIT:

I've noticed the no sense for loop I've done, by the way you should know although most of the characters are only 1 of their kind (demoniac, guard, etc..) there are 2 Masons and from 5 to 12 Villagers, so We need to retrieve these ints and add as much Strings to the Array as much we're told from those ints.

Example: If I get 6 Villagers, I've to add the String "Villager" 6 times into the String Array.

Then I've set that s value to 1 'cause I've to display the first String ([0]) as soon as the Activity gets started, so on the OnCreate() method.

Maybe I'm wrong, if so I please you to correct me!

FET
  • 942
  • 4
  • 13
  • 35

3 Answers3

1

Getting a blank button or just with "Masons" or "Villager" String

That is because you only set the Button's text with the last element of the list. Which is either null or "Masons" (not seeing how it could be "Villager").

for (int s = 1; s < characters.length; s++)
{
    randomButton.setText(characters[s]);
}

If I check the log I see that all the others cards(characters) get displayed as "null"

You only set position 0 of your array. For example, you don't initialize the positions, so these int values default to 0.

int demoniac;
int guard;
int all;

Then

for(i = 0; i < all; i++){
    add(demoniac, "Demoniac");
    add(guard, "Guard");

Really, that loop shouldn't be entered because all equals 0.

Additionally

Collections are zero-indexed, so this doesn't print element 0. You need to set int s = 0;.

for (int s = 1; s < characters.length; s++)

It isn't clear to me what the add(int character, String name) method is returning, but if you explain it, I will update this answer.

I believe this code fulfills most of what you are trying to achieve

// Where the characters are stored
private ArrayList<String> characters;

public void initDeck() {
    if (characters == null)
        characters = new ArrayList<String>();
    // Extract the numbers if you actually need them, otherwise, they just are constants
    addCharacter("Demoniac", 1, characters);
    addCharacter("Guard", 1, characters);
    addCharacter("Medium", 1, characters);
    addCharacter("Mythomaniac", 1, characters);
    addCharacter("Owl", 1, characters);
    addCharacter("Werehamster", 1, characters);
    addCharacter("Villager", 5, characters);
    addCharacter("Masons", 1, characters);
}

public void addCharacter(String name, int amount, ArrayList<String> cards) {
    if (amount < 0) {
        throw new IllegalArgumentException("Must add a non-negative number of characters for " + name);
    }

    // Don't use '==' for Strings
    if (name.equals("Villager")) {
        if (amount != 5 || amount != 12) {
            throw new IllegalArgumentException("There can only be 5 or 12 " + name);
        }
    }

    for (int i = 0; i < amount; i++) {
        cards.add(name);
    }
}

public int searchCharacters(String character, ArrayList<String> cards) {
    return cards.indexOf(character);
}

public Map<String, Integer> getAllCharacterPositions() {
    Map<String, Integer> allPositions = new LinkedHashMap<String, Integer>();
    for (int i = 0; i < characters.size(); i++) {
        allPositions.put(characters.get(i), i);
    }
    return allPositions;
}

void run() {
    // initialize the characters
    initDeck();

    // shuffle them
    Collections.shuffle(characters);

    // print them all out
    for (int i = 0; i < characters.size(); i++) {
        System.out.printf("%d: %s\n", i, characters.get(i));
    }

    // Find the position of a character
    System.out.println();
    String findCharacter = "Owl";
    // Option 1 -- always linear search lookup
    System.out.printf("%d: %s\n", searchCharacters(findCharacter, characters), findCharacter);
    // Option 2 -- one-time linear scan, constant lookup
    Map<String, Integer> positions = getAllCharacterPositions();
    System.out.printf("%d: %s\n", positions.get(findCharacter), findCharacter);

    // Get a random character
    System.out.println();
    Random rand = new Random(System.currentTimeMillis());
    int randPos = rand.nextInt(characters.size());
    System.out.printf("%d: %s\n", randPos, characters.get(randPos));

    // randomButton.setText(characters.get(randPos));
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • Thank You for the very detailed answer, I've edited my question, maybe now I've expressed myself in a better way ;) – FET Jan 29 '16 at 14:27
  • Awesome cricket, I think there's just one missing edit to do, the amount of the characters isn't always the same, it might be 1 or might be 0, and in the Villager case it might be a value from 5 to 12 – FET Jan 29 '16 at 16:13
  • @FET - doesn't need an edit. Just change the parameters in `initDeck` to whatever you want. If you need if-conditions, then update `addCharacter` – OneCricketeer Jan 29 '16 at 16:16
  • @FET - But I have made the edit anyways, because you were comparing strings incorrectly – OneCricketeer Jan 29 '16 at 16:19
  • Tried to mae the method foe the button this way, I need to take next String each time I click: `public void pick(View view){ while(i < characters.size()) { randomButton.setText(characters.get(i)); i++; } }` – FET Jan 29 '16 at 20:14
  • Achieved that this way: `public void pick(View view){ if(i < characters.size()) { randomButton.setText(characters.get(i)); i++; }else { randomButton.setText(null); randomButton.setEnabled(false); } }` Now I'd just like to know what you think about weston's suggestion (I mean the fact of using a card class etc) Just to know what You suggest :) – FET Jan 29 '16 at 20:56
  • I don't understand the purpose of your `i` variable. You don't need it at all... As far as using a class goes, I would only suggest that if each Character had more properties than just a name. As is, you are only using the String, so that's up to you if you want to encapsulate the String into a class. – OneCricketeer Jan 29 '16 at 21:35
  • I'm trying to display all of the Strings one by one, each time you press the button, until you reach the max size of them. – FET Jan 29 '16 at 21:50
  • Ah. I gotcha now. You could do `setText(characters.get(++i)`, then I think. – OneCricketeer Jan 29 '16 at 21:53
  • Nope, as then at the end I'll be passing an index which would be always greater than 1. So I need to add the i++ after having set the text of the button as the current i value. By the way, thank you for your help, it does work anyways! – FET Jan 29 '16 at 22:50
1

Given the array is already shuffled, just look at the first card:

public void show(View view){
    randomButton.setText(characters[0]);
}

If you want to navigate that deck I suggest you put the shuffled list in to a Queue, where you can look at the next card (peek) or take the next card (poll):

private static Queue<string> buildNewShuffledDeck(String[] characters){
    List<String> shuffledCharacterList = new ArrayList<String>(characters);
    Collections.shuffle(shuffledCharacterList);
    Queue<string> deck = new ArrayDeque(shuffledCharacterList);
    return deck;
}

public void show(View view){
    String nextCard = deck.peek();
    if (nextCard != null)
      randomButton.setText(nextCard);
    else
      //deck is empty...
}

Then to take from the deck, say on the random button click:

String nextCard = deck.poll();

General advice on arrays: Stop using them in favor of other data types that are far more useful and interchangeable.

Then next step advice, make a class that represents a Card and stop using Strings, the string you currently have is just one property of a card.

weston
  • 54,145
  • 21
  • 145
  • 203
  • Thank you! I'll really consider about creating that class when redesigning my code, for now I'll keep on going this way, then I'll get to the cleaner and smarter way ahaha, by the way thumbs up for your help, thank you! – FET Jan 29 '16 at 22:51
0

You are just displaying the last character name that you add Replace with this

public void show(View view){
    Random r = new Random(System.currentTimeMillis());
    randomButton.setText(characters[r.nexInt(characters.length)])
}
Radu Ionescu
  • 3,462
  • 5
  • 24
  • 43