Last active
March 1, 2016 00:06
-
-
Save jrwdexter/c525650b35561ad52294 to your computer and use it in GitHub Desktop.
Nerdery .NET Challenge #43 (In F#)
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
(** | |
# 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