|
|
@@ -0,0 +1,89 @@
|
|
|
+import * as A from "fp-ts/Array";
|
|
|
+import * as N from "fp-ts/number";
|
|
|
+
|
|
|
+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<string, Vector>(v => {
|
|
|
+ const points = pipe(
|
|
|
+ v.split(" -> "),
|
|
|
+ A.map<string, Point>(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 : vector.to.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 : vector.to.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<Point> = struct({
|
|
|
+ x: N.Eq,
|
|
|
+ y: N.Eq
|
|
|
+});
|
|
|
+
|
|
|
+const group = (points: Point[]): Point[][] => {
|
|
|
+ const iterator = (points: Point[], grouppedPoints: Point[][]): Point[][] => {
|
|
|
+ if (A.isEmpty(points)) {
|
|
|
+ return grouppedPoints;
|
|
|
+ }
|
|
|
+ const { init, rest } = pipe(points, A.spanLeft(p => eqPoint.equals(points[0], p)));
|
|
|
+ return iterator(rest, pipe([init], A.concat(grouppedPoints)))
|
|
|
+ }
|
|
|
+ return iterator(points, [[]]);
|
|
|
+}
|
|
|
+
|
|
|
+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);
|