I was playing the game Set online, and thought it would be a good exercise to write an F# script to find all of the sets for me.
The rules of set are as follows: A SET is 3 cards for which each feature is either common across all 3 cards or is different on each card. The object is to find all the SETs among the cards.
I started learning F# four days ago, so what I'm looking for are obvious/easy/"no duh" improvements. I've started at a low bar of just writing a function to compare a group of three cards, and tell you if those three cards form a set. You can see my first attempt below. It feels a bit clunky, like I'm not really making use of all that F# has to offer.
// Create a record type to represent each card
type Card =
{ Color: string
Shape: string
Pattern: string
Number: int
}
// Create some functions for comparing elements of a collection
let allEqual l = l |> Seq.pairwise |> Seq.forall (fun (x, y) -> x = y)
let allDifferent l = (l |> Seq.distinct |> Seq.length) = (Seq.length l)
// Combine them
let isSet l = (allEqual l) || (allDifferent l)
// The meat of this script
let compare card1 card2 card3 =
// Put the cards together for easy iteration
let cardList = [card1; card2; card3]
// Check each field of the record to see if it makes a set
let colorSet = cardList |> List.map (fun c -> c.Color ) |> isSet
let shapeSet = cardList |> List.map (fun c -> c.Shape ) |> isSet
let patternSet = cardList |> List.map (fun c -> c.Pattern) |> isSet
let numsSet = cardList |> List.map (fun c -> c.Number ) |> isSet
// Check that they all make a set
colorSet && shapeSet && patternSet && numsSet
// Test the functions out
let c1 = {Color = "blue"; Shape = "oval"; Pattern = "stripes"; Number = 3}
let c2 = {Color = "red"; Shape = "diamond"; Pattern = "solid"; Number = 2}
let c3 = {Color = "green"; Shape = "squiggle"; Pattern = "empty"; Number = 2}
let areCardsSet = compare c1 c2 c3
printfn "The cards c1, c2, and c3 are a set? %b" areCardsSet