Randomize deck of cards using constraints

I am trying to create a class for a deck , which contains 52 cards of a regular deck.
I want a randomized deck when I call randomize function on this class.
so far I have following solution, where I have made sure that there will 13 cards of each suit and their colors will be matching the suit.
But I am trying to write a constraint where i can make sure that each suit’s cards are of unique ranks. Can someone solve that please ? OR if you have some other method of solving this please feel free to comment that also.

Here is my code so far:



class card;
 rand enum {HEART=0,SPADE,CLUB,DIAMOND} suit;
 rand bit [3:0] rank;
 rand enum {RED=0,BLACK} color;

 constraint C_rank {
 	rank inside {[1:13]};
 }
endclass

class deck;
	rand card cards[52];

	function new ();
		foreach (cards[i])
			cards[i] = new;
	endfunction

	constraint C_suit {
		cards.sum with (item.suit == card::HEART   ? 1: 0 ) == 13;
		cards.sum with (item.suit == card::SPADE   ? 1: 0 ) == 13;
		cards.sum with (item.suit == card::CLUB    ? 1: 0 ) == 13;
		cards.sum with (item.suit == card::DIAMOND ? 1: 0 ) == 13;
	}
	constraint C_color {
		foreach(cards[i])  {
			( cards[i].suit == card :: HEART || cards[i].suit == card :: DIAMOND) <-> cards[i].color == card::RED;
			( cards[i].suit == card :: SPADE || cards[i].suit == card :: CLUB) <-> cards[i].color == card::BLACK;
		}
	}
endclass

module test;
        deck one_deck;
        initial begin
          one_deck = new;
          assert (one_deck.randomize());
	  foreach(one_deck.cards[i]) 
	     $display("%p",one_deck.cards[i]);
        end
endmodule

In reply to bharat_vg:

It would be far easier to generate a deck of 52 cards in order, then use the built-in cards.shuffle() method.

Much harder would be to make sure each card is unique using a nested foreach loop

constraint C_unique { foreach (cards[ii]) foreach (cards[jj]) 
    ii != jj -> cards[ii].suit != cards[jj].suit && cards[ii].rank != cards[jj].rank; }

I do not think you need to be concerned with the color as that will naturally fall out with the suit constraint.

1 Like

Hi,

I have tried both you and dave’s code, both of them not work correctly.
Your code’s rank will not be unique.
I updated the constraint based on dave’s suggestion and it looks good.



class card;
 rand enum {HEART=0,SPADE,CLUB,DIAMOND} suit;
 rand bit [3:0] rank;
 rand enum {RED=0,BLACK} color;
 
 constraint C_rank {
 	rank inside {[1:13]};
 }
endclass
 
class deck;
	rand card cards[52];
 
	function new ();
		foreach (cards[i])
			cards[i] = new;
	endfunction
 
 
  constraint D {
    foreach(cards[i])
      foreach(cards[j]) {
        if(cards[i].suit == cards[j].suit && i != j)
          cards[i].rank != cards[j].rank;
        if(cards[i].rank == cards[j].rank && i != j)
          cards[i].suit != cards[j].suit;
      }
  
  }
  
  	constraint C_color {
		foreach(cards[i])  {
			( cards[i].suit == card :: HEART || cards[i].suit == card :: DIAMOND) <-> cards[i].color == card::RED;
			( cards[i].suit == card :: SPADE || cards[i].suit == card :: CLUB) <-> cards[i].color == card::BLACK;
		}
	}
  
endclass
 
module test;
        deck one_deck;
        initial begin
          one_deck = new;
          assert (one_deck.randomize());
	  foreach(one_deck.cards[i]) 
	     $display("%p",one_deck.cards[i]);
        end
endmodule


In reply to dave_59:

In reply to bharat_vg:
It would be far easier to generate a deck of 52 cards in order, then use the built-in cards.shuffle() method.
Much harder would be to make sure each card is unique using a nested foreach loop

constraint C_unique { foreach (cards[ii]) foreach (cards[jj]) 
ii != jj -> cards[ii].suit != cards[jj].suit && cards[ii].rank != cards[jj].rank; }

I do not think you need to be concerned with the color as that will naturally fall out with the suit constraint.

Is there a way to use the built in “unique” constraints after defining the card characteristics to simplify and avoid using a foreach loop? If we have a 16bit variable (numeric) using unique after defining the size would ensure that the values for each element are unique (followed by shuffle if we generate in order).

Just trying to think if we there is a way to simplify the problem here using that thought process.

In reply to andrewZ:

Please help with syntax understanding

  1. How is using scope resolution operator valid here? seems correct as it’s compiling but never came across this interesting usage in any of the reading on the internet. For LHS we just need the full hierarchical path like cards[i].suit or cards[i].color and on the RHS we can directly use the possible enum strings?

  2. what does this operator mean ↔
    Based on the context I could infer that if a card type is heart or diamond it’s color is always RED but haven’t seen this as well. I have came across implication operator → and solve a before b type of usage for constraint solving but not this one

constraint C_color {
foreach(cards[i]) {
( cards[i].suit == card :: HEART || cards[i].suit == card :: DIAMOND) ↔ cards[i].color == card::RED;
( cards[i].suit == card :: SPADE || cards[i].suit == card :: CLUB) ↔ cards[i].color == card::BLACK;
}
}

Please throw in any useful links if I need to do any basic reading as the questions are more about the syntax. Thanks to the forum members in advance for clarifying.

In reply to hsam:

Yes, you could easily represent a deck of cards with an array of integral values, and then use the unique constraint. But that would change the original posted question of having a class object represent a single card.

In reply to dave_59:

Thanks Dave. It would be great if you can also clarify my question on the syntax. I already posted it in the same thread. Thanks for your help in advance:)