Ok, I'm getting a little confused on how to do this. Basically i got N stacks of cards. And need to check the topCard of every stack and check that N - 1 cards match then remove them.

I peeked every stack of cards to get the top card, and added them to an arraylist. But I'm not sure how to go through the arraylist to check that n-1 match or not. (Each card has a getCard method which returns the number then suite as a String (2 Hearts or Ace Diamonds).
(both suite and number have to match)
I'm just getting a bit confused on the best/most efficient way of implementing this.

Recommended Answers

All 32 Replies

There's a for loop in Java that lets you go over each element in a collection. It looks something like this:

for (<datatype> <variable> : <collection>) {
   // do something here with <variable>
}

A more concrete example. Say you have an ArrayList called myList, and it stores data of type String. The for loop would look like this:

for (String str : myList) {  // you could call the variable something other than str if you want
   // do something here with str
}

Let me get this straight - you have an array list consisting of N cards and you want to see that each one of the cards is different?

Yeah i understand while, if and for loops. But im stuck on how to compare the elements within the arraylist. I can't compare the next element with the last, as they may be different.
EG:
2 Hearts
3 Spade
2 Hearts
2 Hears

If i compared to last element, it would only get to the end and find 2 matching cards( not the 3 it needs (N -1 (4 - 1)))

Let me get this straight - you have an array list consisting of N cards and you want to see that each one of the cards is different?

No, i need to check whether N - 1 of the cards match. If theres 4 stack, i need to check if 3 are identical cards, if they are remove them. There is any number of stacks (N)

To get the element from ArrayList, use get(index) and you will get the card object. Then you can use getCard() from it to obtain the String for comparison. Is that what you are looking for?

Basically you don't need to compare all of the elements in the array - if you start with card type A, you iterate over the array cells and you are allowed to only once encounter a different card. If you encounter a different card more than once then there is no way that N-1 cards will be equal, and you return false. Just keep two counters for two different card types.

Basically you don't need to compare all of the elements in the array - if you start with card type A, you iterate over the array cells and you are allowed to only once encounter a different card. If you encounter a different card more than once then there is no way that N-1 cards will be equal, and you return false. Just keep two counters for two different card types.

Ahhh, I think that is a great way of doing it, i will try to implement it soon and see if it works!

ok, heres my attempt, but i don't think its gr8. Also, using this method, once i've found that N-1 do match, how can i remove just the matching ones from the arraylist and the stack they orginated from?

private boolean compareCards(){
		Iterator it = topCards.iterator();
		String last = "";
		int i = 0;
		while(i != 2){
			while(it.hasNext()){
				last = it.next().toString();
				if(it.next()!= last){
					i++;
				}
			}
			
		}
		if(i <= 2){
			return false;
		}
		else{
			return true;
		}
		
	}

In a bit of a hurry but I hope this will give you some idea what to do. It includes some cases that you have missed, and let you know which is the type to remove.

private boolean compareCards()
{
	Iterator it = topCards.iterator();
	String type1 = null, type2 = null, current;
	int numCards, counter1, counter2;
	if(it.hasNext())
	{
		type1 = it.next();
		++counter1;
		++numCards;
	}
	while(it.hasNext() && !(counter1 > 1 && counter2 > 1))
	{
		current = it.next().toString();
		if(current.equals(type1))
		{
			++counter1;
		}
		else
		{
			if(type2 == null)
			{
				type2 = current;
				++counter2;
			}
		}
		++numCards;
	}
	if(counter1 > 1 && counter2 > 1)
	{
		return false;
	}
	else if(counter1 <= 1)
	{
		//you know that the type is type2, you need to remove type2 from the array and the stack.
		return true;
	}
	else
	{
		//you know that the type is type1, you need to remove type1 from the array and the stack.
		return true;
	}
}

I will come back later today and see if I have some better idea. Hope that will help you for now.

Ok thanks for your help. Just to let you know, theres not just two types of cards, there are 52 cards in a deck, so 52 different types. But N number of cards will be compared. At one time, there could be N different cards on top.

It's quite complicated and has got me pulling my hair out :P

How about looping thru the top cards (no need for the ArrayList) and building a HashTable<Card, Integer> showing the number of occurrences of each card, ie
for each top card:
if hashtable's keys contain this card, increment its counter
else add a new entry (card, 1)
Then you know exactly how many of each card you've got.
If the count is right, remove all occurrences of that card from the stacks

