import * as A from "fp-ts/Array"; import * as N from "fp-ts/number"; import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; import { contramap, max, min } from "fp-ts/lib/Ord"; import { Eq, struct } from 'fp-ts/Eq' import { vectors as testVetctors } from "./input.test"; import { vectors as inputVectors } from "./input"; type Point = { x: number, y: number }; type Vector = { from: Point, to: Point }; const parseVectors = (input: string) => pipe( input.split("\n"), A.map(v => { const points = pipe( v.split(" -> "), A.map(p => { const coords = pipe( p.split(","), A.map(parseInt) ); return { x: coords[0], y: coords[1] }; }) ); return { from: points[0], to: points[1] }; }) ); const vectors = parseVectors( // testVetctors inputVectors ); const maxNum = max(N.Ord); const minNum = min(N.Ord); const expand = (vector: Vector): Point[] => pipe( vector.from.x === vector.to.x ? A.replicate(maxNum(vector.to.y, vector.from.y) - minNum(vector.to.y, vector.from.y) + 1, vector.from.x) : A.makeBy( maxNum(vector.to.x, vector.from.x) - minNum(vector.to.x, vector.from.x) + 1, n => (vector.to.x > vector.from.x ? vector.from.x + n : vector.from.x - n) ), A.zip(vector.from.y === vector.to.y ? A.replicate(maxNum(vector.to.x, vector.from.x) - minNum(vector.to.x, vector.from.x) + 1, vector.from.y) : A.makeBy( maxNum(vector.to.y, vector.from.y) - minNum(vector.to.y, vector.from.y) + 1, n => (vector.to.y > vector.from.y ? vector.from.y + n : vector.from.y - n) )), A.map(([x, y]) => ({ x, y })) ); const byX = pipe(N.Ord, contramap((p: Point) => p.x)); const byY = pipe(N.Ord, contramap((p: Point) => p.y)); const eqPoint: Eq = struct({ x: N.Eq, y: N.Eq }); const group = (points: Point[]): Point[][] => pipe( points, A.reduce([] as Point[][], (groupped, p) => pipe(groupped, A.last, O.chain(A.last), O.map(pp => eqPoint.equals(pp, p)), O.getOrElse(() => false)) ? pipe(groupped, A.init, O.map(is => [...is, pipe(groupped, A.last, O.map(l => [...l, p]), O.getOrElse(() => [p]))]), O.getOrElseW(() => pipe(groupped, A.append([p])))) : pipe(groupped, A.append([p]))) ); const result = pipe( vectors, // A.filter(v => v.from.x === v.to.x || v.from.y === v.to.y), A.map(expand), A.flatten, A.sortBy([byX, byY]), group, A.reduce(0, (count, ps) => ps.length > 1 ? count + 1 : count) ); console.log(result);