Day 3 si 4, am renuntat la orice tentativa de a avea rezolvari eficiente. Din nou, in F#:
Day 3-1 Zero si Unu
Day 3 a introdus array-uri 2D. Din fericire, F# are cateva facilitati pentru array2D.
Nu am stiut mai niciodata operatiuni cu biti, asa ca fac niste lucruri dubioase pentru conversii.
let bitArrayToInt bitArray =
let str =
bitArray
|> Array.map (fun i -> i.ToString())
|> String.Concat
System.Convert.ToInt32(str, 2)
let inputs =
Utils.readFileAsLineSeq "day3inputs.txt"
|> Seq.map (fun s ->
s
|> Array.ofSeq
|> Array.map (fun c -> int (Int32.Parse(c.ToString())))
)
let arr2D = array2D inputs
let (gammaRateBits, epsilonRateBits) =
//pentru fiecare coloana din matrice(?) fac un fold si tin evidenta celui mai comun / mai putin comun termen
[|0..(Array2D.length2 arr2D - 1)|]
|> Array.fold (fun (mostCommonArr: int[], leastCommonArr: int[]) (columnIndex: int) ->
//ca sa iau o coloana dintr-o matice, pot sa folosesc .[*, index] unde * inseamna "tot" si val e index-ul coloanei
let column = arr2D.[*, columnIndex]
let count1 = Array.sum column
let count0 = (Array.length column) - count1
let (mostCommon, leastCommon) =
if count1 > count0
then (1, 0)
else (0, 1)
Array.append mostCommonArr [| mostCommon |],
Array.append leastCommonArr [| leastCommon |]
) ([||], [||])
let gammaRate = bitArrayToInt gammaRateBits
let epsilonRate = bitArrayToInt epsilonRateBits
let result = gammaRate * epsilonRate
printfn "%i" result
Day 3-2 Unu si Zero
Recursivitate, cine ar fi crezut ca e ceva util?
let bitArrayToInt bitArray =
let str =
bitArray
|> Array.map (fun i -> i.ToString())
|> String.Concat
System.Convert.ToInt32(str, 2)
let inputs =
Utils.readFileAsLineSeq "day3inputs.txt"
|> Seq.map (fun s ->
s
|> Array.ofSeq
|> Array.map (fun c -> int (Int32.Parse(c.ToString())))
)
|> Array.ofSeq
let getMostCommonInArr arr =
let count1 = Array.sum arr
let count0 = (Array.length arr) - count1
if count1 >= count0
then 1
else 0
let getLeastCommonInArr arr =
let count1 = Array.sum arr
let count0 = (Array.length arr) - count1
if count0 <= count1
then 0
else 1
//Am nevoie sa lucrez pe inputs care se restrang
//In practica, ar fi mers cu un fold, dar prima solutie ce mi-a venit in cap a fost sa folosesc explicit recursivitate
let matching (inputs: int[][]) (matchingValueFn: int[] -> int) maxColumn =
let rec matchingRec (inputs: int[][]) (column: int) =
let arr2D = array2D inputs
let arr = arr2D.[*, column]
let matchingValue = matchingValueFn arr
let filteredInputs =
inputs
|> Array.filter (fun row -> row.[column] = matchingValue)
if (Array.length filteredInputs = 1)
then filteredInputs.[0]
else
if column = maxColumn
then filteredInputs.[0]
else
matchingRec filteredInputs (column + 1)
matchingRec inputs 0
let oxygenBits = matching inputs getMostCommonInArr (Array.length inputs.[0])
let co2Bits = matching inputs getLeastCommonInArr (Array.length inputs.[0])
let oxygen = bitArrayToInt oxygenBits
let co2 = bitArrayToInt co2Bits
let result = oxygen * co2
printfn "%i" result
Day 4-1 BINGO
TLDR: Folds
module Day41 =
open System
type BoardId = int
type Board = {
Id: BoardId
Numbers: int[][]
}
type BoardLine = BoardId * int
let convertToBoard id (lines: string[]) : Board =
let lines = Array.tail lines
let numbers =
lines
|> Array.map (fun line ->
line
|> Seq.chunkBySize 3
|> Seq.map (fun numberString ->
let numberString =
(numberString |> Seq.map string)
|> (String.concat "")
Int32.Parse((string numberString)
))
|> Array.ofSeq
)
printfn "%A" (array2D numbers)
{
Id = id
Numbers = numbers
}
let inputs = Utils.readFileAsLineSeq("day4inputs.txt")
let numbers : seq<int> =
inputs
|> Seq.head
|> (fun s -> s.Split(","))
|> Seq.map (fun numberString ->
let numberString =
(numberString |> Seq.map string)
|> (String.concat "")
Int32.Parse((string numberString)
))
let boards: seq<Board> =
inputs
|> Seq.tail
|> Seq.chunkBySize 6
|> Seq.mapi convertToBoard
//Map ca sa stiu pe ce linii din fiecare Board apare un numar
//Ex pt numarul "33" stiu ca apare pe Board 1 linia 7 (linia sau coloana sunt acelasi lucru) si pe Board 3 linia 1
let numbersMap : Map<int, seq<BoardLine>> =
boards
|> Seq.collect (fun board ->
let numbers2D = array2D board.Numbers
[
1, numbers2D.[*,0]
2, numbers2D.[*,1]
3, numbers2D.[*,2]
4, numbers2D.[*,3]
5, numbers2D.[*,4]
6, numbers2D.[0,*]
7, numbers2D.[1,*]
8, numbers2D.[2,*]
9, numbers2D.[3,*]
10, numbers2D.[4,*]
]
|> Seq.collect( fun (lineNumber, numbers) ->
numbers
|> Seq.map (fun number ->
number, (board.Id, lineNumber)
)
)
)
|> Seq.fold (fun map (number, boardLine) ->
let boardLines =
(map |> Map.tryFind number |> Option.defaultValue Seq.empty)
|> Seq.append [boardLine]
Map.add number boardLines map
) Map.empty
//Am fost foarte tentat sa folosesc valori mutabile, dar m-am abtinut
//Fac un fold in fold in care tin evidenta a cate numere de pe o linie au fost extrase
//Folosesc un map de forma Map<BoardLine, int> unde int e numarul de numere extrase de pe acel BoardLine
//Cand sunt extrase 5 numere pe un BoardLine, am un board castigator si nu mai incerc sa gasesc alte boarduri castigatoare
//De unde stiu pe ce BoardLine a aterizat un numar? Folosesc numbersMap de mai sus.
let (maybeBoardLineAndNumber, _) =
numbers
|> Seq.fold (fun (maybeBoardLineAndNumber, hitsMap) number ->
if Option.isSome maybeBoardLineAndNumber
then (maybeBoardLineAndNumber, hitsMap)
else
let hits = numbersMap |> Map.tryFind number |> Option.defaultValue Seq.empty
let (maybeBoardLineAndNumber, hitsMap) =
hits
|> Seq.fold (fun (maybeBoardLineAndNumber, hitsMap) boardLine ->
if Option.isSome maybeBoardLineAndNumber
then (maybeBoardLineAndNumber, hitsMap)
else
let hitsForBoardline = hitsMap |> Map.tryFind boardLine |> Option.defaultValue 0
if hitsForBoardline = 4
then (Some (boardLine, number)), Map.add boardLine 5 hitsMap
else None, Map.add boardLine (hitsForBoardline + 1) hitsMap
) (maybeBoardLineAndNumber, hitsMap)
(maybeBoardLineAndNumber, hitsMap)
) (None, Map.empty)
let matchingBoard, lastExtractedNumber =
match maybeBoardLineAndNumber with
| Some ((boardId, line), lastExtractedNumber) ->
boards |> Seq.find (fun b -> b.Id = boardId),
lastExtractedNumber
| None -> failwithf "No winning board"
//Presupun ca numerele extrase sunt unice
let numbersExtracted =
numbers
|> Seq.takeWhile (fun n -> n <> lastExtractedNumber)
|> Seq.append [lastExtractedNumber]
//De pe boardul castigator am nevoie sa aflu ce numere NU au fost extrase
//Din toate numerele de pe board, le filtrez pe cele care se regasesc in numerele extrase
let unmarkedNumbersSum =
matchingBoard.Numbers
|> Array.concat
|> Array.filter (fun n -> not (Seq.contains n numbersExtracted ))
|> Array.sum
let result = (unmarkedNumbersSum * lastExtractedNumber)
Day 4-2 BINGO dar vrei sa pierzi si sa nu bata la ochi
TLDR: Folds, again
module Day42 =
open System
type BoardId = int
type Board = {
Id: BoardId
Numbers: int[][]
}
type BoardLine = BoardId * int
let convertToBoard id (lines: string[]) =
let lines = Array.tail lines
let numbers =
lines
|> Array.map (fun line ->
line
|> Seq.chunkBySize 3
|> Seq.map (fun numberString ->
let numberString =
(numberString |> Seq.map string)
|> (String.concat "")
Int32.Parse((string numberString)
))
|> Array.ofSeq
)
{
Id = id
Numbers = numbers
}
let inputs = Utils.readFileAsLineSeq("day4inputs.txt")
let numbers =
inputs
|> Seq.head
|> (fun s -> s.Split(","))
|> Seq.map (fun numberString ->
let numberString =
(numberString |> Seq.map string)
|> (String.concat "")
Int32.Parse((string numberString)
))
let boards =
inputs
|> Seq.tail
|> Seq.chunkBySize 6
|> Seq.mapi convertToBoard
//Map ca sa stiu pe ce linii din fiecare Board apare un numar
//Ex pt numarul "33" stiu ca apare pe Board 1 linia 7 (linia sau coloana sunt acelasi lucru) si pe Board 3 linia 1
let numbersMap : Map<int, seq<BoardLine>> =
boards
|> Seq.collect (fun board ->
let numbers2D = array2D board.Numbers
[
1, numbers2D.[*,0]
2, numbers2D.[*,1]
3, numbers2D.[*,2]
4, numbers2D.[*,3]
5, numbers2D.[*,4]
6, numbers2D.[0,*]
7, numbers2D.[1,*]
8, numbers2D.[2,*]
9, numbers2D.[3,*]
10, numbers2D.[4,*]
]
|> Seq.collect( fun (lineNumber, numbers) ->
numbers
|> Seq.map (fun number ->
number, (board.Id, lineNumber)
)
)
)
|> Seq.fold (fun map (number, boardLine) ->
let boardLines =
(map |> Map.tryFind number |> Option.defaultValue Seq.empty)
|> Seq.append [boardLine]
Map.add number boardLines map
) Map.empty
//Am fost foarte tentat sa folosesc valori mutabile, dar m-am abtinut, din nou
//Fac un fold in fold in care tin evidenta a cate numere de pe o linie au fost extrase
//Folosesc un map de forma Map<BoardLine, int> unde int e numarul de numere extrase de pe acel BoardLine
//Cand sunt extrase 5 numere pe un BoardLine, am un board castigator
//DAR spre deosebire de Day 4-1, aici
//De unde stiu pe ce BoardLine a aterizat un numar? Folosesc numbersMap de mai sus.
let (maybeBoardLineAndNumber, _, _) =
numbers
|> Seq.fold (fun (maybeBoardLineAndNumber, hitsMap, numbersMap) number ->
let hits = numbersMap |> Map.tryFind number |> Option.defaultValue Seq.empty
let (maybeBoardLineAndNumber, hitsMap, numbersMap) =
hits
|> Seq.fold (fun (maybeBoardLineAndNumber, hitsMap, numbersMap) boardLine ->
let hitsForBoardline = hitsMap |> Map.tryFind boardLine |> Option.defaultValue 0
if hitsForBoardline = 4
then
let hitsMap =
(Map.add boardLine 5 hitsMap)
|> Map.filter (fun (boardId, _) _ -> boardId <> (fst boardLine))
let numbersMap =
numbersMap
|> Map.map (fun _ (boardLines: seq<BoardLine>) ->
boardLines |> Seq.filter (fun (boardId, _) -> boardId <> (fst boardLine))
)
(Some (boardLine, number)), hitsMap, numbersMap
else maybeBoardLineAndNumber, Map.add boardLine (hitsForBoardline + 1) hitsMap, numbersMap
) (maybeBoardLineAndNumber, hitsMap, numbersMap)
(maybeBoardLineAndNumber, hitsMap, numbersMap)
) (None, Map.empty, numbersMap)
let (matchingBoard, lastExtractedNumber) =
match maybeBoardLineAndNumber with
| Some ((boardId, line), number) ->
boards |> Seq.find (fun b -> b.Id = boardId),
number
| None -> failwithf "No winning board"
let numbersExtracted =
numbers
|> Seq.takeWhile (fun n -> n <> lastExtractedNumber)
|> Seq.append [lastExtractedNumber]
let unmarkedNumbersSum =
matchingBoard.Numbers
|> Array.concat
|> Array.filter (fun n -> not (Seq.contains n numbersExtracted))
|> Array.sum
let result = unmarkedNumbersSum * lastExtractedNumber