Yeah that seems like a great idea, a lot more efficient than using an arraylist then iterating through that. I'll give it a go and post back.

Ok thanks for your help. Just to let you know, theres not just two types of cards, there are 52 cards in a deck, so 52 different types. But N number of cards will be compared. At one time, there could be N different cards on top.

It's quite complicated and has got me pulling my hair out :P

I know that there are 52 different types, but if you have more than two types there, than it's false. You only need to check whether the first type appears N-1 times, or the second one. If a third type appears - you automatically return false.

Oh yeah i see what you are saying. You seem to understand the problem better than me, haha. Going to try using a hashtable as it seems simplier. However, do you think its best to put the Card objects in the table or a string representation of the card (ie. 2 Hearts) Which would be best, because only thing different in the card objects is the number and suite value. So maybe it is best to use a String value, what do you think?

I'm an OO purist. I'd put the Card every time. I'd also write an equals(Card otherCard) method in the Card class and not rely on the other code knowing about how the Strings work.

apines has a good point - you can incorporate that by aborting if the hashtable size goes >2.

I'm an OO purist. I'd put the Card every time. I'd also write an equals(Card otherCard) method in the Card class and not rely on the other code knowing about how the Strings work.

apines has a good point - you can incorporate that by aborting if the hashtable size goes >2.

Was in the middle of writing the same thing :) Override the equals method is the best practice here in my opinion.

ok Thanks for your help, so how do i update the integer number in the hashtable?

Also should i use containsKey instead of contains? as I'm checking the key?

ok Thanks for your help, so how do i update the integer number in the hashtable?

The Put method with the same key suppose to do this for you, and return the previous value. So get the current value, increment it, and put it back to the table.

Also should i use containsKey instead of contains? as I'm checking the key?

Seems like the correct choice.

Ok, ive implemented abit of this, tell me what you think so far, am i doing it correctly?

public void checkMatch(){
		for(CardHolder h: holders){
			if(topCards.containsKey(h.topCard())){
				Integer i = (Integer) topCards.get(h.topCard());
				topCards.put(h.topCard(),i++);
			}
			else{		
				topCards.put(h.topCard(), 1);
			}
		}
		if(topCards.size() <= 2){
			for(CardHolder h: holders){
				player.add(h.takeTopCard());
			}
		}
	}

I know the last if statement isn't finished yet, need to check the hashmap for keys with values more than 1, and just remove those from the cardHolders.

public void checkMatch(){
		for(CardHolder h: holders){
			if(topCards.containsKey(h.topCard())){
				Integer i = (Integer) topCards.get(h.topCard());
				topCards.put(h.topCard(),i++);
			}
			else{		
				topCards.put(h.topCard(), 1);
			}
		}
		if(topCards.size() <= 2){
			for(CardHolder h: holders){
				player.add(h.takeTopCard());
			}
		}
	}

I know the last if statement isn't finished yet, need to check the hashmap for keys with values more than 1, and just remove those from the cardHolders.

You can insert the if statement into loop, terminating the loop when the statement is true. Other than that it seems that the usage of the table is correct. I am not certain what you are trying to do inside the if, but I guess this is part of what your program needs to do.

You know - the best way to be certain that you are correct is to build a small test class for it.

Ok, just had a few days break and come back to this and looking at it, I'm not sure how i can get this working. I'm a litle confused by what i wrote. It isn't working, but I'm not sure where, am i even doing it write?

public void checkMatch(){
		for(CardHolder h: holders){
			if(topCards.size() <= 2){ //if 
				for(int n=0; n<topCards.size(); n++){
					int k = (Integer) topCards.get(n); 
					if(k > 1){
						topCards.get(n);
						player.add(h.takeTopCard()); 
						System.out.println("Matcha!");
					}
				}
			}
			else if(topCards.containsKey(h.topCard())){
				Integer i = (Integer) topCards.get(h.topCard());
				topCards.put(h.topCard(),i++);
			}
			else{		
				topCards.put(h.topCard(), 1);
			}
		}
		topCards.clear();
	}

Try and explain the changes from your last code. The previous code that you have posted seemed more clear...

