Skip to content

Instantly share code, notes, and snippets.

@kolektiv
Created December 29, 2014 17:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kolektiv/9a1e16b313d6c8b9ce84 to your computer and use it in GitHub Desktop.
Save kolektiv/9a1e16b313d6c8b9ce84 to your computer and use it in GitHub Desktop.
Snowflake Generation
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