# Performance versus elegant code, a never ending trade off [Desiderius part #19]

Generating with constraints

So, the next step, actually generating things. As I wrote last week, my strategy first was to generate entirely random hands. But! I realized that if we do that, we make some assumptions about our partner, because they will have an average hand. I then wanted to generate a random hand for my partner given a certain constraint, in this case that our partner has 0 points. This way, we get the best bid for just our hand. Also, in a later stage I will want to generate hands with other constraints, for the next step of our bidding system.

My first solution was to use the fits function I already wrote. Awesome, code reuse to the max, right? The fits function, if you don’t remember, checks if a certain hand complies to a condition:

```let rec fits (cards : Hand) (c : Condition) : bool =
match c with
| NCards(min, max, s) -> cardsofSuitinHand cards s >= min && cardsofSuitinHand cards s <= max
| NPoints(min, max) -> pointsinHand cards >= min && pointsinHand cards <= max
| And(p, q) -> fits cards p && fits cards q
| Or(p, q) -> fits cards p || fits cards q
```

So, you give fits a hand and a condition, and it returns a boolean whether the hand satisfies the condition. We can use that, by just generating a random hand until it matches:

```//this is an example of a hand constraint
let constreent = fun x -> Desi.fits (Desi.Hand(x)) (Desi.points 0 12) *```

* if you are wondering why my variable is called ‘constreent’ that is because constraint is reserved for future use.

We can now just generate random hands until we meet the condition:

```let randomHandplusRemainderwithConstraint cardSet (constreent: Desi.Card List -> bool)  =
let mutable continueLooping = true
let oneHand = oneRandomHand cardSet
while continueLooping do
let oneHand = oneRandomHand cardSet
// Generate a random hand
if constreent oneHand then
continueLooping
(oneHand , except cardSet oneHand)```

But again, that is very very slow… 🙁 Since in the first situation, I just needed hands with no points, I could solve it with a constraint on individual cards, like so:

```let randomHandplusRemainderwithCardConstraint cardSet (constreent: Desi.Card -> bool) =
//get all the cards that fit the card constraint:
let fitting = List.filter (constreent) cardSet

//take 13 random from those:
let oneHand = oneRandomHand fitting
(oneHand , except cardSet oneHand)```

Calling it with a constreent on cards:

```let constreent = fun x -> Desi.cardtoPoint x <= 0
let (hand3, remainder) = randomHandplusRemainderwithCardConstraint remainder1 constreent```

Finally, I made a relatively elegant and performant solution. The idea is to use conditions instead of functions on hands, and recursively break them down:

```let rec randomHandwithCondition cardSet stillToTake (c: Desi.Condition)  =
match stillToTake with
| 0 -> []
| n -> let oneCard = oneRandomCard cardSet
oneCard :: (randomHandwithCondition cardSet (n-1) (updateCondition c oneCard ))

```

The updateCondition function takes a card and a condition and makes it smaller

```    let updateCondition condition card =
match condition with
| Desi.NPoints(min,max)    -> let x = Desi.cardtoPoint card
Desi.NPoints(min-x,max-x)
| Desi.NCards(min, max, s) -> if helper.getSuit card = s then Desi.NCards(min-1, max-1, s) else Desi.NCards(min, max, s)
```

This post was visited 96 times.