From 4b35e492b5747c8adc1ef27018cd51a92b22c702 Mon Sep 17 00:00:00 2001 From: Rano | Ranadeep Date: Wed, 4 Dec 2024 12:03:53 +0100 Subject: [PATCH] feat: day 4 (#6) * add code coverage * rm redundant task * day 4 * refactor * write permission for pr comment * corner case --- .github/workflows/deno.yaml | 13 ++++- day1/mod.ts | 6 +-- day1/test.ts | 6 +-- day2/example.txt | 1 + day2/mod.ts | 6 +-- day2/test.ts | 6 +-- day4/deno.json | 7 +++ day4/example.txt | 10 ++++ day4/mod.ts | 101 ++++++++++++++++++++++++++++++++++++ day4/test.ts | 9 ++++ deno.json | 6 +-- 11 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 day4/deno.json create mode 100644 day4/example.txt create mode 100644 day4/mod.ts create mode 100644 day4/test.ts diff --git a/.github/workflows/deno.yaml b/.github/workflows/deno.yaml index 4f98f13..c4c5831 100644 --- a/.github/workflows/deno.yaml +++ b/.github/workflows/deno.yaml @@ -9,9 +9,20 @@ jobs: test: name: Test runs-on: ubuntu-latest + permissions: + pull-requests: write steps: - uses: actions/checkout@v4 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - - run: deno test --allow-read + - run: | + deno test --allow-read --coverage=cov_profile + deno coverage --lcov --output=cov.lcov cov_profile + - uses: hrishikesh-kadam/setup-lcov@v1 + - uses: zgosalvez/github-actions-report-lcov@v3 + with: + coverage-files: cov.lcov + minimum-coverage: 60 + github-token: ${{ secrets.GITHUB_TOKEN }} + update-comment: true diff --git a/day1/mod.ts b/day1/mod.ts index 9a17535..a8b3cba 100644 --- a/day1/mod.ts +++ b/day1/mod.ts @@ -1,4 +1,4 @@ -export function process_data(data: string): number[][] { +export function parse(data: string): number[][] { const parsed = data.split("\n").map((x) => x.split(" ").map((x) => parseInt(x)) ); @@ -46,6 +46,6 @@ export function solve2(data: number[][]): number { if (import.meta.main) { const data_path = new URL("input.txt", import.meta.url).pathname; const data = await Deno.readTextFile(data_path); - console.log(solve1(process_data(data))); - console.log(solve2(process_data(data))); + console.log(solve1(parse(data))); + console.log(solve2(parse(data))); } diff --git a/day1/test.ts b/day1/test.ts index 8f4afd4..6ff27b4 100644 --- a/day1/test.ts +++ b/day1/test.ts @@ -1,9 +1,9 @@ import { assertEquals } from "@std/assert"; -import { process_data, solve1, solve2 } from "./mod.ts"; +import { parse, solve1, solve2 } from "./mod.ts"; Deno.test(async function testExample() { const example_data_path = new URL("example.txt", import.meta.url).pathname; const example_data = await Deno.readTextFile(example_data_path); - assertEquals(solve1(process_data(example_data)), 11); - assertEquals(solve2(process_data(example_data)), 31); + assertEquals(solve1(parse(example_data)), 11); + assertEquals(solve2(parse(example_data)), 31); }); diff --git a/day2/example.txt b/day2/example.txt index b49c10d..eab7e86 100644 --- a/day2/example.txt +++ b/day2/example.txt @@ -4,3 +4,4 @@ 1 3 2 4 5 8 6 4 4 1 1 3 6 7 9 +1 2 2 9 4 diff --git a/day2/mod.ts b/day2/mod.ts index 346d6d1..0043967 100644 --- a/day2/mod.ts +++ b/day2/mod.ts @@ -1,4 +1,4 @@ -export function process_data(data: string): number[][] { +export function parse(data: string): number[][] { const parsed = data.split("\n").map((x) => x.split(" ").map((x) => parseInt(x)) ); @@ -39,6 +39,6 @@ export function solve2(data: number[][]): number { if (import.meta.main) { const data_path = new URL("input.txt", import.meta.url).pathname; const data = await Deno.readTextFile(data_path); - console.log(solve1(process_data(data))); - console.log(solve2(process_data(data))); + console.log(solve1(parse(data))); + console.log(solve2(parse(data))); } diff --git a/day2/test.ts b/day2/test.ts index 2e50cf4..aa5a14a 100644 --- a/day2/test.ts +++ b/day2/test.ts @@ -1,9 +1,9 @@ import { assertEquals } from "@std/assert"; -import { process_data, solve1, solve2 } from "./mod.ts"; +import { parse, solve1, solve2 } from "./mod.ts"; Deno.test(async function testExample() { const example_data_path = new URL("example.txt", import.meta.url).pathname; const example_data = await Deno.readTextFile(example_data_path); - assertEquals(solve1(process_data(example_data)), 2); - assertEquals(solve2(process_data(example_data)), 4); + assertEquals(solve1(parse(example_data)), 2); + assertEquals(solve2(parse(example_data)), 4); }); diff --git a/day4/deno.json b/day4/deno.json new file mode 100644 index 0000000..31950ac --- /dev/null +++ b/day4/deno.json @@ -0,0 +1,7 @@ +{ + "name": "@scope/day4", + "version": "0.1.0", + "exports": { + ".": "./mod.ts" + } +} diff --git a/day4/example.txt b/day4/example.txt new file mode 100644 index 0000000..1f4eda2 --- /dev/null +++ b/day4/example.txt @@ -0,0 +1,10 @@ +MMMSXXMASM +MSAMXMSMSA +AMXSXMAAMM +MSAMASMSMX +XMASAMXAMM +XXAMMXXAMA +SMSMSASXSS +SAXAMASAAA +MAMMMXMMMM +MXMXAXMASX diff --git a/day4/mod.ts b/day4/mod.ts new file mode 100644 index 0000000..d6cf8a8 --- /dev/null +++ b/day4/mod.ts @@ -0,0 +1,101 @@ +const XMAS: string = "XMAS"; +const MAS: string = "MAS"; + +export function parse(data: string): string[] { + const parsed = data.split("\n"); + return parsed + // Remove the last element, which is an empty string + .slice(0, parsed.length - 1); +} + +class Grid { + grid: string[]; + constructor(grid: string[]) { + this.grid = grid; + } + + x_len(): number { + return this.grid[0].length; + } + + y_len(): number { + return this.grid.length; + } + + get(x: number, y: number): string { + return this.grid[y]?.[x] ?? ""; + } + + find_xmas_at(x: number, y: number): number { + let count = 0; + + for (const dx of [-1, 0, 1]) { + for (const dy of [-1, 0, 1]) { + if (dx === 0 && dy === 0) continue; + + if ( + Array.from({ length: XMAS.length }).every((_, i) => { + const xx = x + dx * i; + const yy = y + dy * i; + + return this.get(xx, yy) == XMAS[i]; + }) + ) { + count++; + } + } + } + + return count; + } + + is_x_mas_at(x: number, y: number): boolean { + return [-1, 1].some((d) => { + return this.get(x - d, y - d) + this.get(x, y) + + this.get(x + d, y + d) == MAS; + }) && + [-1, 1].some((d) => { + return this.get(x - d, y + d) + this.get(x, y) + + this.get(x + d, y - d) == MAS; + }); + } + + find_all_xmas(): number { + let count = 0; + for (let x = 0; x < this.x_len(); x++) { + for (let y = 0; y < this.y_len(); y++) { + count += this.find_xmas_at(x, y); + } + } + return count; + } + + find_all_x_mas(): number { + let count = 0; + for (let y = 0; y < this.y_len(); y++) { + for (let x = 0; x < this.x_len(); x++) { + if (this.is_x_mas_at(x, y)) { + count++; + } + } + } + return count; + } +} + +export function solve1(data: string[]): number { + const grid = new Grid(data); + return grid.find_all_xmas(); +} + +export function solve2(data: string[]): number { + const grid = new Grid(data); + return grid.find_all_x_mas(); +} + +if (import.meta.main) { + const data_path = new URL("input.txt", import.meta.url).pathname; + const data = await Deno.readTextFile(data_path); + console.log(solve1(parse(data))); + console.log(solve2(parse(data))); +} diff --git a/day4/test.ts b/day4/test.ts new file mode 100644 index 0000000..7b906ca --- /dev/null +++ b/day4/test.ts @@ -0,0 +1,9 @@ +import { assertEquals } from "@std/assert"; +import { parse, solve1, solve2 } from "./mod.ts"; + +Deno.test(async function testExample() { + const example_data_path = new URL("example.txt", import.meta.url).pathname; + const example_data = await Deno.readTextFile(example_data_path); + assertEquals(solve1(parse(example_data)), 18); + assertEquals(solve2(parse(example_data)), 9); +}); diff --git a/deno.json b/deno.json index e8b0794..d06ad49 100644 --- a/deno.json +++ b/deno.json @@ -3,12 +3,10 @@ "members": [ "./day1", "./day2", - "./day3" + "./day3", + "./day4" ] }, - "tasks": { - "dev": "deno run --watch main.ts" - }, "imports": { "@std/assert": "jsr:@std/assert@1" }