├── 2015 ├── Helpers │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ └── example.txt ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── clipboard.py ├── command_opts.py └── utils.py ├── 2016 ├── Helpers │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ └── example.txt ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── clipboard.py ├── command_opts.py └── utils.py ├── 2017 ├── Helpers │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ └── example.txt ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── clipboard.py ├── command_opts.py └── utils.py ├── 2018 ├── Helpers │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.c │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ └── example.txt ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── clipboard.py ├── command_opts.py └── utils.py ├── 2019 ├── Helpers │ ├── Font-DSEG14Classic-Bold.ttf │ ├── Font-SourceCodePro-Bold.ttf │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ ├── dummylog.py │ ├── example.txt │ ├── grid.py │ └── program.py ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── animations │ ├── animation_10.mp4 │ ├── animation_11.mp4 │ ├── animation_13.mp4 │ ├── animation_15.mp4 │ ├── animation_17.mp4 │ ├── animation_18.mp4 │ ├── animation_20.mp4 │ ├── animation_23.mp4 │ ├── animation_24.mp4 │ ├── animation_25.mp4 │ └── links.txt ├── clipboard.py ├── command_opts.py ├── other │ ├── day_23 │ │ ├── App.config │ │ ├── DrawNetwork.csproj │ │ ├── DrawNetwork.sln │ │ ├── MyObj.cs │ │ ├── NetworkForm.Designer.cs │ │ ├── NetworkForm.cs │ │ ├── NetworkForm.resx │ │ ├── Program.cs │ │ └── Properties │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Resources.Designer.cs │ │ │ ├── Resources.resx │ │ │ ├── Settings.Designer.cs │ │ │ └── Settings.settings │ ├── mand_intcode │ │ ├── christmas_note.txt │ │ ├── compiler.py │ │ ├── make_ascii_chart.html │ │ ├── make_ascii_chart.py │ │ ├── mandelbrot_gen.txt │ │ ├── mandelbrot_intcode.txt │ │ ├── merry_xmas.txt │ │ ├── merry_xmas_int.txt │ │ ├── runner.py │ │ └── runner_ascii.py │ └── standalone │ │ └── day_25.py └── utils.py ├── 2020 ├── .gitignore ├── Helpers │ ├── Font-DSEG14Classic-Bold.ttf │ ├── Font-SourceCodePro-Bold.ttf │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ ├── dummylog.py │ ├── example.txt │ ├── grid.py │ └── program.py ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_14_state.txt │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── animations │ ├── animation_05.mp4 │ ├── animation_08.mp4 │ ├── animation_11_1.mp4 │ ├── animation_11_2.mp4 │ ├── animation_12.mp4 │ ├── animation_16.mp4 │ ├── animation_17.mp4 │ ├── animation_18.mp4 │ ├── animation_20.mp4 │ └── animation_24.mp4 ├── clipboard.py ├── command_opts.py └── utils.py ├── 2021 ├── .gitignore ├── Helpers │ ├── Font-DSEG14Classic-Bold.ttf │ ├── Font-SourceCodePro-Bold.ttf │ ├── animate.py │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ ├── dummylog.py │ ├── example.txt │ ├── grid.py │ └── program.py ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── animations │ ├── animation_02.mp4 │ ├── animation_05.mp4 │ ├── animation_08.mp4 │ ├── animation_09.mp4 │ ├── animation_11.mp4 │ ├── animation_15.mp4 │ ├── animation_17.mp4 │ ├── animation_20.mp4 │ ├── animation_23.mp4 │ ├── animation_24.mp4 │ └── animation_25.mp4 ├── clipboard.py ├── command_opts.py ├── main_page │ ├── .gitignore │ ├── add_new_day.py │ ├── aoc │ │ ├── index_00.html │ │ ├── index_01.html │ │ ├── index_02.html │ │ ├── index_03.html │ │ ├── index_04.html │ │ ├── index_05.html │ │ ├── index_06.html │ │ ├── index_07.html │ │ ├── index_08.html │ │ ├── index_09.html │ │ ├── index_10.html │ │ ├── index_11.html │ │ ├── index_12.html │ │ ├── index_13.html │ │ ├── index_14.html │ │ ├── index_15.html │ │ ├── index_16.html │ │ ├── index_17.html │ │ ├── index_18.html │ │ ├── index_19.html │ │ ├── index_20.html │ │ ├── index_21.html │ │ ├── index_22.html │ │ ├── index_23.html │ │ ├── index_24.html │ │ └── index_25.html │ ├── grab_screenshots.py │ └── requirements.txt ├── requirements.txt ├── sleeper.py └── utils.py ├── 2022 ├── .gitignore ├── Helpers │ ├── Font-DSEG14Classic-Bold.ttf │ ├── Font-SourceCodePro-Bold.ttf │ ├── animate.py │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ ├── dummylog.py │ ├── example.txt │ ├── grid.py │ ├── grid_draw.py │ ├── parsers.py │ └── program.py ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── animations │ ├── animation_05.mp4 │ ├── animation_10.mp4 │ └── animation_12.mp4 ├── clipboard.py ├── command_opts.py ├── main_page │ ├── .gitignore │ ├── add_new_day.py │ ├── aoc │ │ ├── index_00.html │ │ ├── index_01.html │ │ ├── index_02.html │ │ ├── index_03.html │ │ ├── index_04.html │ │ ├── index_05.html │ │ ├── index_06.html │ │ ├── index_07.html │ │ ├── index_08.html │ │ ├── index_09.html │ │ ├── index_10.html │ │ ├── index_11.html │ │ ├── index_12.html │ │ ├── index_13.html │ │ ├── index_14.html │ │ ├── index_15.html │ │ ├── index_16.html │ │ ├── index_17.html │ │ ├── index_18.html │ │ ├── index_19.html │ │ ├── index_20.html │ │ ├── index_21.html │ │ ├── index_22.html │ │ ├── index_23.html │ │ ├── index_24.html │ │ └── index_25.html │ ├── grab_screenshots.py │ └── requirements.txt ├── requirements.txt ├── sleeper.py └── utils.py ├── 2023 ├── .gitignore ├── Helpers │ ├── Font-DSEG14Classic-Bold.ttf │ ├── Font-SourceCodePro-Bold.ttf │ ├── animate.py │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ ├── dummylog.py │ ├── example.txt │ ├── grid.py │ ├── grid_draw.py │ ├── parsers.py │ └── program.py ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── animations │ ├── animation_10.mp4 │ └── animation_14.mp4 ├── clipboard.py ├── command_opts.py ├── main_page │ ├── .gitignore │ ├── add_new_day.py │ ├── aoc │ │ ├── index_00.html │ │ ├── index_01.html │ │ ├── index_02.html │ │ ├── index_03.html │ │ ├── index_04.html │ │ ├── index_05.html │ │ ├── index_06.html │ │ ├── index_07.html │ │ ├── index_08.html │ │ ├── index_09.html │ │ ├── index_10.html │ │ ├── index_11.html │ │ ├── index_12.html │ │ ├── index_13.html │ │ ├── index_14.html │ │ ├── index_15.html │ │ ├── index_16.html │ │ ├── index_17.html │ │ ├── index_18.html │ │ ├── index_19.html │ │ ├── index_20.html │ │ ├── index_21.html │ │ ├── index_22.html │ │ ├── index_23.html │ │ ├── index_24.html │ │ └── index_25.html │ ├── grab_screenshots.py │ └── requirements.txt ├── requirements.txt ├── sleeper.py └── utils.py ├── 2024 ├── .gitignore ├── Helpers │ ├── Font-DSEG14Classic-Bold.ttf │ ├── Font-SourceCodePro-Bold.ttf │ ├── animate.py │ ├── day_01.py │ ├── day_02.py │ ├── day_03.py │ ├── day_04.py │ ├── day_05.py │ ├── day_06.py │ ├── day_07.py │ ├── day_08.py │ ├── day_09.py │ ├── day_10.py │ ├── day_11.py │ ├── day_12.py │ ├── day_13.py │ ├── day_14.py │ ├── day_15.py │ ├── day_16.py │ ├── day_17.py │ ├── day_18.py │ ├── day_19.py │ ├── day_20.py │ ├── day_21.py │ ├── day_22.py │ ├── day_23.py │ ├── day_24.py │ ├── day_25.py │ ├── dummylog.py │ ├── example.txt │ ├── grid.py │ ├── grid_draw.py │ ├── parsers.py │ └── program.py ├── Puzzles │ ├── SourceCodePro.css │ ├── SourceCodePro.ttf │ ├── day_01.html │ ├── day_02.html │ ├── day_03.html │ ├── day_04.html │ ├── day_05.html │ ├── day_06.html │ ├── day_07.html │ ├── day_08.html │ ├── day_09.html │ ├── day_10.html │ ├── day_11.html │ ├── day_12.html │ ├── day_13.html │ ├── day_14.html │ ├── day_15.html │ ├── day_16.html │ ├── day_17.html │ ├── day_18.html │ ├── day_19.html │ ├── day_20.html │ ├── day_21.html │ ├── day_22.html │ ├── day_23.html │ ├── day_24.html │ ├── day_25.html │ ├── favicon.png │ ├── highcontrast.css │ ├── html5.js │ ├── index.html │ ├── main_page.png │ ├── main_page_small.png │ └── style.css ├── README.md ├── URL.txt ├── advent.py ├── advent_year.py ├── animations │ ├── animation_06.mp4 │ ├── animation_06_fast.mp4 │ ├── animation_09.mp4 │ ├── animation_12.mp4 │ ├── animation_14.mp4 │ ├── animation_15.mp4 │ ├── animation_16.mp4 │ ├── animation_17.mp4 │ ├── animation_18.mp4 │ ├── animation_21.mp4 │ ├── image_23.png │ ├── image_24_p1.png │ └── image_24_p2.png ├── clipboard.py ├── command_opts.py ├── main_page │ ├── .gitignore │ ├── add_new_day.py │ ├── aoc │ │ ├── index_00.html │ │ ├── index_01.html │ │ ├── index_02.html │ │ ├── index_03.html │ │ ├── index_04.html │ │ ├── index_05.html │ │ ├── index_06.html │ │ ├── index_07.html │ │ ├── index_08.html │ │ ├── index_09.html │ │ ├── index_10.html │ │ ├── index_11.html │ │ ├── index_12.html │ │ ├── index_13.html │ │ ├── index_14.html │ │ ├── index_15.html │ │ ├── index_16.html │ │ ├── index_17.html │ │ ├── index_18.html │ │ ├── index_19.html │ │ ├── index_20.html │ │ ├── index_21.html │ │ ├── index_22.html │ │ ├── index_23.html │ │ ├── index_24.html │ │ └── index_25.html │ ├── grab_screenshots.py │ └── requirements.txt ├── requirements.txt ├── sleeper.py └── utils.py ├── .gitattributes ├── .gitignore ├── README.md ├── make_new_year.py └── other ├── all_images.png ├── aoc └── favicon.png ├── aoc_ticker.html ├── aoc_tree.png ├── aoc_tree_small.png ├── index.html └── make_main_image.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-detectable=false 2 | *.html linguist-detectable=false 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the root helpers, and the private code 2 | /command_opts.py 3 | /bounce_git.py 4 | /test_all.py 5 | /private/* 6 | 7 | # Ignore my little stats side-project 8 | /stats/* 9 | **/.p4ignore 10 | 11 | # Ignore VS Code stuff 12 | **/.vscode/ 13 | 14 | # Python pre-compiled things 15 | **/__pycache__/ 16 | *.py[cod] 17 | *$py.class 18 | **/pythonenv*/ 19 | 20 | # Visual Studio folders 21 | **/.vs/ 22 | **/bin/ 23 | **/obj/ 24 | 25 | # Temp files 26 | *~ 27 | **/.DS_Store/ 28 | **/debug.log 29 | -------------------------------------------------------------------------------- /2015/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: Not Quite Lisp' 5 | 6 | def calc(log, values): 7 | ret = 0 8 | pos = 0 9 | shown = False 10 | for cur in values: 11 | for sub in cur: 12 | if sub == "(": 13 | ret += 1 14 | pos += 1 15 | elif sub == ")": 16 | ret -= 1 17 | pos += 1 18 | if not shown: 19 | if ret < 0: 20 | log("Part 2: %d" % (pos,)) 21 | shown = True 22 | 23 | return ret 24 | 25 | def test(log): 26 | values = [ 27 | ")())())", 28 | ] 29 | 30 | if calc(log, values) == -3: 31 | return True 32 | else: 33 | return False 34 | 35 | 36 | def run(log, values): 37 | log("Part 1: %d" % (calc(log, values),)) 38 | 39 | if __name__ == "__main__": 40 | import sys, os 41 | def find_input_file(): 42 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 43 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 44 | cur = os.path.join(*(dn.split("/") + [fn])) 45 | if os.path.isfile(cur): return cur 46 | fn = find_input_file() 47 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 48 | print(f"Using '{fn}' as input file:") 49 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 50 | print(f"Running day {DAY_DESC}:") 51 | run(print, values) 52 | -------------------------------------------------------------------------------- /2015/Helpers/day_02.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 2 4 | DAY_DESC = 'Day 2: I Was Told There Would Be No Math' 5 | 6 | def calc(log, values): 7 | ret = 0 8 | ribbon = 0 9 | for cur in values: 10 | cur = [int(x) for x in cur.split("x")] 11 | a, b, c = cur[0] * cur[1] * 2, cur[1] * cur[2] * 2, cur[0] * cur[2] * 2 12 | ret += sum((a, b, c)) + min((a, b, c)) // 2 13 | ribbon += sum(sorted(cur)[0:2])*2 + cur[0] * cur[1] * cur[2] 14 | 15 | log("Part 2: %d" % (ribbon,)) 16 | 17 | return ret 18 | 19 | def test(log): 20 | values = [ 21 | "2x3x4", 22 | ] 23 | 24 | if calc(log, values) == 58: 25 | return True 26 | else: 27 | return False 28 | 29 | def run(log, values): 30 | log("Part 1: %d" % (calc(log, values),)) 31 | 32 | if __name__ == "__main__": 33 | import sys, os 34 | def find_input_file(): 35 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 36 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 37 | cur = os.path.join(*(dn.split("/") + [fn])) 38 | if os.path.isfile(cur): return cur 39 | fn = find_input_file() 40 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 41 | print(f"Using '{fn}' as input file:") 42 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 43 | print(f"Running day {DAY_DESC}:") 44 | run(print, values) 45 | -------------------------------------------------------------------------------- /2015/Helpers/day_03.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import deque 4 | 5 | DAY_NUM = 3 6 | DAY_DESC = 'Day 3: Perfectly Spherical Houses in a Vacuum' 7 | 8 | def calc(values, units): 9 | dirs = { 10 | '^': (0, -1), 11 | 'v': (0, 1), 12 | '<': (-1, 0), 13 | '>': (1, 0), 14 | } 15 | 16 | locs = deque() 17 | for _ in range(units): 18 | locs.append((0, 0)) 19 | 20 | seen = set() 21 | seen.add((0, 0)) 22 | 23 | for line in values: 24 | for cur in line: 25 | if cur in dirs: 26 | x, y = locs.popleft() 27 | off = dirs[cur] 28 | x += off[0] 29 | y += off[1] 30 | seen.add((x, y)) 31 | locs.append((x, y)) 32 | 33 | return len(seen) 34 | 35 | def test(log): 36 | values = [ 37 | "^>v<", 38 | ] 39 | 40 | if calc(values, 1) == 4: 41 | return True 42 | else: 43 | return False 44 | 45 | def run(log, values): 46 | log("Part 1: %d" % (calc(values, 1),)) 47 | log("Part 2: %d" % (calc(values, 2),)) 48 | 49 | if __name__ == "__main__": 50 | import sys, os 51 | def find_input_file(): 52 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 53 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 54 | cur = os.path.join(*(dn.split("/") + [fn])) 55 | if os.path.isfile(cur): return cur 56 | fn = find_input_file() 57 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 58 | print(f"Using '{fn}' as input file:") 59 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 60 | print(f"Running day {DAY_DESC}:") 61 | run(print, values) 62 | -------------------------------------------------------------------------------- /2015/Helpers/day_08.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import codecs 4 | 5 | DAY_NUM = 8 6 | DAY_DESC = 'Day 8: Matchsticks' 7 | 8 | def calc(log, values): 9 | total_size = 0 10 | total_decoded = 0 11 | total_encoded = 0 12 | 13 | for cur in values: 14 | total_size += len(cur) 15 | total_decoded += len(codecs.escape_decode(cur[1:-1])[0]) 16 | 17 | cur = cur.replace("\\", "\\\\") 18 | cur = cur.replace('"', '\\"') 19 | 20 | total_encoded += len(cur) + 2 21 | 22 | log("Part 2: %d" % (total_encoded - total_size,)) 23 | 24 | return total_size - total_decoded 25 | 26 | def test(log): 27 | return True 28 | 29 | def run(log, values): 30 | log("Part 1: %d" % (calc(log, values),)) 31 | 32 | if __name__ == "__main__": 33 | import sys, os 34 | def find_input_file(): 35 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 36 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 37 | cur = os.path.join(*(dn.split("/") + [fn])) 38 | if os.path.isfile(cur): return cur 39 | fn = find_input_file() 40 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 41 | print(f"Using '{fn}' as input file:") 42 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 43 | print(f"Running day {DAY_DESC}:") 44 | run(print, values) 45 | -------------------------------------------------------------------------------- /2015/Helpers/day_09.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import itertools 5 | 6 | DAY_NUM = 9 7 | DAY_DESC = 'Day 9: All in a Single Night' 8 | 9 | def calc(log, values): 10 | r = re.compile("(.*) to (.*) = ([0-9]+)") 11 | 12 | cities = set() 13 | dists = {} 14 | 15 | for cur in values: 16 | m = r.search(cur) 17 | a, b, dist = m.groups() 18 | dist = int(dist) 19 | cities.add(a) 20 | cities.add(b) 21 | dists[(a, b)] = dist 22 | dists[(b, a)] = dist 23 | 24 | best_val = None 25 | worst_val = None 26 | 27 | for path in itertools.permutations(cities): 28 | last = None 29 | value = 0 30 | for cur in path: 31 | if last is not None: 32 | value += dists[(last, cur)] 33 | last = cur 34 | if best_val is None or value < best_val: 35 | best_val = value 36 | if worst_val is None or value > worst_val: 37 | worst_val = value 38 | 39 | log("Part 2: %d" % (worst_val,)) 40 | 41 | return best_val 42 | 43 | def test(log): 44 | values = [ 45 | "London to Dublin = 464", 46 | "London to Belfast = 518", 47 | "Dublin to Belfast = 141", 48 | ] 49 | 50 | if calc(log, values) == 605: 51 | return True 52 | else: 53 | return False 54 | 55 | def run(log, values): 56 | log("Part 1: %d" % (calc(log, values),)) 57 | 58 | if __name__ == "__main__": 59 | import sys, os 60 | def find_input_file(): 61 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 62 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 63 | cur = os.path.join(*(dn.split("/") + [fn])) 64 | if os.path.isfile(cur): return cur 65 | fn = find_input_file() 66 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 67 | print(f"Using '{fn}' as input file:") 68 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 69 | print(f"Running day {DAY_DESC}:") 70 | run(print, values) 71 | -------------------------------------------------------------------------------- /2015/Helpers/day_10.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import deque 4 | 5 | DAY_NUM = 10 6 | DAY_DESC = 'Day 10: Elves Look, Elves Say' 7 | 8 | def calc(values, loops): 9 | look = deque(values[0]) 10 | 11 | while loops > 0: 12 | loops -= 1 13 | last = None 14 | count = 0 15 | say = deque() 16 | for cur in look: 17 | if last is not None: 18 | if last != cur: 19 | say.extend("%d%s" % (count, last)) 20 | count = 0 21 | last = cur 22 | count += 1 23 | say.extend("%d%s" % (count, last)) 24 | look = say 25 | 26 | return len(look) 27 | 28 | def test(log): 29 | values = [ 30 | "1", 31 | ] 32 | 33 | if calc(values, 5) == len("312211"): 34 | return True 35 | else: 36 | return False 37 | 38 | def run(log, values): 39 | log("Part 1: %d" % (calc(values, 40),)) 40 | log("Part 2: %d" % (calc(values, 50),)) 41 | 42 | if __name__ == "__main__": 43 | import sys, os 44 | def find_input_file(): 45 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 46 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 47 | cur = os.path.join(*(dn.split("/") + [fn])) 48 | if os.path.isfile(cur): return cur 49 | fn = find_input_file() 50 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 51 | print(f"Using '{fn}' as input file:") 52 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 53 | print(f"Running day {DAY_DESC}:") 54 | run(print, values) 55 | -------------------------------------------------------------------------------- /2015/Helpers/day_11.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | DAY_NUM = 11 6 | DAY_DESC = 'Day 11: Corporate Policy' 7 | 8 | def is_valid(r, value): 9 | if "i" in value or "o" in value or "l" in value: 10 | return False 11 | if r.search(value) is None: 12 | return False 13 | expected = "-" 14 | run = 1 15 | for cur in value: 16 | if cur == expected: 17 | run += 1 18 | if run == 3: 19 | return True 20 | else: 21 | run = 1 22 | expected = chr(ord(cur) + 1) 23 | return False 24 | 25 | def calc(values): 26 | r = re.compile("(.)\\1.*?(.)\\2") 27 | value = list(values[0]) 28 | 29 | while True: 30 | dig = len(value) - 1 31 | while True: 32 | if value[dig] == "z": 33 | value[dig] = "a" 34 | dig -= 1 35 | else: 36 | value[dig] = chr(ord(value[dig]) + 1) 37 | break 38 | if is_valid(r, "".join(value)): 39 | return "".join(value) 40 | 41 | def test(log): 42 | values = [ 43 | "ghijklmn", 44 | ] 45 | 46 | if calc(values) == 'ghjaabcc': 47 | return True 48 | else: 49 | return False 50 | 51 | def run(log, values): 52 | ret = calc(values) 53 | log("Part 1: %s" % (ret,)) 54 | ret = calc([ret]) 55 | log("Part 2: %s" % (ret,)) 56 | 57 | if __name__ == "__main__": 58 | import sys, os 59 | def find_input_file(): 60 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 61 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 62 | cur = os.path.join(*(dn.split("/") + [fn])) 63 | if os.path.isfile(cur): return cur 64 | fn = find_input_file() 65 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 66 | print(f"Using '{fn}' as input file:") 67 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 68 | print(f"Running day {DAY_DESC}:") 69 | run(print, values) 70 | -------------------------------------------------------------------------------- /2015/Helpers/day_12.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | 5 | DAY_NUM = 12 6 | DAY_DESC = 'Day 12: JSAbacusFramework.io' 7 | 8 | def summarize(data, red_pass): 9 | ret = 0 10 | if isinstance(data, dict): 11 | skip = False 12 | if red_pass: 13 | if "red" in data.values(): 14 | skip = True 15 | elif "red" in data: 16 | skip = True 17 | if not skip: 18 | for value in data.values(): 19 | ret += summarize(value, red_pass) 20 | elif isinstance(data, list): 21 | for key in data: 22 | ret += summarize(key, red_pass) 23 | elif isinstance(data, int): 24 | ret += data 25 | return ret 26 | 27 | def calc(values, red_pass): 28 | data = values[0] 29 | data = json.loads(data) 30 | 31 | return summarize(data, red_pass) 32 | 33 | def test(log): 34 | values = [ 35 | '{"a":[-1,1]}', 36 | ] 37 | 38 | if calc(values, False) == 0: 39 | return True 40 | else: 41 | return False 42 | 43 | def run(log, values): 44 | log("Part 1: %d" % (calc(values, False),)) 45 | log("Part 2: %d" % (calc(values, True),)) 46 | 47 | if __name__ == "__main__": 48 | import sys, os 49 | def find_input_file(): 50 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 51 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 52 | cur = os.path.join(*(dn.split("/") + [fn])) 53 | if os.path.isfile(cur): return cur 54 | fn = find_input_file() 55 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 56 | print(f"Using '{fn}' as input file:") 57 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 58 | print(f"Running day {DAY_DESC}:") 59 | run(print, values) 60 | -------------------------------------------------------------------------------- /2015/Helpers/day_17.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import itertools 4 | from collections import defaultdict 5 | 6 | DAY_NUM = 17 7 | DAY_DESC = 'Day 17: No Such Thing as Too Much' 8 | 9 | def calc(log, values, target): 10 | values = [int(x) for x in values] 11 | ret = 0 12 | used = defaultdict(int) 13 | for i in range(1, len(values)+1): 14 | for test in itertools.combinations(values, i): 15 | if sum(test) == target: 16 | ret += 1 17 | used[len(test)] += 1 18 | 19 | min_size = min(used) 20 | log("Part 2: %d" % (used[min_size],)) 21 | 22 | return ret 23 | 24 | def test(log): 25 | values = [ 26 | "20", 27 | "15", 28 | "10", 29 | "5", 30 | "5", 31 | ] 32 | 33 | if calc(log, values, 25) == 4: 34 | return True 35 | else: 36 | return False 37 | 38 | def run(log, values): 39 | log("Part 1: %d" % (calc(log, values, 150),)) 40 | 41 | if __name__ == "__main__": 42 | import sys, os 43 | def find_input_file(): 44 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 45 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 46 | cur = os.path.join(*(dn.split("/") + [fn])) 47 | if os.path.isfile(cur): return cur 48 | fn = find_input_file() 49 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 50 | print(f"Using '{fn}' as input file:") 51 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 52 | print(f"Running day {DAY_DESC}:") 53 | run(print, values) 54 | -------------------------------------------------------------------------------- /2015/Helpers/day_25.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 25 4 | DAY_DESC = 'Day 25: Let It Snow' 5 | 6 | import re 7 | 8 | def calc(target_x, target_y): 9 | x, y = 1, 1 10 | value = 20151125 11 | 12 | while x != target_x or y != target_y: 13 | x += 1 14 | y -= 1 15 | if y == 0: 16 | x, y = 1, x 17 | value = (value * 252533) % 33554393 18 | 19 | return value 20 | 21 | def test(log): 22 | if calc(4, 5) == 6899651: 23 | return True 24 | else: 25 | return False 26 | 27 | def run(log, values): 28 | m = re.findall("[0-9]+", values[0]) 29 | log("Part 1: %d" % (calc(int(m[1]), int(m[0])),)) 30 | 31 | if __name__ == "__main__": 32 | import sys, os 33 | def find_input_file(): 34 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 35 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 36 | cur = os.path.join(*(dn.split("/") + [fn])) 37 | if os.path.isfile(cur): return cur 38 | fn = find_input_file() 39 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 40 | print(f"Using '{fn}' as input file:") 41 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 42 | print(f"Running day {DAY_DESC}:") 43 | run(print, values) 44 | -------------------------------------------------------------------------------- /2015/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_desc(): 4 | return DAY_NUM, 'DAY_TODO' 5 | 6 | 7 | def calc(log, values): 8 | # TODO 9 | return 0 10 | 11 | 12 | def test(log): 13 | values = [ 14 | "TODO", 15 | ] 16 | 17 | if calc(log, values) == 1234: 18 | return True 19 | else: 20 | return False 21 | 22 | 23 | def run(log, values): 24 | log(calc(log, values)) 25 | 26 | if __name__ == "__main__": 27 | import sys, os 28 | def find_input_file(): 29 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 30 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2015/Puzzles"]: 31 | cur = os.path.join(*(dn.split("/") + [fn])) 32 | if os.path.isfile(cur): return cur 33 | fn = find_input_file() 34 | if fn is None: print("Unable to find input file!"); exit(1) 35 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 36 | print(f"Running day {DAY_DESC}:") 37 | run(print, values) 38 | -------------------------------------------------------------------------------- /2015/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2015/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2015/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2015/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2015/Puzzles/favicon.png -------------------------------------------------------------------------------- /2015/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2015/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2015/Puzzles/main_page.png -------------------------------------------------------------------------------- /2015/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2015/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2015/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2015](https://adventofcode.com/2015). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | -------------------------------------------------------------------------------- /2015/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2015 2 | -------------------------------------------------------------------------------- /2015/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2015" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2015/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2016/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import defaultdict 4 | 5 | DAY_NUM = 1 6 | DAY_DESC = 'Day 1: No Time for a Taxicab' 7 | 8 | def calc(log, values): 9 | values = values[0].split(", ") 10 | 11 | x, y = 0, 0 12 | face = 0 13 | path = [(0, 1), (1, 0), (0, -1), (-1, 0)] 14 | seen = defaultdict(int) 15 | shown = False 16 | 17 | seen[(x, y)] += 1 18 | 19 | for cur in values: 20 | if cur[0] == "L": 21 | face = (face + 3) % 4 22 | else: 23 | face = (face + 1) % 4 24 | mul = int(cur[1:]) 25 | 26 | for _ in range(mul): 27 | x += 1 * path[face][0] 28 | y += 1 * path[face][1] 29 | seen[(x, y)] += 1 30 | if not shown: 31 | if seen[(x, y)] == 2: 32 | shown = True 33 | log("Part 2: %d" % (abs(x) + abs(y),)) 34 | 35 | return abs(x) + abs(y) 36 | 37 | def test(log): 38 | values = [ 39 | "R5, L5, R5, R3", 40 | ] 41 | 42 | if calc(log, values) == 12: 43 | return True 44 | else: 45 | return False 46 | 47 | def run(log, values): 48 | log("Part 1: %d" % (calc(log, values),)) 49 | 50 | if __name__ == "__main__": 51 | import sys, os 52 | def find_input_file(): 53 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 54 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 55 | cur = os.path.join(*(dn.split("/") + [fn])) 56 | if os.path.isfile(cur): return cur 57 | fn = find_input_file() 58 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 59 | print(f"Using '{fn}' as input file:") 60 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 61 | print(f"Running day {DAY_DESC}:") 62 | run(print, values) 63 | -------------------------------------------------------------------------------- /2016/Helpers/day_03.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | DAY_NUM = 3 6 | DAY_DESC = 'Day 3: Squares With Three Sides' 7 | 8 | def calc(values, mode): 9 | valid = 0 10 | 11 | r = re.compile("([0-9]+) +([0-9]+) +([0-9]+)") 12 | tris = [] 13 | for cur in values: 14 | m = r.search(cur) 15 | vals = [int(x) for x in m.groups()] 16 | tris.append(vals) 17 | 18 | if mode == 1: 19 | for i in range(0, len(tris), 3): 20 | tris[i], tris[i+1], tris[i+2] = ( 21 | [tris[i][0], tris[i+1][0], tris[i+2][0]], 22 | [tris[i][1], tris[i+1][1], tris[i+2][1]], 23 | [tris[i][2], tris[i+1][2], tris[i+2][2]], 24 | ) 25 | 26 | for vals in tris: 27 | m = max(vals) 28 | if sum(vals) - m > m: 29 | valid += 1 30 | 31 | return valid 32 | 33 | def test(log): 34 | values = [ 35 | " 5 10 25", 36 | ] 37 | 38 | if calc(values, 0) == 0: 39 | return True 40 | else: 41 | return False 42 | 43 | def run(log, values): 44 | log("Part 1: %d" % (calc(values, 0),)) 45 | log("Part 2: %d" % (calc(values, 1),)) 46 | 47 | if __name__ == "__main__": 48 | import sys, os 49 | def find_input_file(): 50 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 51 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 52 | cur = os.path.join(*(dn.split("/") + [fn])) 53 | if os.path.isfile(cur): return cur 54 | fn = find_input_file() 55 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 56 | print(f"Using '{fn}' as input file:") 57 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 58 | print(f"Running day {DAY_DESC}:") 59 | run(print, values) 60 | -------------------------------------------------------------------------------- /2016/Helpers/day_06.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import defaultdict 4 | 5 | DAY_NUM = 6 6 | DAY_DESC = 'Day 6: Signals and Noise' 7 | 8 | def calc(values, first_pass): 9 | ret = "" 10 | for i in range(len(values[0])): 11 | hist = defaultdict(int) 12 | for cur in values: 13 | hist[cur[i]] += 1 14 | letters = list(hist) 15 | letters.sort(key=lambda x: hist[x], reverse=first_pass) 16 | ret += letters[0] 17 | 18 | return ret 19 | 20 | def test(log): 21 | values = [ 22 | "eedadn", 23 | "drvtee", 24 | "eandsr", 25 | "raavrd", 26 | "atevrs", 27 | "tsrnev", 28 | "sdttsa", 29 | "rasrtv", 30 | "nssdts", 31 | "ntnada", 32 | "svetve", 33 | "tesnvt", 34 | "vntsnd", 35 | "vrdear", 36 | "dvrsen", 37 | "enarar", 38 | ] 39 | 40 | if calc(values, True) == "easter": 41 | return True 42 | else: 43 | return False 44 | 45 | def run(log, values): 46 | log("Part 1: %s" % (calc(values, True),)) 47 | log("Part 2: %s" % (calc(values, False),)) 48 | 49 | if __name__ == "__main__": 50 | import sys, os 51 | def find_input_file(): 52 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 53 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 54 | cur = os.path.join(*(dn.split("/") + [fn])) 55 | if os.path.isfile(cur): return cur 56 | fn = find_input_file() 57 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 58 | print(f"Using '{fn}' as input file:") 59 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 60 | print(f"Running day {DAY_DESC}:") 61 | run(print, values) 62 | -------------------------------------------------------------------------------- /2016/Helpers/day_09.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 9 4 | DAY_DESC = 'Day 9: Explosives in Cyberspace' 5 | 6 | def calc(value, ver): 7 | ret = 0 8 | in_paren = None 9 | 10 | buffer = "" 11 | buffer_left = 0 12 | buffer_rep = 0 13 | 14 | for cur in value: 15 | if in_paren is None: 16 | if buffer_left > 0: 17 | buffer += cur 18 | buffer_left -= 1 19 | if buffer_left == 0: 20 | if ver == 1: 21 | ret += len(buffer) * buffer_rep 22 | else: 23 | ret += calc(buffer, 2) * buffer_rep 24 | elif cur == "(": 25 | in_paren = "" 26 | else: 27 | ret += 1 28 | else: 29 | if cur == ")": 30 | buffer_left, buffer_rep = [int(x) for x in in_paren.split("x")] 31 | buffer = "" 32 | in_paren = None 33 | else: 34 | in_paren += cur 35 | 36 | return ret 37 | 38 | def test(log): 39 | values = [ 40 | "X(8x2)(3x3)ABCY", 41 | ] 42 | 43 | if calc(values[0], 1) == 18: 44 | return True 45 | else: 46 | return False 47 | 48 | def run(log, values): 49 | log("Part 1: %d" % (calc(values[0], 1),)) 50 | log("Part 2: %d" % (calc(values[0], 2),)) 51 | 52 | if __name__ == "__main__": 53 | import sys, os 54 | def find_input_file(): 55 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 56 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 57 | cur = os.path.join(*(dn.split("/") + [fn])) 58 | if os.path.isfile(cur): return cur 59 | fn = find_input_file() 60 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 61 | print(f"Using '{fn}' as input file:") 62 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 63 | print(f"Running day {DAY_DESC}:") 64 | run(print, values) 65 | -------------------------------------------------------------------------------- /2016/Helpers/day_15.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | DAY_NUM = 15 6 | DAY_DESC = 'Day 15: Timing is Everything' 7 | 8 | def calc(values, extra=None): 9 | discs = [] 10 | r = re.compile("has ([0-9]+) positions; at time=0, it is at position ([0-9]+)\\.") 11 | for cur in values: 12 | m = r.search(cur) 13 | discs.append([int(x) for x in m.groups()]) 14 | 15 | if extra is not None: 16 | discs.append(extra) 17 | 18 | tick = 0 19 | while True: 20 | good = True 21 | for i in range(len(discs)): 22 | if (tick + i + 1 + discs[i][1]) % (discs[i][0]) != 0: 23 | good = False 24 | break 25 | if good: 26 | return tick 27 | tick += 1 28 | 29 | def test(log): 30 | values = [ 31 | "Disc #1 has 5 positions; at time=0, it is at position 4.", 32 | "Disc #2 has 2 positions; at time=0, it is at position 1.", 33 | ] 34 | 35 | if calc(values) == 5: 36 | return True 37 | else: 38 | return False 39 | 40 | def run(log, values): 41 | log("Part 1: %d" % (calc(values),)) 42 | log("Part 2: %d" % (calc(values, (11, 0)),)) 43 | 44 | if __name__ == "__main__": 45 | import sys, os 46 | def find_input_file(): 47 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 48 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 49 | cur = os.path.join(*(dn.split("/") + [fn])) 50 | if os.path.isfile(cur): return cur 51 | fn = find_input_file() 52 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 53 | print(f"Using '{fn}' as input file:") 54 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 55 | print(f"Running day {DAY_DESC}:") 56 | run(print, values) 57 | -------------------------------------------------------------------------------- /2016/Helpers/day_16.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 16 4 | DAY_DESC = 'Day 16: Dragon Checksum' 5 | 6 | def calc(values, target_len): 7 | value = values[0] 8 | 9 | while len(value) < target_len: 10 | value = value + "0" + "".join(["1" if x == "0" else "0" for x in reversed(value)]) 11 | 12 | value = value[0:target_len] 13 | 14 | code = { 15 | "00": "1", 16 | "11": "1", 17 | "01": "0", 18 | "10": "0", 19 | } 20 | 21 | while len(value) % 2 != 1: 22 | value = "".join([code[value[x:x+2]] for x in range(0, len(value), 2)]) 23 | 24 | return value 25 | 26 | def test(log): 27 | values = [ 28 | "10000", 29 | ] 30 | 31 | if calc(values, 20) == "01100": 32 | return True 33 | else: 34 | return False 35 | 36 | def run(log, values): 37 | log("Part 1: %s" % (calc(values, 272),)) 38 | log("Part 2: %s" % (calc(values, 35651584),)) 39 | 40 | if __name__ == "__main__": 41 | import sys, os 42 | def find_input_file(): 43 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 44 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 45 | cur = os.path.join(*(dn.split("/") + [fn])) 46 | if os.path.isfile(cur): return cur 47 | fn = find_input_file() 48 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 49 | print(f"Using '{fn}' as input file:") 50 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 51 | print(f"Running day {DAY_DESC}:") 52 | run(print, values) 53 | -------------------------------------------------------------------------------- /2016/Helpers/day_18.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 18 4 | DAY_DESC = 'Day 18: Like a Rogue' 5 | 6 | def calc(values, rows): 7 | ret = 0 8 | row = [0 if x == "^" else 1 for x in values[0]] 9 | its_a_trap = {(0, 0, 1), (1, 0, 0), (0, 1, 1), (1, 1, 0)} 10 | 11 | while rows > 0: 12 | rows -= 1 13 | ret += sum(row) 14 | row = [1] + row + [1] 15 | row = [0 if tuple(row[x-1:x+2]) in its_a_trap else 1 for x in range(1, len(row) - 1)] 16 | 17 | return ret 18 | 19 | def test(log): 20 | values = [ 21 | ".^^.^.^^^^", 22 | ] 23 | 24 | if calc(values, 10) == 38: 25 | return True 26 | else: 27 | return False 28 | 29 | def run(log, values): 30 | for part_no, rows in [(1, 40), (2, 400000)]: 31 | log("Part %d: %d" % (part_no, calc(values, rows))) 32 | 33 | if __name__ == "__main__": 34 | import sys, os 35 | def find_input_file(): 36 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 37 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 38 | cur = os.path.join(*(dn.split("/") + [fn])) 39 | if os.path.isfile(cur): return cur 40 | fn = find_input_file() 41 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 42 | print(f"Using '{fn}' as input file:") 43 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 44 | print(f"Running day {DAY_DESC}:") 45 | run(print, values) 46 | -------------------------------------------------------------------------------- /2016/Helpers/day_19.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import deque 4 | 5 | DAY_NUM = 19 6 | DAY_DESC = 'Day 19: An Elephant Named Joseph' 7 | 8 | def calc2(values): 9 | elves = int(values[0]) 10 | left = deque() 11 | right = deque() 12 | for i in range(1, elves + 1): 13 | if i < (elves / 2) + 1: 14 | left.append(i) 15 | else: 16 | right.appendleft(i) 17 | 18 | while len(left) > 0 and len(right) > 0: 19 | if len(left) > len(right): 20 | left.pop() 21 | else: 22 | right.pop() 23 | 24 | right.appendleft(left.popleft()) 25 | left.append(right.pop()) 26 | 27 | if len(left) > 0: 28 | return left.pop() 29 | else: 30 | return right.pop() 31 | 32 | def calc(values): 33 | elves = int(values[0]) 34 | has_presents = deque(range(1, elves + 1)) 35 | 36 | while len(has_presents) > 1: 37 | has_presents.rotate(-1) 38 | has_presents.popleft() 39 | 40 | return has_presents.pop() 41 | 42 | def test(log): 43 | values = [ 44 | "5", 45 | ] 46 | 47 | if calc(values) == 3: 48 | if calc2(values) == 2: 49 | return True 50 | else: 51 | return False 52 | else: 53 | return False 54 | 55 | def run(log, values): 56 | log("Part 1: " + str(calc(values))) 57 | log("Part 2: " + str(calc2(values))) 58 | 59 | if __name__ == "__main__": 60 | import sys, os 61 | def find_input_file(): 62 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 63 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 64 | cur = os.path.join(*(dn.split("/") + [fn])) 65 | if os.path.isfile(cur): return cur 66 | fn = find_input_file() 67 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 68 | print(f"Using '{fn}' as input file:") 69 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 70 | print(f"Running day {DAY_DESC}:") 71 | run(print, values) 72 | -------------------------------------------------------------------------------- /2016/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_desc(): 4 | return DAY_NUM, 'DAY_TODO' 5 | 6 | 7 | def calc(log, values): 8 | # TODO 9 | return 0 10 | 11 | 12 | def test(log): 13 | values = [ 14 | "TODO", 15 | ] 16 | 17 | if calc(log, values) == 1234: 18 | return True 19 | else: 20 | return False 21 | 22 | 23 | def run(log, values): 24 | log(calc(log, values)) 25 | 26 | if __name__ == "__main__": 27 | import sys, os 28 | def find_input_file(): 29 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 30 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2016/Puzzles"]: 31 | cur = os.path.join(*(dn.split("/") + [fn])) 32 | if os.path.isfile(cur): return cur 33 | fn = find_input_file() 34 | if fn is None: print("Unable to find input file!"); exit(1) 35 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 36 | print(f"Running day {DAY_DESC}:") 37 | run(print, values) 38 | -------------------------------------------------------------------------------- /2016/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2016/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2016/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2016/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2016/Puzzles/favicon.png -------------------------------------------------------------------------------- /2016/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2016/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2016/Puzzles/main_page.png -------------------------------------------------------------------------------- /2016/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2016/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2016/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2016](https://adventofcode.com/2016). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | -------------------------------------------------------------------------------- /2016/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2016 2 | -------------------------------------------------------------------------------- /2016/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2016" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2016/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2017/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: Inverse Captcha' 5 | 6 | def calc(log, values): 7 | value = list(values[0]) 8 | ret = 0 9 | ret2 = 0 10 | 11 | for i in range(len(value)): 12 | if value[i] == value[(i+1)%len(value)]: 13 | ret += int(value[i]) 14 | if value[i] == value[(i+(len(value)//2))%len(value)]: 15 | ret2 += int(value[i]) 16 | 17 | log("Part 2: " + str(ret2)) 18 | 19 | return ret 20 | 21 | def test(log): 22 | values = [ 23 | "91212129", 24 | ] 25 | 26 | if calc(log, values) == 9: 27 | return True 28 | else: 29 | return False 30 | 31 | def run(log, values): 32 | log("Part 1: %d" % (calc(log, values),)) 33 | 34 | if __name__ == "__main__": 35 | import sys, os 36 | def find_input_file(): 37 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 38 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 39 | cur = os.path.join(*(dn.split("/") + [fn])) 40 | if os.path.isfile(cur): return cur 41 | fn = find_input_file() 42 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 43 | print(f"Using '{fn}' as input file:") 44 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 45 | print(f"Running day {DAY_DESC}:") 46 | run(print, values) 47 | -------------------------------------------------------------------------------- /2017/Helpers/day_02.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import itertools 4 | 5 | DAY_NUM = 2 6 | DAY_DESC = 'Day 2: Corruption Checksum' 7 | 8 | def calc(log, values): 9 | values = [[int(y) for y in x.replace('\t', ' ').split(' ')] for x in values] 10 | ret = 0 11 | ret2 = 0 12 | 13 | for row in values: 14 | a, b = min(row), max(row) 15 | ret += b - a 16 | for a, b in itertools.combinations(row, 2): 17 | if b > a: 18 | a, b = b, a 19 | if a % b == 0: 20 | ret2 += a // b 21 | 22 | log("Part 2: " + str(ret2)) 23 | 24 | return ret 25 | 26 | def test(log): 27 | values = [ 28 | "5 1 9 5", 29 | "7 5 3", 30 | "2 4 6 8", 31 | ] 32 | 33 | if calc(log, values) == 18: 34 | return True 35 | else: 36 | return False 37 | 38 | def run(log, values): 39 | log("Part 1: %d" % (calc(log, values),)) 40 | 41 | if __name__ == "__main__": 42 | import sys, os 43 | def find_input_file(): 44 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 45 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 46 | cur = os.path.join(*(dn.split("/") + [fn])) 47 | if os.path.isfile(cur): return cur 48 | fn = find_input_file() 49 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 50 | print(f"Using '{fn}' as input file:") 51 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 52 | print(f"Running day {DAY_DESC}:") 53 | run(print, values) 54 | -------------------------------------------------------------------------------- /2017/Helpers/day_03.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 3 4 | DAY_DESC = 'Day 3: Spiral Memory' 5 | 6 | def calc(log, values): 7 | value = int(values[0]) 8 | cur = 1 9 | x, y = 0, 0 10 | change = 1 11 | 12 | wrote = {(0,0): 1} 13 | 14 | while True: 15 | for dx, dy, inc in ((1, 0, 0), (0, -1, 1), (-1, 0, 0), (0, 1, 1)): 16 | for _ in range(change): 17 | x += dx 18 | y += dy 19 | cur += 1 20 | 21 | if wrote is not None: 22 | write = 0 23 | for ox, oy in ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)): 24 | ox += x 25 | oy += y 26 | write += wrote.get((ox, oy), 0) 27 | if write > value: 28 | log("Part 2: " + str(write)) 29 | wrote = None 30 | if wrote is not None: 31 | wrote[(x, y)] = write 32 | 33 | if cur == value: 34 | return abs(x) + abs(y) 35 | change += inc 36 | 37 | def test(log): 38 | values = [ 39 | "1024", 40 | ] 41 | 42 | if calc(log, values) == 31: 43 | return True 44 | else: 45 | return False 46 | 47 | def run(log, values): 48 | log("Part 1: %d" % (calc(log, values),)) 49 | 50 | if __name__ == "__main__": 51 | import sys, os 52 | def find_input_file(): 53 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 54 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 55 | cur = os.path.join(*(dn.split("/") + [fn])) 56 | if os.path.isfile(cur): return cur 57 | fn = find_input_file() 58 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 59 | print(f"Using '{fn}' as input file:") 60 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 61 | print(f"Running day {DAY_DESC}:") 62 | run(print, values) 63 | -------------------------------------------------------------------------------- /2017/Helpers/day_04.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 4 4 | DAY_DESC = 'Day 4: High-Entropy Passphrases' 5 | 6 | def calc(log, values): 7 | ret = 0 8 | ret2 = 0 9 | for cur in values: 10 | cur = cur.split(' ') 11 | if len(set(cur)) == len(cur): 12 | ret += 1 13 | cur = ["".join(sorted(x)) for x in cur] 14 | if len(set(cur)) == len(cur): 15 | ret2 += 1 16 | 17 | log("Part 2: " + str(ret2)) 18 | 19 | return ret 20 | 21 | def test(log): 22 | return True 23 | 24 | def run(log, values): 25 | log("Part 1: %d" % (calc(log, values),)) 26 | 27 | if __name__ == "__main__": 28 | import sys, os 29 | def find_input_file(): 30 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 31 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 32 | cur = os.path.join(*(dn.split("/") + [fn])) 33 | if os.path.isfile(cur): return cur 34 | fn = find_input_file() 35 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 36 | print(f"Using '{fn}' as input file:") 37 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 38 | print(f"Running day {DAY_DESC}:") 39 | run(print, values) 40 | -------------------------------------------------------------------------------- /2017/Helpers/day_05.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 5 4 | DAY_DESC = 'Day 5: A Maze of Twisty Trampolines, All Alike' 5 | 6 | def calc(log, values, mode): 7 | ip = 0 8 | steps = 0 9 | values = [int(x) for x in values] 10 | 11 | if mode == 0: 12 | while ip < len(values): 13 | next_ip = values[ip] + ip 14 | values[ip] += 1 15 | ip = next_ip 16 | steps += 1 17 | else: 18 | while ip < len(values): 19 | next_ip = values[ip] + ip 20 | if values[ip] >= 3: 21 | values[ip] -= 1 22 | else: 23 | values[ip] += 1 24 | ip = next_ip 25 | steps += 1 26 | 27 | return steps 28 | 29 | def test(log): 30 | values = [ 31 | "0", 32 | "3", 33 | "0", 34 | "1", 35 | "-3", 36 | ] 37 | 38 | if calc(log, values, 0) == 5: 39 | if calc(log, values, 1) == 10: 40 | return True 41 | else: 42 | return False 43 | else: 44 | return False 45 | 46 | def run(log, values): 47 | log("Part 1: %d" % (calc(log, values, 0),)) 48 | log("Part 2: %d" % (calc(log, values, 1),)) 49 | 50 | if __name__ == "__main__": 51 | import sys, os 52 | def find_input_file(): 53 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 54 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 55 | cur = os.path.join(*(dn.split("/") + [fn])) 56 | if os.path.isfile(cur): return cur 57 | fn = find_input_file() 58 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 59 | print(f"Using '{fn}' as input file:") 60 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 61 | print(f"Running day {DAY_DESC}:") 62 | run(print, values) 63 | -------------------------------------------------------------------------------- /2017/Helpers/day_06.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 6 4 | DAY_DESC = 'Day 6: Memory Reallocation' 5 | 6 | def calc(log, values, redo): 7 | banks = [int(x) for x in values[0].replace("\t", " ").split(" ")] 8 | 9 | seen = set() 10 | while True: 11 | key = tuple(banks) 12 | if key in seen: 13 | if redo == 0: 14 | break 15 | else: 16 | seen = set() 17 | redo -= 1 18 | seen.add(key) 19 | i = banks.index(max(banks)) 20 | val = banks[i] 21 | banks[i] = 0 22 | for x in range(val): 23 | banks[(i + 1 + x) % len(banks)] += 1 24 | 25 | return len(seen) 26 | 27 | def test(log): 28 | values = [ 29 | "0 2 7 0", 30 | ] 31 | 32 | if calc(log, values, 0) == 5: 33 | if calc(log, values, 1) == 4: 34 | return True 35 | else: 36 | return False 37 | else: 38 | return False 39 | 40 | def run(log, values): 41 | log("Part 1: %d" % (calc(log, values, 0),)) 42 | log("Part 2: %d" % (calc(log, values, 1),)) 43 | 44 | if __name__ == "__main__": 45 | import sys, os 46 | def find_input_file(): 47 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 48 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 49 | cur = os.path.join(*(dn.split("/") + [fn])) 50 | if os.path.isfile(cur): return cur 51 | fn = find_input_file() 52 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 53 | print(f"Using '{fn}' as input file:") 54 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 55 | print(f"Running day {DAY_DESC}:") 56 | run(print, values) 57 | -------------------------------------------------------------------------------- /2017/Helpers/day_09.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 9 4 | DAY_DESC = 'Day 9: Stream Processing' 5 | 6 | def parse_garb(value, i, removed): 7 | escape = False 8 | while True: 9 | i[0] += 1 10 | if escape: 11 | escape = False 12 | else: 13 | if value[i[0]] == "!": 14 | escape = True 15 | elif value[i[0]] == ">": 16 | return 17 | else: 18 | removed[0] += 1 19 | 20 | def parse(value, i, level, removed): 21 | ret = level 22 | while i[0] < len(value): 23 | i[0] += 1 24 | if value[i[0]] == "{": 25 | ret += parse(value, i, level + 1, removed) 26 | elif value[i[0]] == "<": 27 | parse_garb(value, i, removed) 28 | elif value[i[0]] == "}": 29 | return ret 30 | 31 | def calc(log, values): 32 | removed = [0] 33 | ret = parse(values[0], [0], 1, removed) 34 | log("Part 2: " + str(removed[0])) 35 | return ret 36 | 37 | def test(log): 38 | values = [ 39 | "{{},{},{},{}}", 40 | ] 41 | 42 | if calc(log, values) == 9: 43 | return True 44 | else: 45 | return False 46 | 47 | def run(log, values): 48 | log("Part 1: %d" % (calc(log, values),)) 49 | 50 | if __name__ == "__main__": 51 | import sys, os 52 | def find_input_file(): 53 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 54 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 55 | cur = os.path.join(*(dn.split("/") + [fn])) 56 | if os.path.isfile(cur): return cur 57 | fn = find_input_file() 58 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 59 | print(f"Using '{fn}' as input file:") 60 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 61 | print(f"Running day {DAY_DESC}:") 62 | run(print, values) 63 | -------------------------------------------------------------------------------- /2017/Helpers/day_11.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import deque 4 | 5 | DAY_NUM = 11 6 | DAY_DESC = 'Day 11: Hex Ed' 7 | 8 | def dist(tx, ty): 9 | tx = abs(tx) 10 | ty = abs(ty) 11 | 12 | if ty > tx: 13 | return ty + tx // 2 14 | else: 15 | return tx 16 | 17 | def calc(log, values): 18 | longest = 0 19 | 20 | x, y = 0, 0 21 | left = 0 22 | for cur in values[0].split(","): 23 | left += 1 24 | 25 | for cur in values[0].split(","): 26 | left -= 1 27 | if x % 2 == 0: 28 | offs = {"nw": (-1, -1), "n": (0, -1), "ne": (1, -1), "sw": (-1, 0), "s": (0, 1), "se": (1, 0)} 29 | else: 30 | offs = {"nw": (-1, 0), "n": (0, -1), "ne": (1, 0), "sw": (-1, 1), "s": (0, 1), "se": (1, 1)} 31 | x, y = x + offs[cur][0], y + offs[cur][1] 32 | cur_dist = dist(x, y) 33 | if cur_dist > longest: 34 | longest = cur_dist 35 | 36 | log("Part 2: " + str(longest)) 37 | 38 | return dist(x, y) 39 | 40 | def test(log): 41 | values = [ 42 | "se,sw,se,sw,sw", 43 | ] 44 | 45 | if calc(log, values) == 2: 46 | return True 47 | else: 48 | return False 49 | 50 | def run(log, values): 51 | log("Part 1: %d" % (calc(log, values),)) 52 | 53 | if __name__ == "__main__": 54 | import sys, os 55 | def find_input_file(): 56 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 57 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 58 | cur = os.path.join(*(dn.split("/") + [fn])) 59 | if os.path.isfile(cur): return cur 60 | fn = find_input_file() 61 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 62 | print(f"Using '{fn}' as input file:") 63 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 64 | print(f"Running day {DAY_DESC}:") 65 | run(print, values) 66 | -------------------------------------------------------------------------------- /2017/Helpers/day_17.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import deque 4 | 5 | DAY_NUM = 17 6 | DAY_DESC = 'Day 17: Spinlock' 7 | 8 | def calc(log, values, mode): 9 | value = int(values[0]) 10 | 11 | spin = deque() 12 | spin.append(0) 13 | i = 0 14 | 15 | rounds = 2017 if mode == 0 else 50000000 16 | while rounds > 0: 17 | rounds -= 1 18 | spin.rotate(-value) 19 | i += 1 20 | spin.append(i) 21 | 22 | if mode == 0: 23 | return spin.popleft() 24 | else: 25 | while spin.popleft() != 0: 26 | pass 27 | return spin.popleft() 28 | 29 | def test(log): 30 | values = [ 31 | "3", 32 | ] 33 | 34 | if calc(log, values, 0) == 638: 35 | return True 36 | else: 37 | return False 38 | 39 | def run(log, values): 40 | log("Part 1: %d" % (calc(log, values, 0),)) 41 | log("Part 2: %d" % (calc(log, values, 1),)) 42 | 43 | if __name__ == "__main__": 44 | import sys, os 45 | def find_input_file(): 46 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 47 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 48 | cur = os.path.join(*(dn.split("/") + [fn])) 49 | if os.path.isfile(cur): return cur 50 | fn = find_input_file() 51 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 52 | print(f"Using '{fn}' as input file:") 53 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 54 | print(f"Running day {DAY_DESC}:") 55 | run(print, values) 56 | -------------------------------------------------------------------------------- /2017/Helpers/day_19.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 19 4 | DAY_DESC = 'Day 19: A Series of Tubes' 5 | 6 | def calc(log, values): 7 | y = 0 8 | for x in range(len(values[0])): 9 | if values[0][x] == "|": 10 | break 11 | 12 | dx, dy = 0, 1 13 | ret = "" 14 | steps = 0 15 | 16 | while True: 17 | x, y = x + dx, y + dy 18 | steps += 1 19 | 20 | if values[y][x] == "+": 21 | for ox, oy in ((-1, 0), (1, 0), (0, -1), (0, 1)): 22 | if (ox, oy) != (-dx, -dy) and values[y + oy][x + ox] != ' ': 23 | dx, dy = ox, oy 24 | break 25 | elif values[y][x] == " ": 26 | break 27 | elif values[y][x] not in {"-", "|"}: 28 | ret += values[y][x] 29 | 30 | log("Part 2: " + str(steps)) 31 | 32 | return ret 33 | 34 | def test(log): 35 | values = [ 36 | " | ", 37 | " | +--+ ", 38 | " A | C ", 39 | " F---|----E|--+ ", 40 | " | | | D ", 41 | " +B-+ +--+ ", 42 | " ", 43 | ] 44 | 45 | if calc(log, values) == "ABCDEF": 46 | return True 47 | else: 48 | return False 49 | 50 | def run(log, values): 51 | log("Part 1: %s" % (calc(log, values),)) 52 | 53 | if __name__ == "__main__": 54 | import sys, os 55 | def find_input_file(): 56 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 57 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 58 | cur = os.path.join(*(dn.split("/") + [fn])) 59 | if os.path.isfile(cur): return cur 60 | fn = find_input_file() 61 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 62 | print(f"Using '{fn}' as input file:") 63 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 64 | print(f"Running day {DAY_DESC}:") 65 | run(print, values) 66 | -------------------------------------------------------------------------------- /2017/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_desc(): 4 | return DAY_NUM, 'DAY_TODO' 5 | 6 | 7 | def calc(log, values): 8 | # TODO 9 | return 0 10 | 11 | 12 | def test(log): 13 | values = [ 14 | "TODO", 15 | ] 16 | 17 | if calc(log, values) == 1234: 18 | return True 19 | else: 20 | return False 21 | 22 | 23 | def run(log, values): 24 | log(calc(log, values)) 25 | 26 | if __name__ == "__main__": 27 | import sys, os 28 | def find_input_file(): 29 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 30 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2017/Puzzles"]: 31 | cur = os.path.join(*(dn.split("/") + [fn])) 32 | if os.path.isfile(cur): return cur 33 | fn = find_input_file() 34 | if fn is None: print("Unable to find input file!"); exit(1) 35 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 36 | print(f"Running day {DAY_DESC}:") 37 | run(print, values) 38 | -------------------------------------------------------------------------------- /2017/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2017/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2017/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2017/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2017/Puzzles/favicon.png -------------------------------------------------------------------------------- /2017/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2017/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2017/Puzzles/main_page.png -------------------------------------------------------------------------------- /2017/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2017/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2017/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2017](https://adventofcode.com/2017). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | -------------------------------------------------------------------------------- /2017/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2017 2 | -------------------------------------------------------------------------------- /2017/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2017" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2017/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2018/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: Chronal Calibration' 5 | 6 | def calc(log, values, test_mode): 7 | ret = 0 8 | real_ret = None 9 | seen = {} 10 | first = True 11 | while first: 12 | for value in values: 13 | ret += value 14 | seen[ret] = seen.get(ret, 0) + 1 15 | if first: 16 | if seen[ret] == 2: 17 | log("Part 2: %d" % (ret,)) 18 | first = False 19 | if real_ret is None: 20 | real_ret = ret 21 | if test_mode: 22 | break 23 | return real_ret 24 | 25 | def test(log): 26 | test = [ 27 | ("+1, +1, +1", 3), 28 | ("+1, +1, -2", 0), 29 | ("-1, -2, -3", -6), 30 | ] 31 | for value, ret in test: 32 | values = [int(x.strip()) for x in value.split(', ')] 33 | test_val = calc(log, values, True) 34 | log("[%s] -> %d, %d" % (value, ret, test_val)) 35 | if ret != test_val: 36 | return False 37 | 38 | return True 39 | 40 | def run(log, values): 41 | values = [int(x) for x in values] 42 | log("Part 1: %d" % (calc(log, values, False),)) 43 | 44 | if __name__ == "__main__": 45 | import sys, os 46 | def find_input_file(): 47 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 48 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2018/Puzzles"]: 49 | cur = os.path.join(*(dn.split("/") + [fn])) 50 | if os.path.isfile(cur): return cur 51 | fn = find_input_file() 52 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 53 | print(f"Using '{fn}' as input file:") 54 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 55 | print(f"Running day {DAY_DESC}:") 56 | run(print, values) 57 | -------------------------------------------------------------------------------- /2018/Helpers/day_05.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 5 4 | DAY_DESC = 'Day 5: Alchemical Reduction' 5 | 6 | def decode(polymer): 7 | found = True 8 | i = 0 9 | while found: 10 | found = False 11 | while i < len(polymer) - 1: 12 | a, b = list(polymer[i:i+2]) 13 | if a != b and a.lower() == b.lower(): 14 | polymer = polymer[0:i] + polymer[i+2:] 15 | found = True 16 | if i > 0: 17 | i -= 1 18 | break 19 | i += 1 20 | 21 | return len(polymer) 22 | 23 | def calc(log, values): 24 | polymer = values[0] 25 | values = set() 26 | for cur in polymer: 27 | values.add(cur.lower()) 28 | 29 | best = None 30 | best_val = None 31 | for cur in values: 32 | test = decode(polymer.replace(cur, "").replace(cur.upper(), "")) 33 | if best is None or test < best: 34 | best = test 35 | best_val = cur 36 | 37 | log("Part 2: %d" % (best,)) 38 | 39 | return decode(polymer) 40 | 41 | def test(log): 42 | values = [ 43 | "dabAcCaCBAcCcaDA", 44 | ] 45 | 46 | if calc(log, values) == 10: 47 | return True 48 | else: 49 | return False 50 | 51 | def run(log, values): 52 | log("Part 1: %d" % (calc(log, values),)) 53 | 54 | if __name__ == "__main__": 55 | import sys, os 56 | def find_input_file(): 57 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 58 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2018/Puzzles"]: 59 | cur = os.path.join(*(dn.split("/") + [fn])) 60 | if os.path.isfile(cur): return cur 61 | fn = find_input_file() 62 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 63 | print(f"Using '{fn}' as input file:") 64 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 65 | print(f"Running day {DAY_DESC}:") 66 | run(print, values) 67 | -------------------------------------------------------------------------------- /2018/Helpers/day_09.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import defaultdict, deque 4 | 5 | DAY_NUM = 9 6 | DAY_DESC = 'Day 9: Marble Mania' 7 | 8 | def calc(players, marbles): 9 | board = deque([0]) 10 | player_scores = defaultdict(int) 11 | cur_player = 0 12 | 13 | for i in range(1, marbles + 1): 14 | if i % 23 == 0: 15 | board.rotate(7) 16 | removed = board.pop() 17 | board.rotate(-1) 18 | 19 | player_scores[cur_player] += removed 20 | player_scores[cur_player] += i 21 | else: 22 | board.rotate(-1) 23 | board.append(i) 24 | cur_player = (cur_player + 1) % players 25 | 26 | return max(player_scores.values()) 27 | 28 | def test(log): 29 | if calc(9, 25) == 32: 30 | return True 31 | else: 32 | return False 33 | 34 | def run(log, values): 35 | import re 36 | m = re.search("(?P[0-9]+) players; last marble is worth (?P[0-9]+) points", values[0]) 37 | log("Part 1: %d" % (calc(int(m['a']), int(m['b'])),)) 38 | log("Part 2: %d" % (calc(int(m['a']), int(m['b']) * 100),)) 39 | 40 | if __name__ == "__main__": 41 | import sys, os 42 | def find_input_file(): 43 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 44 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2018/Puzzles"]: 45 | cur = os.path.join(*(dn.split("/") + [fn])) 46 | if os.path.isfile(cur): return cur 47 | fn = find_input_file() 48 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 49 | print(f"Using '{fn}' as input file:") 50 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 51 | print(f"Running day {DAY_DESC}:") 52 | run(print, values) 53 | -------------------------------------------------------------------------------- /2018/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_desc(): 4 | return DAY_NUM, 'DAY_TODO' 5 | 6 | 7 | def calc(log, values): 8 | # TODO 9 | return 0 10 | 11 | 12 | def test(log): 13 | values = [ 14 | "TODO", 15 | ] 16 | 17 | if calc(log, values) == 1234: 18 | return True 19 | else: 20 | return False 21 | 22 | 23 | def run(log, values): 24 | log(calc(log, values)) 25 | 26 | if __name__ == "__main__": 27 | import sys, os 28 | def find_input_file(): 29 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 30 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2018/Puzzles"]: 31 | cur = os.path.join(*(dn.split("/") + [fn])) 32 | if os.path.isfile(cur): return cur 33 | fn = find_input_file() 34 | if fn is None: print("Unable to find input file!"); exit(1) 35 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 36 | print(f"Running day {DAY_DESC}:") 37 | run(print, values) 38 | -------------------------------------------------------------------------------- /2018/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2018/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2018/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2018/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2018/Puzzles/favicon.png -------------------------------------------------------------------------------- /2018/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2018/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2018/Puzzles/main_page.png -------------------------------------------------------------------------------- /2018/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2018/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2018/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2018](https://adventofcode.com/2018). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | -------------------------------------------------------------------------------- /2018/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2018 2 | -------------------------------------------------------------------------------- /2018/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2018" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2018/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2019/Helpers/Font-DSEG14Classic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/Helpers/Font-DSEG14Classic-Bold.ttf -------------------------------------------------------------------------------- /2019/Helpers/Font-SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/Helpers/Font-SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /2019/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: The Tyranny of the Rocket Equation' 5 | 6 | def calc(log, values, mode): 7 | ret = 0 8 | for cur in values: 9 | if mode == 1: 10 | ret += (int(cur) // 3) - 2 11 | else: 12 | first = True 13 | while True: 14 | temp = (int(cur) // 3) - 2 15 | if temp > 0 or first: 16 | ret += temp 17 | first = False 18 | if temp > 0: 19 | cur = temp 20 | else: 21 | break 22 | 23 | return ret 24 | 25 | def test(log): 26 | values = log.decode_values(""" 27 | 100756 28 | """) 29 | 30 | ret, expected = calc(log, values, 1), 33583 31 | log("Test returned %s, expected %s" % (str(ret), str(expected))) 32 | if ret != expected: 33 | return False 34 | ret, expected = calc(log, values, 2), 50346 35 | log("Test returned %s, expected %s" % (str(ret), str(expected))) 36 | if ret != expected: 37 | return False 38 | 39 | return True 40 | 41 | def run(log, values): 42 | log("Part 1: " + str(calc(log, values, 1))) 43 | log("Part 2: " + str(calc(log, values, 2))) 44 | 45 | if __name__ == "__main__": 46 | import sys, os 47 | def find_input_file(): 48 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 49 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2019/Puzzles"]: 50 | cur = os.path.join(*(dn.split("/") + [fn])) 51 | if os.path.isfile(cur): return cur 52 | fn = find_input_file() 53 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 54 | print(f"Using '{fn}' as input file:") 55 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 56 | print(f"Running day {DAY_DESC}:") 57 | run(print, values) 58 | -------------------------------------------------------------------------------- /2019/Helpers/day_05.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 5 4 | DAY_DESC = 'Day 5: Sunny with a Chance of Asteroids' 5 | 6 | def calc(log, values, input_val): 7 | from program import Program 8 | 9 | prog = Program.from_values(values, log) 10 | prog.add_to_input(input_val) 11 | prog.tick_till_end() 12 | return prog.last_output 13 | 14 | def test(log): 15 | values = log.decode_values(""" 16 | 1002,4,3,4,33 17 | """) 18 | 19 | ret, expected = calc(log, values, 1), None 20 | log("Test returned %s, expected %s" % (str(ret), str(expected))) 21 | if ret != expected: 22 | return False 23 | 24 | return True 25 | 26 | def run(log, values): 27 | log("Part 1: " + str(calc(log, values, 1))) 28 | log("Part 2: " + str(calc(log, values, 5))) 29 | 30 | if __name__ == "__main__": 31 | import sys, os 32 | def find_input_file(): 33 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 34 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2019/Puzzles"]: 35 | cur = os.path.join(*(dn.split("/") + [fn])) 36 | if os.path.isfile(cur): return cur 37 | fn = find_input_file() 38 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 39 | print(f"Using '{fn}' as input file:") 40 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 41 | print(f"Running day {DAY_DESC}:") 42 | run(print, values) 43 | -------------------------------------------------------------------------------- /2019/Helpers/day_09.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 9 4 | DAY_DESC = 'Day 9: Sensor Boost' 5 | 6 | def calc(log, values, first_input): 7 | from program import Program 8 | 9 | ticker = [int(x) for x in values[0].split(",")] 10 | 11 | prog = Program(ticker, log) 12 | prog.add_to_input(first_input) 13 | prog.tick_till_end() 14 | 15 | return ",".join([str(x) for x in list(prog.output)[::-1]]) 16 | 17 | def test(log): 18 | values = log.decode_values(""" 19 | 109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99 20 | """) 21 | 22 | ret, expected = calc(log, values, 0), values[0] 23 | log("Test returned\n '%s'\nExpected\n '%s'" % (str(ret), str(expected))) 24 | if ret != expected: 25 | return False 26 | 27 | return True 28 | 29 | def run(log, values): 30 | log("Part 1: " + str(calc(log, values, 1))) 31 | log("Part 2: " + str(calc(log, values, 2))) 32 | 33 | if __name__ == "__main__": 34 | import sys, os 35 | def find_input_file(): 36 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 37 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2019/Puzzles"]: 38 | cur = os.path.join(*(dn.split("/") + [fn])) 39 | if os.path.isfile(cur): return cur 40 | fn = find_input_file() 41 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 42 | print(f"Using '{fn}' as input file:") 43 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 44 | print(f"Running day {DAY_DESC}:") 45 | run(print, values) 46 | -------------------------------------------------------------------------------- /2019/Helpers/day_21.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 21 4 | DAY_DESC = 'Day 21: Springdroid Adventure' 5 | 6 | def calc(log, values, walk): 7 | from program import Program 8 | prog = Program.from_values(values, log) 9 | 10 | def sb(value, use=True): 11 | if use: 12 | for cur in value + "\n": 13 | prog.add_to_input(ord(cur)) 14 | 15 | sb("NOT A J") 16 | sb("NOT B T") 17 | sb("AND H T", not walk) 18 | sb("OR T J") 19 | sb("NOT C T") 20 | sb("AND H T", not walk) 21 | sb("OR T J") 22 | sb("AND D J") 23 | 24 | sb("WALK" if walk else "RUN") 25 | 26 | prog.tick_till_end() 27 | 28 | output = [""] 29 | while len(prog.output) > 0: 30 | value = prog.get_output() 31 | if value > 128: 32 | return value 33 | else: 34 | if value == 10: 35 | output.append("") 36 | else: 37 | output[-1] += chr(value) 38 | 39 | for cur in output: 40 | log(cur) 41 | 42 | return "ERROR" 43 | 44 | def test(log): 45 | return True 46 | 47 | def run(log, values): 48 | log("Part 1: " + str(calc(log, values, True))) 49 | log("Part 2: " + str(calc(log, values, False))) 50 | 51 | if __name__ == "__main__": 52 | import sys, os 53 | def find_input_file(): 54 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 55 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2019/Puzzles"]: 56 | cur = os.path.join(*(dn.split("/") + [fn])) 57 | if os.path.isfile(cur): return cur 58 | fn = find_input_file() 59 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 60 | print(f"Using '{fn}' as input file:") 61 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 62 | print(f"Running day {DAY_DESC}:") 63 | run(print, values) 64 | -------------------------------------------------------------------------------- /2019/Helpers/dummylog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | class DummyLog: 4 | def __init__(self): 5 | pass 6 | 7 | def show(self, value): 8 | print(value) 9 | 10 | def __call__(self, value): 11 | print(value) 12 | -------------------------------------------------------------------------------- /2019/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_desc(): 4 | return DAY_NUM, 'DAY_TODO' 5 | 6 | 7 | def calc(log, values): 8 | # from grid import Grid 9 | # grid = Grid() 10 | # from program import Program 11 | # prog = Program.from_values(values, log) 12 | 13 | # TODO 14 | return 0 15 | 16 | 17 | def test(log): 18 | values = log.decode_values(""" 19 | TODO 20 | """) 21 | 22 | ret, expected = calc(log, values), 1234 23 | log("Test returned %s, expected %s" % (str(ret), str(expected))) 24 | if ret != expected: 25 | return False 26 | 27 | return True 28 | 29 | 30 | def run(log, values): 31 | log(calc(log, values)) 32 | 33 | if __name__ == "__main__": 34 | import sys, os 35 | def find_input_file(): 36 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 37 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2019/Puzzles"]: 38 | cur = os.path.join(*(dn.split("/") + [fn])) 39 | if os.path.isfile(cur): return cur 40 | fn = find_input_file() 41 | if fn is None: print("Unable to find input file!"); exit(1) 42 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 43 | print(f"Running day {DAY_DESC}:") 44 | run(print, values) 45 | -------------------------------------------------------------------------------- /2019/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2019/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2019/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/Puzzles/favicon.png -------------------------------------------------------------------------------- /2019/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2019/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/Puzzles/main_page.png -------------------------------------------------------------------------------- /2019/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2019/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2019](https://adventofcode.com/2019). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | 7 | Some visualizations for your viewing pleasure: 8 | 9 | * Day 10: [Monitoring Station](https://youtu.be/g13m23MKyMY) 10 | * Day 11: [Space Police](https://youtu.be/7OOVKy46o0U) 11 | * Day 13: [Care Package](https://youtu.be/qYlukN2nLfo) 12 | * Day 15: [Visualizing the robot and oxygen](https://youtu.be/DP7HRHQFqAU) 13 | * Day 17: [Set and Forget](https://youtu.be/DJYUQx7PG_4) 14 | * Day 18: [Many-Worlds Interpretation](https://youtu.be/Tao6Nge87bk) 15 | * Day 20: [Digging into all of the mazes](https://youtu.be/Wwt42Hx7Am0) 16 | * Day 23: [Watching the network traffic](https://youtu.be/MsPq_qKokBs) 17 | * Day 24: [Multi-dimensional Game of Life](https://youtu.be/sVxj-QwCvKA) 18 | * Day 25: [One last run through the maze](https://youtu.be/l4XM85T6fMM) 19 | -------------------------------------------------------------------------------- /2019/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2019 2 | -------------------------------------------------------------------------------- /2019/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2019" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2019/animations/animation_10.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_10.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_11.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_11.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_13.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_13.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_15.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_15.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_17.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_17.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_18.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_18.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_20.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_20.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_23.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_23.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_24.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_24.mp4 -------------------------------------------------------------------------------- /2019/animations/animation_25.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2019/animations/animation_25.mp4 -------------------------------------------------------------------------------- /2019/other/day_23/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /2019/other/day_23/DrawNetwork.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DrawNetwork", "DrawNetwork.csproj", "{6EB1EC04-1BF5-4DE5-B06A-FD23B66C4DEA}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {6EB1EC04-1BF5-4DE5-B06A-FD23B66C4DEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {6EB1EC04-1BF5-4DE5-B06A-FD23B66C4DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {6EB1EC04-1BF5-4DE5-B06A-FD23B66C4DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {6EB1EC04-1BF5-4DE5-B06A-FD23B66C4DEA}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {FEBAA846-FDEC-4892-83DD-6AED31791344} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /2019/other/day_23/MyObj.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DrawNetwork 8 | { 9 | class MyObj 10 | { 11 | public string Name; 12 | public double Xa; 13 | public double Ya; 14 | public double Xb; 15 | public double Yb; 16 | public int Framea; 17 | public int Frameb; 18 | public int Type; 19 | 20 | public double X(int frame) 21 | { 22 | if (Framea == -1) 23 | { 24 | return Xa; 25 | } 26 | var perc = ((double)(frame - Framea)) / ((double)(Frameb - Framea)); 27 | return Xa * (1.0 - perc) + Xb * perc; 28 | } 29 | 30 | public double Y(int frame) 31 | { 32 | if (Framea == -1) 33 | { 34 | return Ya; 35 | } 36 | var perc = ((double)(frame - Framea)) / ((double)(Frameb - Framea)); 37 | return Ya * (1.0 - perc) + Yb * perc; 38 | } 39 | 40 | public bool IsVisible(int frame) 41 | { 42 | if (Framea == -1) 43 | { 44 | return true; 45 | } 46 | if (frame >= Framea && frame < Frameb) 47 | { 48 | return true; 49 | } 50 | return false; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /2019/other/day_23/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace DrawNetwork 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new NetworkForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /2019/other/day_23/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DrawNetwork")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DrawNetwork")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6eb1ec04-1bf5-4de5-b06a-fd23b66c4dea")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /2019/other/day_23/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DrawNetwork.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /2019/other/day_23/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /2019/other/mand_intcode/christmas_note.txt: -------------------------------------------------------------------------------- 1 | And, I'll leave a small [intcode program that outputs ASCII](https://topaz.github.io/paste/#XQAAAQA8BAAAAAAAAAAYiwKH5EyZok3aHbDk608JxYVPfEtrHgvHAW5WthJWT/Veuuz5Wzo8/tyxrHUYQVrLi2kEvoCkrLNfsDmtakE8FXgljlwotk9+4W1dPPYErIKex3nNgUZuxL25kiRb1gA2cvDRAnTz6AsKNDwbgujj/BiYSPnbMdMMP9+FrcgaxFuW2MeGKlne1isO8TvAYTTVyBzYUWHnRkowwximigvIILKGPGowxTwsahfUJFYGjwUxRMw/Q5gggQjlJQwG+yDhgkcC3pvtN36k8lNYCj2qMKhbVwXyxEzzwVnlkABKvn1RLjSQMlfdzKKnVhyaEqac7brwdH5tdIGkdBm/nA6FQLGfbkTh0PQ2bIXxFmSdMM7ZeS1sfFlPrSN2Y868NjPEUhjkH7f6am22zUfG8gmURKngba54zqPB0xE0s07sld6TymEwk/2h7+2V9eE7HiEcQlOhmwo75OPAU+b6XZJ5rAaK0fwf89sfyf9RQukA) to run. Mac and Linux users can change the first value from 1 to 2 to see it in color. 2 | -------------------------------------------------------------------------------- /2019/other/mand_intcode/make_ascii_chart.html: -------------------------------------------------------------------------------- 1 |
 2 |         .---_
 3 |        / / /\|
 4 |      / / | \ *
 5 |     /  /  \ \   MERRY CHRISTMAS!
 6 |    / /  / \  \   -- seligman99
 7 |  ./~~~~~~~~~~~\.
 8 | ( .",^. -". '.~ )
 9 |  '~~~~~~~~~~~~~'
10 | 
-------------------------------------------------------------------------------- /2019/other/mand_intcode/mandelbrot_intcode.txt: -------------------------------------------------------------------------------- 1 | 1101,0,-53,203,1101,0,-37,204,1101,0,-1,205,1007,205,15,202,1006,202,104,1001,205,1,205,2,204,204,202,1002,202,-1,202,2,203,203,206,1,206,202,206,2,203,204,207,1002,207,2,207,101,0,206,209,1101,0,25,210,1101,0,62,212,1105,1,155,1,211,2,203,101,0,207,209,1101,0,25,210,1101,0,81,212,1105,1,155,1,211,6,204,2,203,203,206,2,204,204,202,1,206,202,202,1007,202,15625,202,1005,202,12,4,2,4,6,1008,205,15,202,1005,202,122,1001,205,96,205,1006,202,126,1101,0,32,205,4,205,1001,2,1,2,1007,2,22,202,1005,202,0,1101,0,-53,2,1001,6,1,6,1007,6,38,202,1005,202,0,99,102,-1,210,210,1007,209,0,208,1006,208,170,102,-1,209,209,1101,0,0,211,1007,209,1,202,1005,202,192,1001,211,1,211,1,209,210,209,1006,202,174,6,208,212,102,-1,211,211,105,1,212 -------------------------------------------------------------------------------- /2019/other/mand_intcode/merry_xmas_int.txt: -------------------------------------------------------------------------------- 1 | 1,142,142,317,1101,0,11,320,1105,1,136,1008,319,99,318,1005,318,120,1008,319,100,318,1006,318,76,1008,317,2,318,1006,318,49,1101,0,39,320,1105,1,136,1101,0,46,320,1105,1,136,1105,1,4,1101,0,56,320,1105,1,136,104,27,104,91,4,319,1101,0,69,320,1105,1,136,4,319,104,109,1105,1,4,1007,319,100,318,1005,318,99,4,316,1001,319,-1,319,1007,319,100,318,1006,318,83,1105,1,4,1,316,319,316,1008,316,31,318,1005,318,115,4,316,1105,1,4,104,10,1105,1,4,1008,317,2,318,1005,318,135,104,27,104,91,4,48,104,109,99,1001,147,0,319,1001,137,1,137,105,1,320,100,57,49,1,106,14,-1,101,50,-64,1,105,15,-15,100,51,49,15,-15,100,57,49,15,45,32,-93,1,103,15,-15,100,51,49,15,-15,92,-92,100,57,49,60,-60,100,57,51,10,-11,1,102,100,57,49,15,-15,0,100,51,49,15,-15,0,60,-60,100,57,49,60,-60,101,45,-8,13,0,7,-57,100,57,50,35,5,10,-9,10,1,-7,-12,18,100,57,55,-50,-2,1,101,100,57,49,15,-15,100,51,49,15,-15,0,15,-15,60,-60,0,100,57,49,60,-60,101,100,57,48,13,0,-13,83,-14,7,-3,-2,6,-12,13,-53,0,-26,1,100,57,55,14,1,79,109,-34,-46,-15,9,-8,14,-12,10,50,-48,-14,13,-11,12,-14,7,7,80,-94,9,-10,1,7,87,111,-87,-8,99,31 -------------------------------------------------------------------------------- /2019/other/mand_intcode/runner_ascii.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | from datetime import datetime, timedelta 5 | import os 6 | 7 | def main(lines): 8 | sys.path.insert(0, os.path.join('..', '..', 'Helpers')) 9 | 10 | from program import Program 11 | from dummylog import DummyLog 12 | 13 | #Program.debug(lines) 14 | p = Program([int(x) for x in lines.split(",")], DummyLog()) 15 | while p.flag_running: 16 | p.tick() 17 | while len(p.output) > 0: 18 | sys.stdout.write(chr(p.get_output())) 19 | sys.stdout.flush() 20 | 21 | if __name__ == "__main__": 22 | with open(sys.argv[1]) as f: 23 | main(f.read()) 24 | -------------------------------------------------------------------------------- /2019/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2020/.gitignore: -------------------------------------------------------------------------------- 1 | /*.png 2 | /*.mp4 3 | -------------------------------------------------------------------------------- /2020/Helpers/Font-DSEG14Classic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/Helpers/Font-DSEG14Classic-Bold.ttf -------------------------------------------------------------------------------- /2020/Helpers/Font-SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/Helpers/Font-SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /2020/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: Report Repair' 5 | 6 | def calc(log, values, mode): 7 | values = [int(x) for x in values] 8 | 9 | if mode == 1: 10 | for x in range(len(values)): 11 | for y in range(x + 1, len(values)): 12 | if values[x] + values[y] == 2020: 13 | return values[x] * values[y] 14 | else: 15 | for x in range(len(values)): 16 | for y in range(x + 1, len(values)): 17 | for z in range(y + 1, len(values)): 18 | if values[x] + values[y] + values[z] == 2020: 19 | return values[x] * values[y] * values[z] 20 | 21 | return 10 22 | 23 | def test(log): 24 | values = log.decode_values(""" 25 | 1721 26 | 979 27 | 366 28 | 299 29 | 675 30 | 1456 31 | """) 32 | 33 | log.test(calc(log, values, 1), 514579) 34 | log.test(calc(log, values, 2), 241861950) 35 | 36 | def run(log, values): 37 | log(f"Part 1: {calc(log, values, 1)}") 38 | log(f"Part 2: {calc(log, values, 2)}") 39 | 40 | if __name__ == "__main__": 41 | import sys, os 42 | def find_input_file(): 43 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 44 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 45 | cur = os.path.join(*(dn.split("/") + [fn])) 46 | if os.path.isfile(cur): return cur 47 | fn = find_input_file() 48 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 49 | print(f"Using '{fn}' as input file:") 50 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 51 | print(f"Running day {DAY_DESC}:") 52 | run(print, values) 53 | -------------------------------------------------------------------------------- /2020/Helpers/day_02.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | from collections import defaultdict 5 | 6 | DAY_NUM = 2 7 | DAY_DESC = 'Day 2: Password Philosophy' 8 | 9 | def calc(log, values, mode): 10 | r = re.compile("([0-9]+)-([0-9]+) ([a-z]): ([a-z]+)") 11 | ret = 0 12 | for cur in values: 13 | m = r.search(cur) 14 | a, b = int(m.group(1)), int(m.group(2)) 15 | target = m.group(3) 16 | pw = m.group(4) 17 | 18 | if mode == 1: 19 | counts = defaultdict(int) 20 | for x in pw: 21 | counts[x] += 1 22 | if counts[target] >= a and counts[target] <= b: 23 | ret += 1 24 | else: 25 | if (pw[a-1] == target and pw[b-1] != target) or (pw[a-1] != target and pw[b-1] == target): 26 | ret += 1 27 | 28 | return ret 29 | 30 | def test(log): 31 | values = log.decode_values(""" 32 | 1-3 a: abcde 33 | 1-3 b: cdefg 34 | 2-9 c: ccccccccc 35 | """) 36 | 37 | log.test(calc(log, values, 1), 2) 38 | log.test(calc(log, values, 2), 1) 39 | 40 | def run(log, values): 41 | log(f"Part 1: {calc(log, values, 1)}") 42 | log(f"Part 2: {calc(log, values, 2)}") 43 | 44 | if __name__ == "__main__": 45 | import sys, os 46 | def find_input_file(): 47 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 48 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 49 | cur = os.path.join(*(dn.split("/") + [fn])) 50 | if os.path.isfile(cur): return cur 51 | fn = find_input_file() 52 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 53 | print(f"Using '{fn}' as input file:") 54 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 55 | print(f"Running day {DAY_DESC}:") 56 | run(print, values) 57 | -------------------------------------------------------------------------------- /2020/Helpers/day_03.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 3 4 | DAY_DESC = 'Day 3: Toboggan Trajectory' 5 | 6 | def calc(log, values, mode): 7 | from grid import Grid 8 | grid = Grid.from_text(values) 9 | ret = [] 10 | 11 | if mode == 1: 12 | passes = [[3,1]] 13 | else: 14 | passes = [[1,1],[3,1],[5,1],[7,1],[1,2]] 15 | for step_x, step_y in passes: 16 | ret.append(0) 17 | x, y = 0, 0 18 | while True: 19 | x += step_x 20 | y += step_y 21 | x = x % grid.width() 22 | if y >= grid.height(): 23 | break 24 | if grid[x, y] == "#": 25 | ret[-1] += 1 26 | 27 | value = 1 28 | for x in ret: 29 | value *= x 30 | 31 | return value 32 | 33 | def test(log): 34 | values = log.decode_values(""" 35 | ..##....... 36 | #...#...#.. 37 | .#....#..#. 38 | ..#.#...#.# 39 | .#...##..#. 40 | ..#.##..... 41 | .#.#.#....# 42 | .#........# 43 | #.##...#... 44 | #...##....# 45 | .#..#...#.# 46 | """) 47 | 48 | log.test(calc(log, values, 1), 7) 49 | log.test(calc(log, values, 2), 336) 50 | 51 | def run(log, values): 52 | log(f"Part 1: {calc(log, values, 1)}") 53 | log(f"Part 2: {calc(log, values, 2)}") 54 | 55 | if __name__ == "__main__": 56 | import sys, os 57 | def find_input_file(): 58 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 59 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 60 | cur = os.path.join(*(dn.split("/") + [fn])) 61 | if os.path.isfile(cur): return cur 62 | fn = find_input_file() 63 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 64 | print(f"Using '{fn}' as input file:") 65 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 66 | print(f"Running day {DAY_DESC}:") 67 | run(print, values) 68 | -------------------------------------------------------------------------------- /2020/Helpers/day_06.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import defaultdict 4 | 5 | DAY_NUM = 6 6 | DAY_DESC = 'Day 6: Custom Customs' 7 | 8 | def calc(log, values, mode): 9 | total_answers = 0 10 | this_group = defaultdict(int) 11 | for value in values + [""]: 12 | if len(value) == 0: 13 | if len(this_group) > 0: 14 | if mode == 1: 15 | total_answers += len(this_group) - 1 16 | else: 17 | total_answers += len([x for x in this_group if this_group[x] == this_group['people']]) - 1 18 | this_group = defaultdict(int) 19 | else: 20 | for answer in value: 21 | this_group[answer] += 1 22 | this_group['people'] += 1 23 | 24 | return total_answers 25 | 26 | def test(log): 27 | values = log.decode_values(""" 28 | abc 29 | 30 | a 31 | b 32 | c 33 | 34 | ab 35 | ac 36 | 37 | a 38 | a 39 | a 40 | a 41 | 42 | b 43 | """) 44 | 45 | log.test(calc(log, values, 1), 11) 46 | log.test(calc(log, values, 2), 6) 47 | 48 | def run(log, values): 49 | log(f"Part 1: {calc(log, values, 1)}") 50 | log(f"Part 2: {calc(log, values, 2)}") 51 | 52 | if __name__ == "__main__": 53 | import sys, os 54 | def find_input_file(): 55 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 56 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 57 | cur = os.path.join(*(dn.split("/") + [fn])) 58 | if os.path.isfile(cur): return cur 59 | fn = find_input_file() 60 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 61 | print(f"Using '{fn}' as input file:") 62 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 63 | print(f"Running day {DAY_DESC}:") 64 | run(print, values) 65 | -------------------------------------------------------------------------------- /2020/Helpers/day_15.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import defaultdict, deque 4 | 5 | DAY_NUM = 15 6 | DAY_DESC = 'Day 15: Rambunctious Recitation' 7 | 8 | def calc(log, values, mode): 9 | numbers = [int(x) for x in values[0].split(",")] 10 | 11 | said = {} 12 | last = None 13 | 14 | for i in range(len(numbers)): 15 | said[last], last = i, numbers[i] 16 | 17 | for i in range(len(numbers), 2020 if mode == 1 else 30000000): 18 | said[last], last = i, i - said.get(last, i) 19 | if (mode == 1 and i % 1000 == 19) or (mode == 2 and i % 5000000 == 999999): 20 | log(f"For round {i:8d}, {last:8d} was said") 21 | 22 | return last 23 | 24 | def test(log): 25 | values = log.decode_values(""" 26 | 0,3,6 27 | """) 28 | 29 | log.test(calc(log, values, 1), 436) 30 | # log.test(calc(log, values, 2), 175594) 31 | 32 | def run(log, values): 33 | log(f"Part 1: {calc(log, values, 1)}") 34 | log(f"Part 2: {calc(log, values, 2)}") 35 | 36 | if __name__ == "__main__": 37 | import sys, os 38 | def find_input_file(): 39 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 40 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 41 | cur = os.path.join(*(dn.split("/") + [fn])) 42 | if os.path.isfile(cur): return cur 43 | fn = find_input_file() 44 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 45 | print(f"Using '{fn}' as input file:") 46 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 47 | print(f"Running day {DAY_DESC}:") 48 | run(print, values) 49 | -------------------------------------------------------------------------------- /2020/Helpers/day_25.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 25 4 | DAY_DESC = 'Day 25: Combo Breaker' 5 | 6 | def transform(loop, subject): 7 | value = 1 8 | for _ in range(loop): 9 | value = value * subject 10 | value = value % 20201227 11 | return value 12 | 13 | def transform_bail(subject, bail): 14 | value = 1 15 | loop = 0 16 | while True: 17 | loop += 1 18 | value = value * subject 19 | value = value % 20201227 20 | if bail == value: 21 | return loop 22 | 23 | def calc(log, values, mode): 24 | door = transform_bail(7, int(values[1])) 25 | return transform(door, int(values[0])) 26 | 27 | 28 | def test(log): 29 | values = log.decode_values(""" 30 | 5764801 31 | 17807724 32 | """) 33 | 34 | log.test(calc(log, values, 1), 14897079) 35 | 36 | def run(log, values): 37 | log(f"Part 1: {calc(log, values, 1)}") 38 | 39 | if __name__ == "__main__": 40 | import sys, os 41 | def find_input_file(): 42 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 43 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 44 | cur = os.path.join(*(dn.split("/") + [fn])) 45 | if os.path.isfile(cur): return cur 46 | fn = find_input_file() 47 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 48 | print(f"Using '{fn}' as input file:") 49 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 50 | print(f"Running day {DAY_DESC}:") 51 | run(print, values) 52 | -------------------------------------------------------------------------------- /2020/Helpers/dummylog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | class DummyLog: 4 | def __init__(self, filename=None): 5 | self.filename = filename 6 | 7 | def show(self, value): 8 | if self.filename is not None: 9 | with open(self.filename, "at") as f: 10 | f.write(str(value) + "\n") 11 | else: 12 | print(value) 13 | 14 | def __call__(self, value): 15 | self.show(value) 16 | 17 | def decode_values(self, values): 18 | ret = values.replace("\t", " ").split("\n") 19 | # Only remove empty lines at the start and end 20 | while len(ret) > 0 and len(ret[0].strip()) == 0: 21 | ret = ret[1:] 22 | while len(ret) > 0 and len(ret[-1].strip()) == 0: 23 | ret = ret[:-1] 24 | # Remove the indenting based off the first line 25 | if len(ret) > 0: 26 | pad = len(ret[0]) - len(ret[0].lstrip(' ')) 27 | pad -= pad % 4 28 | if pad > 0 and len(ret) > 0: 29 | for i in range(len(ret)): 30 | if ret[i].startswith(" " * pad): 31 | ret[i] = ret[i][pad:] 32 | return ret 33 | 34 | def test(self, actual, expected): 35 | self.show("Test returned %s, expected %s" % (str(actual), str(expected))) 36 | if actual != expected: 37 | raise ValueError("Test failure") 38 | -------------------------------------------------------------------------------- /2020/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_desc(): 4 | return DAY_NUM, 'DAY_TODO' 5 | 6 | def calc(log, values, mode): 7 | # TODO: Delete or use these 8 | # from grid import Grid 9 | # grid = Grid.from_text(values) 10 | # from program import Program 11 | # prog = Program(values) 12 | 13 | # TODO 14 | return 0 15 | 16 | def test(log): 17 | values = log.decode_values(""" 18 | TODO 19 | """) 20 | 21 | log.test(calc(log, values, 1), 'TODO') 22 | log.test(calc(log, values, 2), 'TODO') 23 | 24 | def run(log, values): 25 | log(calc(log, values, 1)) 26 | log(calc(log, values, 2)) 27 | 28 | if __name__ == "__main__": 29 | import sys, os 30 | def find_input_file(): 31 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 32 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2020/Puzzles"]: 33 | cur = os.path.join(*(dn.split("/") + [fn])) 34 | if os.path.isfile(cur): return cur 35 | fn = find_input_file() 36 | if fn is None: print("Unable to find input file!"); exit(1) 37 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 38 | print(f"Running day {DAY_DESC}:") 39 | run(print, values) 40 | -------------------------------------------------------------------------------- /2020/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2020/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2020/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/Puzzles/favicon.png -------------------------------------------------------------------------------- /2020/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2020/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/Puzzles/main_page.png -------------------------------------------------------------------------------- /2020/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2020/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2020](https://adventofcode.com/2020). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | 7 | Some visualizations for your viewing pleasure: 8 | 9 | * Day 5: [Binary Boarding](https://youtu.be/N8QSaKOU6Bc) 10 | * Day 8: [Handheld Halting](https://youtu.be/2kt56axunqo) 11 | * Day 11: [Seating System ..](https://youtu.be/nTz7TnbUhxk), [Part 2](https://youtu.be/4jUEO3hnqNE) 12 | * Day 12: [Rain Risk](https://youtu.be/7TNH5ycypV8) 13 | * Day 16: [Ticket Translation](https://youtu.be/Lq_ph7QqiLo) 14 | * Day 17: [Conway Cubes](https://youtu.be/hfB96XHvrow) 15 | * Day 20: [Finding the monsters](https://youtu.be/SnUisO-bOeA) 16 | * Day 24: [Lobby Layout](https://youtu.be/gV_YQQm1ug0) 17 | -------------------------------------------------------------------------------- /2020/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2020 2 | -------------------------------------------------------------------------------- /2020/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2020" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2020/animations/animation_05.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_05.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_08.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_08.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_11_1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_11_1.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_11_2.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_11_2.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_12.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_12.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_16.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_16.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_17.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_17.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_18.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_18.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_20.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_20.mp4 -------------------------------------------------------------------------------- /2020/animations/animation_24.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2020/animations/animation_24.mp4 -------------------------------------------------------------------------------- /2020/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2021/.gitignore: -------------------------------------------------------------------------------- 1 | /*.png 2 | /*.mp4 3 | -------------------------------------------------------------------------------- /2021/Helpers/Font-DSEG14Classic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/Helpers/Font-DSEG14Classic-Bold.ttf -------------------------------------------------------------------------------- /2021/Helpers/Font-SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/Helpers/Font-SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /2021/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: Sonar Sweep' 5 | 6 | def calc(log, values, mode): 7 | values = [int(x) for x in values] 8 | window_size = {1: 1, 2: 3}[mode] 9 | last = sum(values[0:window_size]) 10 | ret = 0 11 | for i in range(len(values) - window_size + 1): 12 | cur = sum(values[i:i+window_size]) 13 | if cur > last: ret += 1 14 | last = cur 15 | return ret 16 | 17 | def test(log): 18 | values = log.decode_values(""" 19 | 199 20 | 200 21 | 208 22 | 210 23 | 200 24 | 207 25 | 240 26 | 269 27 | 260 28 | 263 29 | """) 30 | 31 | log.test(calc(log, values, 1), 7) 32 | log.test(calc(log, values, 2), 5) 33 | 34 | def run(log, values): 35 | log(f"Part 1: {calc(log, values, 1)}") 36 | log(f"Part 2: {calc(log, values, 2)}") 37 | 38 | if __name__ == "__main__": 39 | import sys, os 40 | def find_input_file(): 41 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 42 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2021/Puzzles"]: 43 | cur = os.path.join(*(dn.split("/") + [fn])) 44 | if os.path.isfile(cur): return cur 45 | fn = find_input_file() 46 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 47 | print(f"Using '{fn}' as input file:") 48 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 49 | print(f"Running day {DAY_DESC}:") 50 | run(print, values) 51 | -------------------------------------------------------------------------------- /2021/Helpers/day_07.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 7 4 | DAY_DESC = 'Day 7: The Treachery of Whales' 5 | 6 | def calc(log, values, mode): 7 | values = [int(x) for x in values[0].split(",")] 8 | best = None 9 | cost = {} 10 | 11 | for target in range(min(values), max(values)+1): 12 | temp = 0 13 | for cur in values: 14 | if mode == 1: 15 | temp += abs(cur - target) 16 | else: 17 | x = abs(cur - target) 18 | if x not in cost: 19 | cost[x] = sum(range(x + 1)) 20 | temp += cost[x] 21 | if best is not None and temp > best: 22 | break 23 | if best is None: 24 | best = temp 25 | else: 26 | best = min(best, temp) 27 | 28 | return best 29 | 30 | def test(log): 31 | values = log.decode_values(""" 32 | 16,1,2,0,4,2,7,1,2,14 33 | """) 34 | 35 | log.test(calc(log, values, 1), 37) 36 | log.test(calc(log, values, 2), 168) 37 | 38 | def run(log, values): 39 | log(f"Part 1: {calc(log, values, 1)}") 40 | log(f"Part 2: {calc(log, values, 2)}") 41 | 42 | if __name__ == "__main__": 43 | import sys, os 44 | def find_input_file(): 45 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 46 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2021/Puzzles"]: 47 | cur = os.path.join(*(dn.split("/") + [fn])) 48 | if os.path.isfile(cur): return cur 49 | fn = find_input_file() 50 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 51 | print(f"Using '{fn}' as input file:") 52 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 53 | print(f"Running day {DAY_DESC}:") 54 | run(print, values) 55 | -------------------------------------------------------------------------------- /2021/Helpers/day_16.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 16 4 | DAY_DESC = 'Day 16: Packet Decoder' 5 | 6 | def calc(log, values, mode, print_formula=False): 7 | from program import Program 8 | program = Program(values, print_formula=print_formula) 9 | program.run() 10 | 11 | if print_formula: 12 | log("".join(program.formula)) 13 | 14 | if mode == 1: 15 | return program.version_sum 16 | else: 17 | return program.result 18 | 19 | def other_show_formula(describe, values): 20 | if describe: 21 | return "Show the formula used" 22 | from dummylog import DummyLog 23 | calc(DummyLog(), values, 2, print_formula=True) 24 | 25 | def test(log): 26 | log.test(calc(log, ["620080001611562C8802118E34"], 1), 12) 27 | log.test(calc(log, ["C200B40A82"], 2), 3) 28 | log.test(calc(log, ["04005AC33890"], 2), 54) 29 | log.test(calc(log, ["880086C3E88112"], 2), 7) 30 | log.test(calc(log, ["CE00C43D881120"], 2), 9) 31 | log.test(calc(log, ["D8005AC2A8F0"], 2), 1) 32 | log.test(calc(log, ["F600BC2D8F"], 2), 0) 33 | log.test(calc(log, ["9C005AC2F8F0"], 2), 0) 34 | log.test(calc(log, ["9C0141080250320F1802104A08"], 2), 1) 35 | 36 | def run(log, values): 37 | log(f"Part 1: {calc(log, values, 1)}") 38 | log(f"Part 2: {calc(log, values, 2)}") 39 | 40 | if __name__ == "__main__": 41 | import sys, os 42 | def find_input_file(): 43 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 44 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2021/Puzzles"]: 45 | cur = os.path.join(*(dn.split("/") + [fn])) 46 | if os.path.isfile(cur): return cur 47 | fn = find_input_file() 48 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 49 | print(f"Using '{fn}' as input file:") 50 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 51 | print(f"Running day {DAY_DESC}:") 52 | run(print, values) 53 | -------------------------------------------------------------------------------- /2021/Helpers/dummylog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | class DummyLog: 4 | def __init__(self, filename=None): 5 | self.filename = filename 6 | 7 | def show(self, value): 8 | if self.filename is not None: 9 | with open(self.filename, "at") as f: 10 | f.write(str(value) + "\n") 11 | else: 12 | print(value) 13 | 14 | def __call__(self, value): 15 | self.show(value) 16 | 17 | def decode_values(self, values): 18 | ret = values.replace("\t", " ").split("\n") 19 | # Only remove empty lines at the start and end 20 | while len(ret) > 0 and len(ret[0].strip()) == 0: 21 | ret = ret[1:] 22 | while len(ret) > 0 and len(ret[-1].strip()) == 0: 23 | ret = ret[:-1] 24 | # Remove the indenting based off the first line 25 | if len(ret) > 0: 26 | pad = len(ret[0]) - len(ret[0].lstrip(' ')) 27 | pad -= pad % 4 28 | if pad > 0 and len(ret) > 0: 29 | for i in range(len(ret)): 30 | if ret[i].startswith(" " * pad): 31 | ret[i] = ret[i][pad:] 32 | return ret 33 | 34 | def test(self, actual, expected): 35 | self.show("Test returned %s, expected %s" % (str(actual), str(expected))) 36 | if actual != expected: 37 | raise ValueError("Test failure") 38 | -------------------------------------------------------------------------------- /2021/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = NEED_DAY_NUM 4 | DAY_DESC = 'NEED_DAY_DESC' 5 | 6 | def calc(log, values, mode): 7 | # TODO: Delete or use these 8 | # from grid import Grid 9 | # grid = Grid.from_text(values) 10 | # from program import Program 11 | # program = Program(values) 12 | 13 | # TODO 14 | return 0 15 | 16 | def test(log): 17 | values = log.decode_values(""" 18 | TODO 19 | """) 20 | 21 | log.test(calc(log, values, 1), 'TODO') 22 | log.test(calc(log, values, 2), 'TODO') 23 | 24 | def run(log, values): 25 | log(calc(log, values, 1)) 26 | log(calc(log, values, 2)) 27 | 28 | if __name__ == "__main__": 29 | import sys, os 30 | def find_input_file(): 31 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 32 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2021/Puzzles"]: 33 | cur = os.path.join(*(dn.split("/") + [fn])) 34 | if os.path.isfile(cur): return cur 35 | fn = find_input_file() 36 | if fn is None: print("Unable to find input file!"); exit(1) 37 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 38 | print(f"Running day {DAY_DESC}:") 39 | run(print, values) 40 | -------------------------------------------------------------------------------- /2021/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2021/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2021/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/Puzzles/favicon.png -------------------------------------------------------------------------------- /2021/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2021/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/Puzzles/main_page.png -------------------------------------------------------------------------------- /2021/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2021/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2021](https://adventofcode.com/2021). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | 7 | Some visualizations for your viewing pleasure: 8 | 9 | * Day 2: [Dive!](https://youtu.be/tLdEWEvzxvQ) 10 | * Day 5: [Hydrothermal Venture](https://youtu.be/cIiT64_j-v8) 11 | * Day 8: [Seven Segment Search](https://youtu.be/wcF0En4ip8k) 12 | * Day 9: [Smoke Basin](https://youtu.be/mxkVOQiGJ0A) 13 | * Day 11: [Dumbo Octopus](https://youtu.be/IG0A7URhzqE) 14 | * Day 15: [Chiton](https://youtu.be/kHGdWeL85_E) 15 | * Day 17: [Trick Shot](https://youtu.be/6A7yMv69_WY) 16 | * Day 20: [Trench Map](https://youtu.be/lOYZosPyo8s) 17 | * Day 23: [Amphipod](https://youtu.be/ItzJExLcs4k) 18 | * Day 24: [Arithmetic Logic Unit](https://youtu.be/V7nyPUqrDoU) 19 | * Day 25: [Sea Cucumber](https://youtu.be/x-FrI-H_1Sc) 20 | -------------------------------------------------------------------------------- /2021/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2021 2 | -------------------------------------------------------------------------------- /2021/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2021" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2021/animations/animation_02.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_02.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_05.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_05.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_08.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_08.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_09.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_09.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_11.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_11.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_15.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_15.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_17.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_17.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_20.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_20.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_23.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_23.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_24.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_24.mp4 -------------------------------------------------------------------------------- /2021/animations/animation_25.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2021/animations/animation_25.mp4 -------------------------------------------------------------------------------- /2021/main_page/.gitignore: -------------------------------------------------------------------------------- 1 | .p4ignore 2 | .venv 3 | screenshots 4 | frames 5 | *.exe 6 | *.png 7 | *.ttf 8 | *.css 9 | *.js 10 | *.mp4 11 | -------------------------------------------------------------------------------- /2021/main_page/add_new_day.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | i = 0 6 | while True: 7 | fn = os.path.join("aoc", f"index_{i:02d}.html") 8 | if not os.path.isfile(fn): 9 | break 10 | i += 1 11 | 12 | print("Using " + fn) 13 | 14 | sfn = os.path.join("..", "Puzzles", "index.html") 15 | temp = "" 16 | with open(sfn) as f: 17 | for row in f: 18 | skip = False 19 | if row.startswith('interval = setInterval(update_countdown,1000);'): 20 | skip = True 21 | if row.startswith('update_countdown();'): 22 | skip = True 23 | if not skip: 24 | temp += row 25 | 26 | with open(fn, "wt") as f: 27 | f.write(temp) 28 | -------------------------------------------------------------------------------- /2021/main_page/requirements.txt: -------------------------------------------------------------------------------- 1 | selenium 2 | chromedriver-binary-auto 3 | slackclient 4 | undetected-chromedriver 5 | pillow 6 | -------------------------------------------------------------------------------- /2021/requirements.txt: -------------------------------------------------------------------------------- 1 | browser_cookie3 2 | -------------------------------------------------------------------------------- /2021/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2022/.gitignore: -------------------------------------------------------------------------------- 1 | /*.png 2 | /*.mp4 3 | -------------------------------------------------------------------------------- /2022/Helpers/Font-DSEG14Classic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/Helpers/Font-DSEG14Classic-Bold.ttf -------------------------------------------------------------------------------- /2022/Helpers/Font-SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/Helpers/Font-SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /2022/Helpers/day_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 1 4 | DAY_DESC = 'Day 1: Calorie Counting' 5 | 6 | def calc(log, values, mode): 7 | batches = [[]] 8 | for cur in values: 9 | if len(cur) == 0: 10 | batches.append([]) 11 | else: 12 | batches[-1].append(int(cur)) 13 | 14 | batches = [sum(x) for x in batches] 15 | 16 | if mode == 1: 17 | return str(max(batches)) 18 | else: 19 | batches.sort(reverse=True) 20 | return str(sum(batches[0:3])) 21 | 22 | def test(log): 23 | values = log.decode_values(""" 24 | 1000 25 | 2000 26 | 3000 27 | 28 | 4000 29 | 30 | 5000 31 | 6000 32 | 33 | 7000 34 | 8000 35 | 9000 36 | 37 | 10000 38 | """) 39 | 40 | log.test(calc(log, values, 1), '24000') 41 | log.test(calc(log, values, 2), '45000') 42 | 43 | def run(log, values): 44 | log(f"Part 1: {calc(log, values, 1)}") 45 | log(f"Part 2: {calc(log, values, 2)}") 46 | 47 | if __name__ == "__main__": 48 | import sys, os 49 | def find_input_file(): 50 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 51 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2022/Puzzles"]: 52 | cur = os.path.join(*(dn.split("/") + [fn])) 53 | if os.path.isfile(cur): return cur 54 | fn = find_input_file() 55 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 56 | print(f"Using '{fn}' as input file:") 57 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 58 | print(f"Running day {DAY_DESC}:") 59 | run(print, values) 60 | -------------------------------------------------------------------------------- /2022/Helpers/day_02.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 2 4 | DAY_DESC = 'Day 2: Rock Paper Scissors' 5 | 6 | def calc(log, values, mode): 7 | score = 0 8 | 9 | for a, _, b in values: 10 | a = {"A": "R", "B": "P", "C": "S"}[a] 11 | if mode == 1: 12 | b = {"X": "R", "Y": "P", "Z": "S"}[b] 13 | else: 14 | if b == "Y": 15 | b = a 16 | elif b == "X": 17 | # Force a win 18 | b = {"R": "S", "S": "P", "P": "R"}[a] 19 | else: 20 | # Force a loss 21 | b = {"R": "P", "P": "S", "S": "R"}[a] 22 | 23 | if a == b: 24 | score += 3 25 | elif (b == "R" and a == "S") or (b == "S" and a == "P") or (b == "P" and a == "R"): 26 | score += 6 27 | 28 | score += {"R": 1, "P": 2, "S": 3}[b] 29 | 30 | return score 31 | 32 | def test(log): 33 | values = log.decode_values(""" 34 | A Y 35 | B X 36 | C Z 37 | """) 38 | 39 | log.test(calc(log, values, 1), 15) 40 | log.test(calc(log, values, 2), 12) 41 | 42 | def run(log, values): 43 | log(f"Part 1: {calc(log, values, 1)}") 44 | log(f"Part 2: {calc(log, values, 2)}") 45 | 46 | if __name__ == "__main__": 47 | import sys, os 48 | def find_input_file(): 49 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 50 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2022/Puzzles"]: 51 | cur = os.path.join(*(dn.split("/") + [fn])) 52 | if os.path.isfile(cur): return cur 53 | fn = find_input_file() 54 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 55 | print(f"Using '{fn}' as input file:") 56 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 57 | print(f"Running day {DAY_DESC}:") 58 | run(print, values) 59 | -------------------------------------------------------------------------------- /2022/Helpers/day_04.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 4 4 | DAY_DESC = 'Day 4: Camp Cleanup' 5 | 6 | def calc(log, values, mode): 7 | ret = 0 8 | for row in values: 9 | row = row.split(",") 10 | a = list(map(int, row[0].split("-"))) 11 | b = list(map(int, row[1].split("-"))) 12 | a = set(range(a[0], a[1] + 1)) 13 | b = set(range(b[0], b[1] + 1)) 14 | if mode == 1: 15 | if len(a & b) == min(len(a), len(b)): 16 | ret += 1 17 | else: 18 | if len(a & b) > 0: 19 | ret += 1 20 | return ret 21 | 22 | def test(log): 23 | values = log.decode_values(""" 24 | 2-4,6-8 25 | 2-3,4-5 26 | 5-7,7-9 27 | 2-8,3-7 28 | 6-6,4-6 29 | 2-6,4-8 30 | """) 31 | 32 | log.test(calc(log, values, 1), 2) 33 | log.test(calc(log, values, 2), 4) 34 | 35 | def run(log, values): 36 | log(f"Part 1: {calc(log, values, 1)}") 37 | log(f"Part 2: {calc(log, values, 2)}") 38 | 39 | if __name__ == "__main__": 40 | import sys, os 41 | def find_input_file(): 42 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 43 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2022/Puzzles"]: 44 | cur = os.path.join(*(dn.split("/") + [fn])) 45 | if os.path.isfile(cur): return cur 46 | fn = find_input_file() 47 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 48 | print(f"Using '{fn}' as input file:") 49 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 50 | print(f"Running day {DAY_DESC}:") 51 | run(print, values) 52 | -------------------------------------------------------------------------------- /2022/Helpers/day_06.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 6 4 | DAY_DESC = 'Day 6: Tuning Trouble' 5 | 6 | def calc(log, values, mode): 7 | last = [] 8 | target_len = 4 if mode == 1 else 14 9 | for i in range(len(values[0])): 10 | if len(set(values[0][i:target_len+i])) == target_len: 11 | return i + target_len 12 | 13 | def test(log): 14 | values = log.decode_values(""" 15 | mjqjpqmgbljsphdztnvjfqwrcgsmlb 16 | """) 17 | 18 | log.test(calc(log, values, 1), 7) 19 | log.test(calc(log, values, 2), 19) 20 | 21 | def run(log, values): 22 | log(f"Part 1: {calc(log, values, 1)}") 23 | log(f"Part 2: {calc(log, values, 2)}") 24 | 25 | if __name__ == "__main__": 26 | import sys, os 27 | def find_input_file(): 28 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 29 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2022/Puzzles"]: 30 | cur = os.path.join(*(dn.split("/") + [fn])) 31 | if os.path.isfile(cur): return cur 32 | fn = find_input_file() 33 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 34 | print(f"Using '{fn}' as input file:") 35 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 36 | print(f"Running day {DAY_DESC}:") 37 | run(print, values) 38 | -------------------------------------------------------------------------------- /2022/Helpers/dummylog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | class DummyLog: 4 | def __init__(self, filename=None): 5 | self.filename = filename 6 | 7 | def show(self, value): 8 | if self.filename is not None: 9 | with open(self.filename, "at") as f: 10 | f.write(str(value) + "\n") 11 | else: 12 | print(value) 13 | 14 | def __call__(self, value): 15 | self.show(value) 16 | 17 | def decode_values(self, values): 18 | ret = values.replace("\t", " ").split("\n") 19 | # Only remove empty lines at the start and end 20 | while len(ret) > 0 and len(ret[0].strip()) == 0: 21 | ret = ret[1:] 22 | while len(ret) > 0 and len(ret[-1].strip()) == 0: 23 | ret = ret[:-1] 24 | # Remove the indenting based off the first line 25 | if len(ret) > 0: 26 | pad = len(ret[0]) - len(ret[0].lstrip(' ')) 27 | pad -= pad % 4 28 | if pad > 0 and len(ret) > 0: 29 | for i in range(len(ret)): 30 | if ret[i].startswith(" " * pad): 31 | ret[i] = ret[i][pad:] 32 | return ret 33 | 34 | def test(self, actual, expected): 35 | self.show("Test returned %s, expected %s" % (str(actual), str(expected))) 36 | if actual != expected: 37 | raise ValueError("Test failure") 38 | -------------------------------------------------------------------------------- /2022/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = NEED_DAY_NUM 4 | DAY_DESC = 'NEED_DAY_DESC' 5 | 6 | def calc(log, values, mode): 7 | # TODO: Delete or use these 8 | # from parsers import get_ints, get_floats 9 | # from grid import Grid, Point 10 | # grid = Grid.from_text(values) 11 | # from program import Program 12 | # program = Program(values) 13 | 14 | # TODO 15 | return 0 16 | 17 | def test(log): 18 | values = log.decode_values(""" 19 | TODO 20 | """) 21 | 22 | log.test(calc(log, values, 1), 'TODO') 23 | log.test(calc(log, values, 2), 'TODO') 24 | 25 | def run(log, values): 26 | log(calc(log, values, 1)) 27 | log(calc(log, values, 2)) 28 | 29 | if __name__ == "__main__": 30 | import sys, os 31 | def find_input_file(): 32 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 33 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2022/Puzzles"]: 34 | cur = os.path.join(*(dn.split("/") + [fn])) 35 | if os.path.isfile(cur): return cur 36 | fn = find_input_file() 37 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 38 | print(f"Using '{fn}' as input file:") 39 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 40 | print(f"Running day {DAY_DESC}:") 41 | run(print, values) 42 | -------------------------------------------------------------------------------- /2022/Helpers/parsers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_ints(line): 4 | ret = [""] 5 | for x in line: 6 | if len(ret[-1]) == 0 and x == "-": 7 | ret[-1] = "-" 8 | elif "0" <= x <= "9": 9 | ret[-1] += x 10 | else: 11 | if len(ret[-1]) > 0: 12 | ret.append("") 13 | if len(ret[-1]) == 0: 14 | ret.pop(-1) 15 | return list(map(int, ret)) 16 | 17 | def get_floats(line): 18 | ret = [""] 19 | for x in line: 20 | if x == "-" and len(ret[-1]) == 0: 21 | ret[-1] = "-" 22 | elif "0" <= x <= "9": 23 | ret[-1] += x 24 | elif x == "." and "." not in ret[-1]: 25 | ret[-1] += x 26 | else: 27 | if len(ret[-1]) > 0: 28 | ret.append("") 29 | if len(ret[-1]) == 0: 30 | ret.pop(-1) 31 | return list(map(float, ret)) 32 | -------------------------------------------------------------------------------- /2022/Helpers/program.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import math 4 | 5 | class Program: 6 | def __init__(self, values): 7 | self.values = values 8 | self.pc = 0 9 | self.regs = {'x': 1} 10 | self.cycles = 0 11 | self.ins = None 12 | 13 | def run(self): 14 | while True: 15 | self.ins = self.values[self.pc] 16 | ins = self.ins.split(' ') 17 | 18 | ins_cycles = 1 19 | 20 | if ins[0] == "addx": 21 | ins_cycles = 2 22 | 23 | for _ in range(ins_cycles): 24 | self.cycles += 1 25 | yield True 26 | 27 | if ins[0] == "addx": 28 | self.regs['x'] += int(ins[1]) 29 | 30 | self.pc += 1 31 | 32 | if self.pc >= len(self.values): 33 | break 34 | -------------------------------------------------------------------------------- /2022/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2022/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2022/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/Puzzles/favicon.png -------------------------------------------------------------------------------- /2022/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2022/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/Puzzles/main_page.png -------------------------------------------------------------------------------- /2022/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2022/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2022](https://adventofcode.com/2022). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | 7 | Some visualizations for your viewing pleasure: 8 | 9 | * Day 5: [Watching the crane at work](https://imgur.com/a/nyVEK2j) 10 | * Day 7: [The layout of the drive](https://imgur.com/a/PDXx0GX) 11 | * Day 9: [Dragging a rope around](https://youtu.be/zTpJBzVDktk) 12 | * Day 10: [Decoding the message](https://imgur.com/a/Z02NxRl), [Beep Beep](https://imgur.com/a/ZoLPltM), [Christmas Time](https://imgur.com/a/Wzv32Dn) 13 | * Day 12: [Finding a path up the hill](https://imgur.com/a/2EQCAaC) 14 | * Day 14: [Filling up the cave with sand](https://youtu.be/Oqo4ee30pXU) 15 | * Day 16: [Finding a path through the cave of pressure](https://youtu.be/XyWthomQ9mM) 16 | * Day 17: [Playing a game](https://youtu.be/dMAxp1nmmiI), [(speed up version)](https://youtu.be/Hrsan4LFvDo) 17 | * Day 18: [Showing the lava drop](https://imgur.com/a/e0rbktk) 18 | * Day 20: [Sorting the buffer](https://youtu.be/Df63_i2p7jA) 19 | * Day 23: [The elves moving](https://youtu.be/s3xn8bOo6pA) (Warning: Flashing lights), [Smoothed version](https://youtu.be/yPZwSp3Te_M) 20 | * Day 24: [Moving amongst the wind](https://youtu.be/1lCGzchS6L4) (Warning: Flashing lights) 21 | * [The calendar itself](https://youtu.be/I4h1X-Bq29s) 22 | -------------------------------------------------------------------------------- /2022/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2022 2 | -------------------------------------------------------------------------------- /2022/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2022" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2022/animations/animation_05.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/animations/animation_05.mp4 -------------------------------------------------------------------------------- /2022/animations/animation_10.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/animations/animation_10.mp4 -------------------------------------------------------------------------------- /2022/animations/animation_12.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2022/animations/animation_12.mp4 -------------------------------------------------------------------------------- /2022/main_page/.gitignore: -------------------------------------------------------------------------------- 1 | .p4ignore 2 | .venv 3 | screenshots 4 | frames 5 | *.exe 6 | *.png 7 | *.ttf 8 | *.css 9 | *.js 10 | *.mp4 11 | -------------------------------------------------------------------------------- /2022/main_page/add_new_day.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | i = 0 6 | while True: 7 | fn = os.path.join("aoc", f"index_{i:02d}.html") 8 | if not os.path.isfile(fn): 9 | break 10 | i += 1 11 | 12 | print("Using " + fn) 13 | 14 | sfn = os.path.join("..", "Puzzles", "index.html") 15 | temp = "" 16 | with open(sfn) as f: 17 | for row in f: 18 | skip = False 19 | if row.startswith('interval = setInterval(update_countdown,1000);'): 20 | skip = True 21 | if row.startswith('update_countdown();'): 22 | skip = True 23 | if not skip: 24 | temp += row 25 | 26 | with open(fn, "wt") as f: 27 | f.write(temp) 28 | -------------------------------------------------------------------------------- /2022/main_page/requirements.txt: -------------------------------------------------------------------------------- 1 | selenium 2 | chromedriver-binary-auto 3 | slackclient 4 | undetected-chromedriver 5 | pillow 6 | -------------------------------------------------------------------------------- /2022/requirements.txt: -------------------------------------------------------------------------------- 1 | browser_cookie3 2 | pillow -------------------------------------------------------------------------------- /2022/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | if sys.version_info >= (3, 10): 6 | import importlib.util 7 | import importlib.machinery 8 | else: 9 | import imp 10 | import hashlib 11 | 12 | required_methods = [ 13 | "run", 14 | "test", 15 | "DAY_NUM", 16 | "DAY_DESC", 17 | ] 18 | 19 | def load_source(modname, filename): 20 | if sys.version_info >= (3, 11): 21 | loader = importlib.machinery.SourceFileLoader(modname, filename) 22 | spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) 23 | module = importlib.util.module_from_spec(spec) 24 | loader.exec_module(module) 25 | sys.modules[module.__name__] = module 26 | return module 27 | else: 28 | return imp.load_source(modname, filename) 29 | 30 | def get_helpers(): 31 | for cur in sorted(os.listdir("Helpers")): 32 | if cur.startswith("day_") and cur.endswith(".py"): 33 | name = ".".join(cur.split(".")[:-1]) 34 | cur = os.path.join("Helpers", cur) 35 | with open(cur, "rb") as f: 36 | hash = hashlib.sha256(f.read()).hexdigest() 37 | helper = load_source(name, cur) 38 | for method in required_methods: 39 | if not hasattr(helper, method): 40 | raise Exception(f"ERROR: {cur} doesn't implement '{method}'!") 41 | helper.filename = cur 42 | helper.hash = hash 43 | yield helper 44 | -------------------------------------------------------------------------------- /2023/.gitignore: -------------------------------------------------------------------------------- 1 | /*.png 2 | /*.mp4 3 | -------------------------------------------------------------------------------- /2023/Helpers/Font-DSEG14Classic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/Helpers/Font-DSEG14Classic-Bold.ttf -------------------------------------------------------------------------------- /2023/Helpers/Font-SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/Helpers/Font-SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /2023/Helpers/day_09.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 9 4 | DAY_DESC = 'Day 9: Mirage Maintenance' 5 | 6 | def calc(log, values, mode): 7 | ret = 0 8 | 9 | if mode == 1: next_value = lambda a, b: a + b 10 | else: next_value = lambda a, b: b - a 11 | 12 | for row in values: 13 | row = [[int(x) for x in row.split(" ")]] 14 | while any(row[-1]): 15 | last = row[-1] 16 | row.append([last[x+1] - last[x] for x in range(len(last)-1)]) 17 | 18 | if mode == 2: 19 | row = [x[::-1] for x in row] 20 | 21 | row[-1].append(0) 22 | for i in range(len(row)-2, -1, -1): 23 | row[i].append(next_value(row[i+1][-1], row[i][-1])) 24 | ret += row[0][-1] 25 | 26 | return ret 27 | 28 | def test(log): 29 | values = log.decode_values(""" 30 | 0 3 6 9 12 15 31 | 1 3 6 10 15 21 32 | 10 13 16 21 30 45 33 | """) 34 | 35 | log.test(calc(log, values, 1), '114') 36 | log.test(calc(log, values, 2), '2') 37 | 38 | def run(log, values): 39 | log(f"Part 1: {calc(log, values, 1)}") 40 | log(f"Part 2: {calc(log, values, 2)}") 41 | 42 | if __name__ == "__main__": 43 | import sys, os 44 | def find_input_file(): 45 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 46 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2023/Puzzles"]: 47 | cur = os.path.join(*(dn.split("/") + [fn])) 48 | if os.path.isfile(cur): return cur 49 | fn = find_input_file() 50 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 51 | print(f"Using '{fn}' as input file:") 52 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 53 | print(f"Running day {DAY_DESC}:") 54 | run(print, values) 55 | -------------------------------------------------------------------------------- /2023/Helpers/day_15.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 15 4 | DAY_DESC = 'Day 15: Lens Library' 5 | 6 | from collections import defaultdict 7 | 8 | def calc(log, values, mode): 9 | ret = 0 10 | 11 | boxes = defaultdict(dict) 12 | 13 | for cur in values[0].split(","): 14 | x = 0 15 | for dig in cur: 16 | if dig in "-=": 17 | target = x 18 | x += ord(dig) 19 | x *= 17 20 | x %= 256 21 | ret += x 22 | 23 | if cur.endswith("-"): 24 | label = cur[:-1] 25 | if label in boxes[target]: 26 | del boxes[target][label] 27 | else: 28 | label, focus = cur.split("=") 29 | boxes[target][label] = int(focus) 30 | 31 | if mode == 2: 32 | ret = 0 33 | for box_num, box in boxes.items(): 34 | for lens_num, (label, focus) in enumerate(box.items()): 35 | ret += (box_num + 1) * (lens_num + 1) * focus 36 | 37 | return ret 38 | 39 | def test(log): 40 | values = log.decode_values(""" 41 | rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7 42 | """) 43 | 44 | log.test(calc(log, values, 1), '1320') 45 | log.test(calc(log, values, 2), '145') 46 | 47 | def run(log, values): 48 | log(f"Part 1: {calc(log, values, 1)}") 49 | log(f"Part 2: {calc(log, values, 2)}") 50 | 51 | if __name__ == "__main__": 52 | import sys, os 53 | def find_input_file(): 54 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 55 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2023/Puzzles"]: 56 | cur = os.path.join(*(dn.split("/") + [fn])) 57 | if os.path.isfile(cur): return cur 58 | fn = find_input_file() 59 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 60 | print(f"Using '{fn}' as input file:") 61 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 62 | print(f"Running day {DAY_DESC}:") 63 | run(print, values) 64 | -------------------------------------------------------------------------------- /2023/Helpers/day_25.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = 25 4 | DAY_DESC = 'Day 25: Snowverload' 5 | 6 | def calc(log, values, mode): 7 | import igraph 8 | values = {key: value.split(' ') for key, value in [x.split(': ') for x in values]} 9 | cut = igraph.Graph.ListDict(values).mincut() 10 | return len(cut.partition[0]) * len(cut.partition[1]) 11 | 12 | def test(log): 13 | values = log.decode_values(""" 14 | jqt: rhn xhk nvd 15 | rsh: frs pzl lsr 16 | xhk: hfx 17 | cmg: qnr nvd lhk bvb 18 | rhn: xhk bvb hfx 19 | bvb: xhk hfx 20 | pzl: lsr hfx nvd 21 | qnr: nvd 22 | ntq: jqt hfx bvb xhk 23 | nvd: lhk 24 | lsr: lhk 25 | rzs: qnr cmg lsr rsh 26 | frs: qnr lhk lsr 27 | """) 28 | 29 | log.test(calc(log, values, 1), '54') 30 | 31 | def run(log, values): 32 | log(f"Part 1: {calc(log, values, 1)}") 33 | 34 | if __name__ == "__main__": 35 | import sys, os 36 | def find_input_file(): 37 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 38 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2023/Puzzles"]: 39 | cur = os.path.join(*(dn.split("/") + [fn])) 40 | if os.path.isfile(cur): return cur 41 | fn = find_input_file() 42 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 43 | print(f"Using '{fn}' as input file:") 44 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 45 | print(f"Running day {DAY_DESC}:") 46 | run(print, values) 47 | -------------------------------------------------------------------------------- /2023/Helpers/dummylog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | class DummyLog: 4 | def __init__(self, filename=None): 5 | self.filename = filename 6 | 7 | def show(self, value): 8 | if self.filename is not None: 9 | with open(self.filename, "at") as f: 10 | f.write(str(value) + "\n") 11 | else: 12 | print(value) 13 | 14 | def __call__(self, value): 15 | self.show(value) 16 | 17 | def decode_values(self, values): 18 | ret = values.replace("\t", " ").split("\n") 19 | # Only remove empty lines at the start and end 20 | while len(ret) > 0 and len(ret[0].strip()) == 0: 21 | ret = ret[1:] 22 | while len(ret) > 0 and len(ret[-1].strip()) == 0: 23 | ret = ret[:-1] 24 | # Remove the indenting based off the first line 25 | if len(ret) > 0: 26 | pad = len(ret[0]) - len(ret[0].lstrip(' ')) 27 | pad -= pad % 4 28 | if pad > 0 and len(ret) > 0: 29 | for i in range(len(ret)): 30 | if ret[i].startswith(" " * pad): 31 | ret[i] = ret[i][pad:] 32 | return ret 33 | 34 | def test(self, actual, expected): 35 | self.show("Test returned %s, expected %s" % (str(actual), str(expected))) 36 | if actual != expected: 37 | raise ValueError("Test failure") 38 | -------------------------------------------------------------------------------- /2023/Helpers/example.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | DAY_NUM = NEED_DAY_NUM 4 | DAY_DESC = 'NEED_DAY_DESC' 5 | 6 | def calc(log, values, mode): 7 | # TODO: Delete or use these 8 | # from parsers import get_ints, get_floats 9 | # from grid import Grid, Point 10 | # grid = Grid.from_text(values) 11 | # from program import Program 12 | # program = Program(values) 13 | 14 | # TODO 15 | return 0 16 | 17 | def test(log): 18 | values = log.decode_values(""" 19 | TODO 20 | """) 21 | 22 | log.test(calc(log, values, 1), 'TODO') 23 | log.test(calc(log, values, 2), 'TODO') 24 | 25 | def run(log, values): 26 | log(calc(log, values, 1)) 27 | log(calc(log, values, 2)) 28 | 29 | if __name__ == "__main__": 30 | import sys, os 31 | def find_input_file(): 32 | for fn in sys.argv[1:] + ["input.txt", f"day_{DAY_NUM:0d}_input.txt", f"day_{DAY_NUM:02d}_input.txt"]: 33 | for dn in ["", "Puzzles", "../Puzzles", "../../private/inputs/2023/Puzzles"]: 34 | cur = os.path.join(*(dn.split("/") + [fn])) 35 | if os.path.isfile(cur): return cur 36 | fn = find_input_file() 37 | if fn is None: print("Unable to find input file!\nSpecify filename on command line"); exit(1) 38 | print(f"Using '{fn}' as input file:") 39 | with open(fn) as f: values = [x.strip("\r\n") for x in f.readlines()] 40 | print(f"Running day {DAY_DESC}:") 41 | run(print, values) 42 | -------------------------------------------------------------------------------- /2023/Helpers/parsers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_ints(line): 4 | ret = [""] 5 | for x in line: 6 | if len(ret[-1]) == 0 and x == "-": 7 | ret[-1] = "-" 8 | elif "0" <= x <= "9": 9 | ret[-1] += x 10 | else: 11 | if len(ret[-1]) > 0: 12 | ret.append("") 13 | if len(ret[-1]) == 0: 14 | ret.pop(-1) 15 | return list(map(int, ret)) 16 | 17 | def get_floats(line): 18 | ret = [""] 19 | for x in line: 20 | if x == "-" and len(ret[-1]) == 0: 21 | ret[-1] = "-" 22 | elif "0" <= x <= "9": 23 | ret[-1] += x 24 | elif x == "." and "." not in ret[-1]: 25 | ret[-1] += x 26 | else: 27 | if len(ret[-1]) > 0: 28 | ret.append("") 29 | if len(ret[-1]) == 0: 30 | ret.pop(-1) 31 | return list(map(float, ret)) 32 | -------------------------------------------------------------------------------- /2023/Helpers/program.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import math 4 | 5 | class Program: 6 | def __init__(self, values): 7 | self.values = values 8 | self.pc = 0 9 | self.regs = {'x': 1} 10 | self.cycles = 0 11 | self.ins = None 12 | 13 | def run(self): 14 | while True: 15 | self.ins = self.values[self.pc] 16 | ins = self.ins.split(' ') 17 | 18 | ins_cycles = 1 19 | 20 | if ins[0] == "addx": 21 | ins_cycles = 2 22 | 23 | for _ in range(ins_cycles): 24 | self.cycles += 1 25 | yield True 26 | 27 | if ins[0] == "addx": 28 | self.regs['x'] += int(ins[1]) 29 | 30 | self.pc += 1 31 | 32 | if self.pc >= len(self.values): 33 | break 34 | -------------------------------------------------------------------------------- /2023/Puzzles/SourceCodePro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Code Pro'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url(SourceCodePro.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /2023/Puzzles/SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/Puzzles/SourceCodePro.ttf -------------------------------------------------------------------------------- /2023/Puzzles/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/Puzzles/favicon.png -------------------------------------------------------------------------------- /2023/Puzzles/highcontrast.css: -------------------------------------------------------------------------------- 1 | * { 2 | background: white !important; 3 | color: black !important; 4 | text-shadow: none !important; 5 | } 6 | a { 7 | color: #0000ff !important; 8 | text-decoration: underline !important; 9 | } 10 | em { 11 | font-weight: 900 !important; 12 | } 13 | -------------------------------------------------------------------------------- /2023/Puzzles/main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/Puzzles/main_page.png -------------------------------------------------------------------------------- /2023/Puzzles/main_page_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/Puzzles/main_page_small.png -------------------------------------------------------------------------------- /2023/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | These are my solutions to the [Advent of Code for 2023](https://adventofcode.com/2023). 4 | 5 | The Solutions themselves are in the `Puzzles` folder. They're meant to be run with the `advent.py` helper. Run it to see what options it provides, but at a high level, you can run either the `test` or `run` mode to run a day's solution. 6 | 7 | Some visualizations for your viewing pleasure: 8 | 9 | * Day 10: [Finding the space inside the pipes](https://youtu.be/DYrIH225wHs), and [updated version](https://youtu.be/-vaIkRA1w9k) 10 | * Day 14: [Animating the sand](https://youtu.be/5EWSnlYrt_0), and a [smoothed version](https://youtu.be/qvfBEnJZfsU) 11 | * Day 16: [Watching the lasers](https://youtu.be/1KsEUjXK9_s) 12 | * Day 18: [Painting the Maze](https://youtu.be/3eFCQ2M4xf0) 13 | * Day 23: [Watching all the possibilities](https://youtu.be/bcK-ThfHx9o) 14 | * [The calendar itself](https://youtu.be/EYtkMaH6xQY) 15 | -------------------------------------------------------------------------------- /2023/URL.txt: -------------------------------------------------------------------------------- 1 | https://adventofcode.com/2023 2 | -------------------------------------------------------------------------------- /2023/advent_year.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | YEAR_NUMBER = "2023" 4 | 5 | if __name__ == "__main__": 6 | print("This module can not be run directly") 7 | -------------------------------------------------------------------------------- /2023/animations/animation_10.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/animations/animation_10.mp4 -------------------------------------------------------------------------------- /2023/animations/animation_14.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seligman/aoc/b2e14a0233277ce18faa654247a3b5854ce1e858/2023/animations/animation_14.mp4 -------------------------------------------------------------------------------- /2023/main_page/.gitignore: -------------------------------------------------------------------------------- 1 | .p4ignore 2 | .venv 3 | screenshots 4 | frames 5 | *.exe 6 | *.png 7 | *.ttf 8 | *.css 9 | *.js 10 | *.mp4 11 | -------------------------------------------------------------------------------- /2023/main_page/add_new_day.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | if not os.path.isdir("aoc"): 6 | os.mkdir("aoc") 7 | print("Newly created folder detected, you'll need to copy the