#if INTERACTIVE #r "System.Drawing" #endif module LatinSquaresDemo = module LatinSquares = open System // Generate a Latin Square, populating with the specified values. To generate a 'reduced' Latin Square // send in the values sorted; otherwise randomise the values before calling. let inline LatinSquare(values : ^a[]) = let n = values |> Array.length let r = new Random() let scramble = Array.sortBy (fun _ -> r.Next(n)) let hasConflicts (a : ^a option[,]) r = let (=?) (m : ^a option) (n : ^a option) = (n.IsNone && m.IsNone) || (n.IsSome && m.IsSome && (n.Value = m.Value)) let mutable conflicts = false for c in 0..n-1 do let bottom = a.[r,c] for r' in 0..r-1 do if bottom =? a.[r',c] then conflicts <- true conflicts let arr = Array2D.init n n (fun _ _ -> None) values |> Array.iteri (fun c x -> arr.[0, c] <- Some(x)) for r in 1..n-1 do let mutable conflicts = true while conflicts do values |> scramble |> Array.iteri (fun c x -> arr.[r,c] <- Some(x)) conflicts <- hasConflicts arr r arr |> Array2D.map (fun e -> e.Value) module Demo = open System open System.Drawing open LatinSquares // [[1; 2; 3] // [2; 3; 1] // [3; 1; 2]] let ints3x3 = LatinSquare([|1..3|]) // [[1; 2; 3; 4; 5; 6; 7] // [5; 4; 2; 1; 6; 7; 3] // [4; 6; 5; 7; 1; 3; 2] // [7; 1; 4; 3; 2; 5; 6] // [3; 7; 1; 6; 4; 2; 5] // [6; 5; 7; 2; 3; 1; 4] // [2; 3; 6; 5; 7; 4; 1]] let ints7x7 = LatinSquare([|1..7|]) // [[1.5; 2.0; 2.5; 3.0; 3.5; 4.0; 4.5] // [3.5; 3.0; 2.0; 1.5; 4.0; 4.5; 2.5] // [3.0; 4.0; 3.5; 4.5; 1.5; 2.5; 2.0] // [4.5; 1.5; 3.0; 2.5; 2.0; 3.5; 4.0] // [2.5; 4.5; 1.5; 4.0; 3.0; 2.0; 3.5] // [4.0; 3.5; 4.5; 2.0; 2.5; 1.5; 3.0] // [2.0; 2.5; 4.0; 3.5; 4.5; 3.0; 1.5]] let floats7x7 = LatinSquare([|1.5..0.5..4.5|]) //[[02/01/2013 00:00:00; 03/01/2013 00:00:00; 04/01/2013 00:00:00; // 05/01/2013 00:00:00; 06/01/2013 00:00:00; 07/01/2013 00:00:00; // 08/01/2013 00:00:00] // [06/01/2013 00:00:00; 05/01/2013 00:00:00; 03/01/2013 00:00:00; // 02/01/2013 00:00:00; 07/01/2013 00:00:00; 08/01/2013 00:00:00; // 04/01/2013 00:00:00] // [05/01/2013 00:00:00; 07/01/2013 00:00:00; 06/01/2013 00:00:00; // 08/01/2013 00:00:00; 02/01/2013 00:00:00; 04/01/2013 00:00:00; // 03/01/2013 00:00:00] // [08/01/2013 00:00:00; 02/01/2013 00:00:00; 05/01/2013 00:00:00; // 04/01/2013 00:00:00; 03/01/2013 00:00:00; 06/01/2013 00:00:00; // 07/01/2013 00:00:00] // [04/01/2013 00:00:00; 08/01/2013 00:00:00; 02/01/2013 00:00:00; // 07/01/2013 00:00:00; 05/01/2013 00:00:00; 03/01/2013 00:00:00; // 06/01/2013 00:00:00] // [07/01/2013 00:00:00; 06/01/2013 00:00:00; 08/01/2013 00:00:00; // 03/01/2013 00:00:00; 04/01/2013 00:00:00; 02/01/2013 00:00:00; // 05/01/2013 00:00:00] // [03/01/2013 00:00:00; 04/01/2013 00:00:00; 07/01/2013 00:00:00; // 06/01/2013 00:00:00; 08/01/2013 00:00:00; 05/01/2013 00:00:00; // 02/01/2013 00:00:00]] let dates7x7 = LatinSquare([|1..7|] |> Array.map (fun d -> DateTime(2013, 1, 1).AddDays(d |> float))) // [["Harder"; "Better"; "Faster"; "Stronger"] // ["Stronger"; "Harder"; "Better"; "Faster"] // ["Faster"; "Stronger"; "Harder"; "Better"] // ["Better"; "Faster"; "Stronger"; "Harder"]] let daftPunk = LatinSquare([|"Harder"; "Better"; "Faster"; "Stronger"|]) // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
// let stainedGlassHTML = let colors = [| Color.Purple; Color.LightBlue; Color.DarkGreen; Color.Red; Color.Brown; Color.Yellow; Color.DarkBlue |] let n = colors |> Array.length let sb = new System.Text.StringBuilder() let (+~) line = sb.AppendLine(line) |> ignore "" |> (+~) " " |> (+~) LatinSquare(colors) |> Array2D.iteri (fun _ c panel -> if c = 0 then " " |> (+~) sprintf " " panel.Name |> (+~) if c = n-1 then " " |> (+~)) "
" |> (+~) "" |> (+~) sb.ToString()