| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- import * as O from "fp-ts/Option";
- import * as N from "fp-ts/number";
- import { chunksOf, concat, every, exists, filter, findFirst, isOutOfBound, map, mapWithIndex, reduce, replicate, tail } from "fp-ts/lib/Array";
- import { pipe } from "fp-ts/lib/function";
- import { concatAll } from "fp-ts/lib/Monoid";
- import { isEmpty } from "fp-ts/lib/string";
- import { draws as testDraws, RawTable, tables as testTables } from "./input.test";
- import { draws as inputDraws, tables as inputTables } from "./input";
- type Value = {
- value: number,
- marked: boolean
- };
- type Table = {
- id: number;
- lastMarked?: number,
- won?: number;
- table: Value[][]
- }
- const parseTables = (tables: string) => pipe(
- tables.split("\n"),
- filter(s => !isEmpty(s)),
- chunksOf(5),
- map(table => pipe(table, map(row => row.split(" ").filter(n => !isEmpty(n)).map(s => parseInt(s)))))
- );
- const tables: Table[] = pipe(
- // testTables,
- parseTables(inputTables),
- mapWithIndex<RawTable, Table>((i, t) => ({
- id: i,
- table: pipe(t, map(r => pipe(r, map<number, Value>(v => ({ value: v, marked: false })))))
- }))
- );
- const draws: number[] =
- // testDraws;
- inputDraws;
- const product = (a: number) => (b: number) =>
- N.MonoidProduct.concat(a, b);
- const result = (table: Table): number => pipe(
- [...table.table],
- reduce([] as Value[], (all, curr) => pipe(all, concat(curr))),
- filter(v => !v.marked),
- map(v => v.value),
- concatAll(N.MonoidSum),
- product(table.lastMarked ?? 1)
- );
- const evalRows = (table: Table): O.Option<number> => pipe(
- [...table.table],
- map(every(v => v.marked)),
- reduce(false, (acc, r) => acc || r),
- O.guard,
- O.map(() => result(table))
- );
- const evalColumns = (table: Table): O.Option<number> => pipe(
- [...table.table],
- reduce(
- replicate(table.table[0].length, true),
- (marks, row) => pipe(row, map(v => v.marked), mapWithIndex((i, m) => marks[i] && m))
- ),
- exists(m => m),
- O.guard,
- O.map(() => result(table))
- );
- const evalTable = (table: Table): Table => pipe(
- table,
- evalRows,
- O.alt(() => evalColumns(table)),
- O.fold(
- () => ({...table}),
- n => ({...table, won: n})
- )
- );
- const findValue = (draw: number) => (table: Table): O.Option<Value> => pipe(
- [...table.table],
- map(findFirst((v: Value) => v.value === draw)),
- reduce(O.none as O.Option<Value>, (v, o) => pipe(v, O.alt(() => o)))
- );
- const calc = (tables: Table[]) => (draw: number): Table[] => pipe(
- tables,
- filter(t => t.won === undefined),
- map(t => pipe(
- t,
- findValue(draw),
- O.fold<Value, Table>(
- () => ({
- ...t,
- lastMarked: undefined
- }),
- v => {
- v.marked = true;
- return {
- ...t,
- lastMarked: draw
- };
- }
- ),
- evalTable
- ))
- );
- const play = (ts: Table[], ds: number[]): Table[] => {
- if(isOutOfBound(0, ds)) {
- return ts;
- }
- const newTables = calc(ts)(ds[0]);
- console.log("new winners:", pipe(newTables, filter(t => t.won !== undefined)));
- return play(newTables, pipe(ds, tail, O.getOrElse(() => [] as number[])));
- }
- play(tables, draws);
|