Skip to content

Instantly share code, notes, and snippets.

@jrwdexter
Last active March 1, 2016 00:06
Show Gist options
  • Save jrwdexter/c525650b35561ad52294 to your computer and use it in GitHub Desktop.
Save jrwdexter/c525650b35561ad52294 to your computer and use it in GitHub Desktop.
Nerdery .NET Challenge #43 (In F#)
(**
# Challenge #43 solution - Lights out
*)
(**
## Helper methods
The first helper method we have is an active pattern to determine if a string is a valid bit string.
*)
let (|Bits|_|) (str:string) =
if str |> isNull || (str |> Seq.exists (fun c -> c <> '0' && c <> '1'))
then None
else str.Trim('0').ToCharArray() |> Seq.map (fun c -> if c = '1' then 1 else 0) |> Some
(**
Next, determine if it is solvable.
*)
let isSolvable str =
match str with
| Bits(bits) ->
// Lets have an internal helper function that aggregates a char for us
let evaluateChar aggregate bit =
let toAdd =
match (bit,aggregate % 3) with
| (1,_) -> 1
| (_,0) -> 0
| _ -> -1
aggregate + toAdd
// Run that function over the sequence
let algoSum = bits |> Seq.fold evaluateChar 0
// Return whether or not it is solvable (mod 3 == 0)
algoSum % 3 = 0
| _ -> false
(**
## Solution methods
*)
let doSolveStep (str:string) =
let trimmed = str.Trim('0')
let toString (charArray:char seq) = charArray |> Seq.toList |> System.String.Concat
if trimmed.Length = 0 then None
else
let offset = str.IndexOf(trimmed)
let beginZeros = str.ToCharArray() |> Seq.take offset |> toString
let endZeros = str.ToCharArray() |> Seq.skip (offset + trimmed.Length) |> toString
let swapChars = Seq.map (fun c -> if c = '1' then '0' else '1')
let result =
(
offset + trimmed.Length - 1,
sprintf "%s%s%s%s"
beginZeros
(trimmed.ToCharArray() |> Seq.take (trimmed.Length - 3) |> toString)
(trimmed.ToCharArray() |> Seq.skip (trimmed.Length - 3) |> swapChars |> toString)
endZeros
)
printfn "Step: %s" (snd result)
result |> Some
// Let's do the solving thing if it is solvable
let solve str =
if isSolvable str
then
printfn "Solved! %A" (Seq.unfold doSolveStep str |> Seq.toArray)
else
printfn "Unsolvable"
let byteArrayToString (bytes:byte seq) =
bytes |> Seq.map (fun b ->
seq {
for i = 0.0 to 7.0 do
if b &&& byte(2.0 ** i) <> byte(0)
then yield '1'
else yield '0'
} |> Seq.rev |> System.String.Concat) |> Seq.reduce (+)
[byte(1); byte(172); byte(107)] |> byteArrayToString |> solve // Same as the below
// Turns into: solve "11010110001101011"
(**
Prints
11010110001101100
11010110001110000
11010110000000000
11011000000000000
11100000000000000
00000000000000000
Solved! [|16; 14; 12; 6; 4; 2|]
val solve : str:string -> unit
val it : unit = ()
*)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment