Created
December 29, 2014 17:35
-
-
Save kolektiv/9a1e16b313d6c8b9ce84 to your computer and use it in GitHub Desktop.
Snowflake Generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Cells = | |
// Types | |
type LifeSpec = | |
| LifeSpec of GenerationSpec list | |
and GenerationSpec = | |
| GenerationSpec of strength: int * liveness: (int -> bool) | |
type Life = | |
| Life of generations: Generation list | |
and Generation = | |
| Generation of strength: int * cells: Set<Coordinate> | |
and Coordinate = | |
| Coordinate of x: int * y: int | |
// Constructors | |
let genZero = | |
Generation (0, Set.ofList [ Coordinate (0,0) ]) | |
let lifeZero = | |
Life ([ genZero ]) | |
// Liveness Functions | |
let hex1 n = | |
n = 1 | |
let hex134 n= | |
n = 1 || n = 3 || n = 4 | |
let hex135 n= | |
n = 1 || n = 3 || n = 5 | |
let hex145 n = | |
n = 1 || n = 4 || n = 5 | |
let hex1456 n = | |
n = 1 || n = 4 || n = 5 || n = 6 | |
// Neighbourhoods | |
let neighbourhood (Coordinate (x, y)) = | |
[ Coordinate (x - 1, y) | |
Coordinate (x + 1, y) | |
Coordinate (x, y - 1) | |
Coordinate (x, y + 1) | |
Coordinate (x + 1, y - 1) | |
Coordinate (x - 1, y + 1) ] | |
let liveNeighbours cells (coordinate: Coordinate) = | |
coordinate | |
|> neighbourhood | |
|> List.filter (fun n -> Set.contains n cells) | |
|> List.length | |
// Generations | |
let nextGeneration (Generation (_, cells)) s l = | |
cells | |
|> Set.toSeq | |
|> Seq.map (neighbourhood >> Seq.ofList) | |
|> Seq.concat | |
|> Seq.distinct | |
|> Seq.filter (fun c -> l (liveNeighbours cells c)) | |
|> Set.ofSeq | |
|> fun c -> Generation (s, c) | |
let rec gen lifeSpec life = | |
match lifeSpec, life with | |
| LifeSpec (x), Life ([]) -> gen (LifeSpec (x)) (lifeZero) | |
| LifeSpec ([]), y -> y | |
| LifeSpec (GenerationSpec (s, l) :: xs), Life (y :: ys) -> | |
gen (LifeSpec (xs)) (Life (nextGeneration y s l :: y :: ys)) | |
module Draw = | |
open System | |
open System.Drawing | |
open System.Drawing.Imaging | |
open Cells | |
// Types | |
type Canvas = | |
{ Graphics: Graphics | |
Sizing: CanvasSizing } | |
and CanvasSizing = | |
{ Scale: int | |
Size: int } | |
// Drawing | |
let drawCell canvas b x y = | |
let p = 4 * canvas.Sizing.Scale | |
let x = int (Math.Floor (Math.Sqrt (3.) * (float (x + (y/2))))) | |
let y = int (Math.Floor (1.5 * (float y))) | |
let x' = (canvas.Sizing.Size / 2) + x * canvas.Sizing.Scale | |
let y' = (canvas.Sizing.Size / 2) + y * canvas.Sizing.Scale | |
canvas.Graphics.FillEllipse (b, x', y', p, p) | |
let drawGeneration canvas b cells = | |
cells | |
|> Set.iter (fun (Coordinate (x, y)) -> | |
drawCell canvas b x y) | |
let drawLife canvas generations = | |
canvas.Graphics.Clear (Color.White) | |
generations | |
|> List.iteri (fun i (Generation (s, cells)) -> | |
use b = new SolidBrush (Color.FromArgb (255, s, s, s)) | |
drawGeneration canvas b cells) | |
// Setup/Write | |
let write (Life generations) = | |
let size = 1000 | |
let xMax = | |
generations | |
|> List.map (fun (Generation (_, cells)) -> Set.toList cells) | |
|> List.concat | |
|> List.maxBy (fun (Coordinate (x, _)) -> Math.Abs x) | |
|> fun (Coordinate (x, _)) -> Math.Abs x | |
let yMax = | |
generations | |
|> List.map (fun (Generation (_, cells)) -> Set.toList cells) | |
|> List.concat | |
|> List.maxBy (fun (Coordinate (_, y)) -> Math.Abs y) | |
|> fun (Coordinate (_, y)) -> Math.Abs y | |
let scale = int (0.3 * (floor (max (float size/float xMax) | |
(float size/float yMax)))) | |
let sizing = | |
{ Scale = scale | |
Size = size } | |
let bitmap = new Bitmap (sizing.Size, sizing.Size) | |
let graphics = Graphics.FromImage (bitmap) | |
let canvas = | |
{ Graphics = graphics | |
Sizing = sizing } | |
drawLife canvas generations | |
bitmap.Save (@"C:\Users\andrew\Documents\Snowflakes\snowflake.bmp", ImageFormat.Bmp) | |
module Git = | |
open LibGit2Sharp | |
// Types | |
type WeeklySummary = | |
{ Week: int | |
Commits: int | |
Committers: int } | |
// Summary | |
let commits path = | |
let repo = new Repository (path) | |
repo.Commits | |
|> List.ofSeq | |
|> List.rev | |
let summarize commits = | |
let first = | |
commits | |
|> List.head | |
let grouped = | |
commits | |
|> Seq.groupBy (fun (c: Commit) -> | |
let date = c.Author.When.Date | |
let year = date.Year - first.Author.When.Year | |
let week = date.DayOfYear / 7 | |
let overallWeek = (year * 52) + week | |
overallWeek) | |
|> Seq.toList | |
let indexed = | |
grouped | |
|> List.map (fun (d,c) -> d - (grouped |> List.head |> fst), Seq.toList c) | |
let max = | |
indexed | |
|> List.rev | |
|> List.head | |
|> fst | |
let mapped = | |
indexed | |
|> Map.ofList | |
let summaries = | |
List.init max (fun i -> | |
match Map.tryFind i mapped with | |
| Some commits -> commits | |
| _ -> []) | |
|> List.mapi (fun i commits -> | |
let commits' = List.length commits | |
let committers = (Seq.groupBy (fun (c: LibGit2Sharp.Commit) -> c.Author.Name) >> Seq.length) commits | |
{ Week = i | |
Commits = commits' | |
Committers = committers }) | |
summaries | |
module Program = | |
open System | |
open System.Diagnostics | |
open Cells | |
open Draw | |
open Git | |
[<EntryPoint>] | |
let main _ = | |
let watch = Stopwatch.StartNew () | |
let liveness = | |
[ hex1 | |
hex145 | |
hex135 | |
hex134 | |
hex1456 ] | |
let summaries = | |
commits @"Z:\Code\fsharp\FSharp.Data" | |
|> summarize | |
let maxCommits = | |
summaries | |
|> List.maxBy (fun s -> s.Commits) | |
|> fun s -> s.Commits | |
let maxCommitters = | |
summaries | |
|> List.maxBy (fun s -> s.Committers) | |
|> fun s -> s.Committers | |
let strengthStep = | |
255. / float maxCommits | |
let liveStep = | |
4. / float maxCommitters | |
let lifeSpec = | |
// LifeSpec (List.init 250 (fun i -> GenerationSpec (i, hex1456))) | |
summaries | |
|> List.map (fun s -> | |
let strength = int (255. - (strengthStep * float s.Commits)) | |
let liveness = liveness.[int (floor ((float s.Committers * liveStep)))] | |
GenerationSpec (strength, liveness)) | |
|> LifeSpec | |
let life = | |
gen lifeSpec (Life []) | |
write life | |
watch.Stop () | |
watch.Elapsed.TotalSeconds |> printfn "%f seconds" | |
Console.ReadLine () |> ignore | |
0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment