Last week I wrote about my strategy for creating the fitness function data, and now, I have really written the code! So, here goes. We create a deck of cards and select 13 random ones.
//make a list with (all) 52 cards let theWholeDeck = cartesian allCardSuits allRanks
//get one random hand and the rest of the deck let (hand1, remainder1) = randomHandplusRemainder theWholeDeck
Randomness needed
For the randomHandplusRemainder function, I needed some code to randomly select 13 cards out of the 52. So, as you do, I googled and landed on StackOverflow, where I found this code:
let takeRandomFrom xs n = let insertAt n xs x = Seq.concat [Seq.take n xs; seq [x]; Seq.skip n xs] let randomInsert xs = insertAt (rnd.Next( (Seq.length xs) + 1 )) xs xs |> Seq.fold randomInsert Seq.empty |> Seq.take n
In retrospect, should have been more sceptical as the answer had no upvotes 🙂 The code works, but it does not perform, at all* When I found out, I myself wrote a better version. While writing this I am thinking it would be nice to post this on SO too. Will do that later.
let rec takeRandomFrom (xs: 'a List) n = //modified from generate random hands, should be moved to a general helper(TODO) match xs with | [] -> [] | xs -> match n with | 0 -> [] | n -> let randomIndex = rnd.Next(xs.Length) let randomItem = xs.[randomIndex] let rest1 = takeFromList randomIndex xs let rest2 = skipFromList (randomIndex+1) xs randomItem :: takeRandomFrom (List.append rest1 rest2) (n-1)
Way quicker!
* which I only found out at a later stage of the project thought!
Great series, thanks for posting these articles!
Minor point: I’m not sure if assuming that your partner has zero points will lead to a sensible bid for your hand. Many (most?) reasonable, minimum opening hands, opposite a partner who has no points, will fail to make any contract. I suspect that it is better to assume that the remaining points are distributed randomly among the other three players.