Randomize deck of cards using constraints

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.