Yeah, did some testing and that last method was silly. Ok here goes:

public void checkMatch(){
		for(CardHolder h: holders){
			
			System.out.println("Checking stack");
		    
			if(topCards.containsKey(h.topCard())){ //else no match add card(if contained update)
				Integer i = (Integer) topCards.get(h.topCard());
				topCards.put(h.topCard(),i++);
				System.out.println("update existing card");
			}
			
			else{									//first time card added, add and put value as 1
				topCards.put(h.topCard(), 1);
				System.out.println("adding new card");
			}
			
		}
		
		if(topCards.size() <= 2){ //matcha has been found if true
			System.out.println("matched");
			for(CardHolder h: holders){
				for(int n=0; n<topCards.size(); n++){
					Integer k = (Integer) topCards.get(h.topCard()); 
					if(k.intValue() > 1){
						topCards.get(n);
						player.add(h.takeTopCard()); 
						System.out.println("Matcha!");
					}
				}
			}
	    }
		System.out.println("clearing hashtable");
		topCards.clear();
	}

Right, as far as testing. I've managed to get it almost working. Heres my output:

Card Holder 1: 10 Clubs Card Holder 2: 2 Diamonds Card Holder 3: 2 Diamonds
Checking stack
adding new card
Checking stack
adding new card
Checking stack
update existing card
matched
clearing hashtable
Card Holder 1: 10 Clubs Card Holder 2: 2 Diamonds Card Holder 3: 2 Diamonds

So it finds that 2 diamonds was found in the hashtable and updated it. Then it was found that a matched state occurreed (2, 2 of diamonds) however, the cards and not being removed (pop'd) from the stack. Not sure why not.

The fact that topCards.size() <= 2 does not necessary means that there was a match - half of the cards can be type1, half type2, meaning there is no match. The expression should be that if topCards.size() > 2 then for certain you don't have a match.

ok, so like that?

public void checkMatch(){
		for(CardHolder h: holders){
			
			System.out.println("Checking stack");
		    
			if(topCards.containsKey(h.topCard())){ //else no match add card(if contained update)
				Integer i = (Integer) topCards.get(h.topCard());
				topCards.put(h.topCard(),i++);
				System.out.println("update existing card");
			}
			
			else{									//first time card added, add and put value as 1
				topCards.put(h.topCard(), 1);
				System.out.println("adding new card");
			}
			
		}
		
		if(topCards.size() > 2){ //matcha has been found if not true
			
	    }
		else{
			System.out.println("matched");
			for(CardHolder h: holders){
				for(int n=0; n<topCards.size(); n++){
					Integer k = (Integer) topCards.get(h.topCard()); 
					if(k.intValue() > 1){
						topCards.get(n);
						player.add(h.takeTopCard()); 
						System.out.println("Matcha!");
					}
				}
			}
		}
		System.out.println("clearing hashtable");
		topCards.clear();
	}

Again - even if the table size is <= 2, it does not necessary means that n-1 of the cards are of the same type - if you have only type1 and type2 cards, when half is type1, the other half is type2 - you will consider it a match when it's not. The condition on the table size should let you break the loop sooner but you cannot rely only on it when considering whether a match has been made.

Ok, so your saying like this, if i understand you correctly that is:

public void checkMatch(){
		for(CardHolder h: holders){
			
			System.out.println("Checking stack");
			if(topCards.size() > 2){
			}
			else if(topCards.containsKey(h.topCard())){ //else no match add card(if contained update)
				Integer i = (Integer) topCards.get(h.topCard());
				topCards.put(h.topCard(),i++);
				System.out.println("update existing card");
			}
			
			else{									//first time card added, add and put value as 1
				topCards.put(h.topCard(), 1);
				System.out.println("adding new card");
			}
			
		}

But how am i supposed to check whether a match has been made?

*EDIT*
would a possible way to return the Integer value from the hashtable, then just check if that value equals N-1? that would find the match correctly wouldn't it?

would a possible way to return the Integer value from the hashtable, then just check if that value equals N-1? that would find the match correctly wouldn't it?

Yes (that's what I had in mind when I first suggested HashTable). You can loop thru the keyset checking the corresponding values, something like:

for (Card c : topcards.keySet)
   if (topcards.get(c) == (n-1)) // card c appears (n-1) times
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.