commit e9df3737e1957bb734975354c5f89b71e4532fc9 Author: Ikatono Date: Tue Dec 10 14:36:10 2024 -0600 initial commit, day 10 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2211df6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/01a.py b/01a.py new file mode 100755 index 0000000..7c317de --- /dev/null +++ b/01a.py @@ -0,0 +1,24 @@ +#!/usr/bin/python + +with open('01a.txt') as f: + text = f.read().strip() + +lines = text.split('\n') + +a = [0] * len(lines) +b = a[:] + +for i in range(len(lines)): + spl = lines[i].split(' ', maxsplit=1) + a[i] = int(spl[0].strip()) + b[i] = int(spl[1].strip()) + +a.sort() +b.sort() + +total = 0 + +for x, y in zip(a, b): + total += abs(x - y) + +print(total) \ No newline at end of file diff --git a/01b.py b/01b.py new file mode 100755 index 0000000..5b37a07 --- /dev/null +++ b/01b.py @@ -0,0 +1,40 @@ +#!/usr/bin/python + +with open('01a.txt') as f: + text = f.read().strip() + +lines = text.split('\n') + +a = [None] * len(lines) +b = [None] * len(lines) + +for i in range(len(lines)): + spl = lines[i].split(' ', maxsplit=1) + a[i] = int(spl[0].strip()) + b[i] = int(spl[1].strip()) + +a.sort() +b.sort() + +total = 0 + +# for x, y in zip(a, b): +# total += abs(x - y) + +# print(total) + +i_a = 0 +i_b = 0 + +while i_a < len(lines) and i_b < len(lines): + x_a = a[i_a] + x_b = b[i_b] + if x_a == x_b: + total += x_b + i_b += 1 + elif x_a < x_b: + i_a += 1 + else: + i_b += 1 + +print(total) diff --git a/02a.py b/02a.py new file mode 100755 index 0000000..c473bbf --- /dev/null +++ b/02a.py @@ -0,0 +1,19 @@ +with open('02a.txt') as f: + text = f.read().strip() + +def make_report(line): + return [int(x.strip()) for x in line.split()] + +reports = [make_report(x) for x in text.split('\n')] + +def test_report(report): + if len(report) == 1: + return True + dir = 1 if report[1] - report[0] > 0 else -1 + for i in range(len(report)-1): + diff = (report[i+1] - report[i]) * dir + if diff < 1 or diff > 3: + return False + return True + +print(sum(test_report(x) for x in reports)) diff --git a/02b.py b/02b.py new file mode 100755 index 0000000..e5b66d5 --- /dev/null +++ b/02b.py @@ -0,0 +1,25 @@ +with open('02a.txt') as f: + text = f.read().strip() + +def make_report(line): + return [int(x.strip()) for x in line.split()] + +reports = [make_report(x) for x in text.split('\n')] + +def test_report(report): + if len(report) == 1: + return True + dir = 1 if report[1] - report[0] > 0 else -1 + for i in range(len(report)-1): + diff = (report[i+1] - report[i]) * dir + if diff < 1 or diff > 3: + return False + return True + +def test_sub_reports(report): + for i in range(len(report)): + if test_report(report[:i] + report[i+1:]): + return True + return False + +print(sum(test_sub_reports(x) for x in reports)) diff --git a/03a.py b/03a.py new file mode 100755 index 0000000..4d45ea1 --- /dev/null +++ b/03a.py @@ -0,0 +1,15 @@ +#!/usr/bin/python + +import re + +with open('03a.txt') as f: + text = f.read() + +reg = re.compile(r'mul\((?P[0-9]+),(?P[0-9]+)\)') + +total = 0 + +for match in reg.finditer(text): + total += int(match.group('num1')) * int(match.group('num2')) + +print(total) diff --git a/03b.py b/03b.py new file mode 100755 index 0000000..787b04b --- /dev/null +++ b/03b.py @@ -0,0 +1,24 @@ +#!/usr/bin/python + +import re + +with open('03a.txt') as f: + text = f.read() + +reg = re.compile(r'(?Pmul\((?P[0-9]+),(?P[0-9]+)\))|(?Pdo\(\))|(?Pdon\'t\(\))') + +total = 0 +enabled = True + +for match in reg.finditer(text): + if match.group('do'): + enabled = True + elif match.group('dont'): + enabled = False + elif match.group('mul'): + if enabled: + total += int(match.group('num1')) * int(match.group('num2')) + else: + raise RuntimeError() + +print(total) diff --git a/04a.py b/04a.py new file mode 100755 index 0000000..050c59c --- /dev/null +++ b/04a.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +with open('04a.txt') as f: + lines = f.readlines() +lines = [x.strip() for x in lines if x.strip()] +count = 0 + +i_len = len(lines) +j_len = len(lines[0]) +for i in range(i_len): + for j in range(j_len): + if lines[i][j] == 'X': + UP = i >= 3 + DOWN = (i_len - i) >= 4 + LEFT = j >= 3 + RIGHT = (j_len - j) >= 4 + if UP: + if lines[i-1][j] == 'M' and lines[i-2][j] == 'A' and lines[i-3][j] == 'S': + count += 1 + if DOWN: + if lines[i+1][j] == 'M' and lines[i+2][j] == 'A' and lines[i+3][j] == 'S': + count += 1 + if LEFT: + if lines[i][j-1] == 'M' and lines[i][j-2] == 'A' and lines[i][j-3] == 'S': + count += 1 + if RIGHT: + if lines[i][j+1] == 'M' and lines[i][j+2] == 'A' and lines[i][j+3] == 'S': + count += 1 + if UP and LEFT: + if lines[i-1][j-1] == 'M' and lines[i-2][j-2] == 'A' and lines[i-3][j-3] == 'S': + count += 1 + if UP and RIGHT: + if lines[i-1][j+1] == 'M' and lines[i-2][j+2] == 'A' and lines[i-3][j+3] == 'S': + count += 1 + if DOWN and LEFT: + if lines[i+1][j-1] == 'M' and lines[i+2][j-2] == 'A' and lines[i+3][j-3] == 'S': + count += 1 + if DOWN and RIGHT: + if lines[i+1][j+1] == 'M' and lines[i+2][j+2] == 'A' and lines[i+3][j+3] == 'S': + count += 1 + +print(count) diff --git a/04a_alt.py b/04a_alt.py new file mode 100755 index 0000000..047efaa --- /dev/null +++ b/04a_alt.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +import re + +with open('04a.txt') as f: + chars = ''.join(c for c in f.read() if c in ['X', 'M', 'A', 'S']) + +UP = r'S.{139}A.{139}M.{139}X' +DOWN = r'X.{139}M.{139}A.{139}S' +LEFT = r'SAMX' +RIGHT = r'XMAS' +UPLEFT = r'S.{140}A.{140}M.{140}X' +UPRIGHT = r'S.{138}A.{138}M.{138}X' +DOWNLEFT = r'X.{138}M.{138}A.{138}S' +DOWNRIGHT = r'X.{140}M.{140}A.{140}S' + +ORED = '|'.join((UP, DOWN, LEFT, RIGHT, UPLEFT, UPRIGHT, DOWNLEFT, DOWNRIGHT)) +REG = re.compile(f'(?={ORED})') + +def lookahead(s): + return f'(?={s})' + +up = next(re.finditer(UP, chars)) +print(up.pos) + +_UP = len(re.findall(UP, chars)) +_DOWN = len(re.findall(DOWN, chars)) +_LEFT = len(re.findall(LEFT, chars)) +_RIGHT = len(re.findall(RIGHT, chars)) +_UPLEFT = len(re.findall(UPLEFT, chars)) +_UPRIGHT = len(re.findall(UPRIGHT, chars)) +_DOWNLEFT = len(re.findall(DOWNLEFT, chars)) +_DOWNRIGHT = len(re.findall(DOWNRIGHT, chars)) + +print(f'UP {_UP}') +print(f'DOWN {_DOWN}') +print(f'LEFT {_LEFT}') +print(f'RIGHT {_RIGHT}') +print(f'UPLEFT {_UPLEFT}') +print(f'UPRIGHT {_UPRIGHT}') +print(f'DOWNLEFT {_DOWNLEFT}') +print(f'DOWNRIGHT {_DOWNRIGHT}') +print(f'TOTAL {_UP + _DOWN + _LEFT + _RIGHT + _UPLEFT + _UPRIGHT + _DOWNLEFT + _DOWNRIGHT}') + +print(len(REG.findall(chars))) diff --git a/04b.py b/04b.py new file mode 100755 index 0000000..050c59c --- /dev/null +++ b/04b.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +with open('04a.txt') as f: + lines = f.readlines() +lines = [x.strip() for x in lines if x.strip()] +count = 0 + +i_len = len(lines) +j_len = len(lines[0]) +for i in range(i_len): + for j in range(j_len): + if lines[i][j] == 'X': + UP = i >= 3 + DOWN = (i_len - i) >= 4 + LEFT = j >= 3 + RIGHT = (j_len - j) >= 4 + if UP: + if lines[i-1][j] == 'M' and lines[i-2][j] == 'A' and lines[i-3][j] == 'S': + count += 1 + if DOWN: + if lines[i+1][j] == 'M' and lines[i+2][j] == 'A' and lines[i+3][j] == 'S': + count += 1 + if LEFT: + if lines[i][j-1] == 'M' and lines[i][j-2] == 'A' and lines[i][j-3] == 'S': + count += 1 + if RIGHT: + if lines[i][j+1] == 'M' and lines[i][j+2] == 'A' and lines[i][j+3] == 'S': + count += 1 + if UP and LEFT: + if lines[i-1][j-1] == 'M' and lines[i-2][j-2] == 'A' and lines[i-3][j-3] == 'S': + count += 1 + if UP and RIGHT: + if lines[i-1][j+1] == 'M' and lines[i-2][j+2] == 'A' and lines[i-3][j+3] == 'S': + count += 1 + if DOWN and LEFT: + if lines[i+1][j-1] == 'M' and lines[i+2][j-2] == 'A' and lines[i+3][j-3] == 'S': + count += 1 + if DOWN and RIGHT: + if lines[i+1][j+1] == 'M' and lines[i+2][j+2] == 'A' and lines[i+3][j+3] == 'S': + count += 1 + +print(count) diff --git a/04b_alt.py b/04b_alt.py new file mode 100755 index 0000000..9154275 --- /dev/null +++ b/04b_alt.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import re + +with open('04a.txt') as f: + text = f.read().strip().replace('\n', 'Z') + +TOP = r'M[^Z]M.{139}A.{139}S[^Z]S' +LEFT = r'M[^Z]S.{139}A.{139}M[^Z]S' +BOTTOM = r'S[^Z]S.{139}A.{139}M[^Z]M' +RIGHT = r'S[^Z]M.{139}A.{139}S[^Z]M' + +T = re.compile(f'(?={TOP})') +L = re.compile(f'(?={LEFT})') +B = re.compile(f'(?={BOTTOM})') +R = re.compile(f'(?={RIGHT})') + +T_ = len(T.findall(text)) +L_ = len(L.findall(text)) +B_ = len(B.findall(text)) +R_ = len(R.findall(text)) + +print(f'TOP {T_}') +print(f'LEFT {L_}') +print(f'BOTTOM {B_}') +print(f'RIGHT {R_}') +print(f'TOTAL {T_ + L_ + B_ + R_}') diff --git a/10.cpp b/10.cpp new file mode 100644 index 0000000..a65ff1b --- /dev/null +++ b/10.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include + +using map_t = std::array, 54>; + +struct Point +{ + int16_t Row; + int16_t Col; +}; + +using sols_t = std::unordered_set; + +void load_map(map_t& map, const char* filepath) +{ + std::fstream in(filepath); + std::istreambuf_iterator iter(in); + // std::istream_iterator end; + for (auto& row : map) + { + for (auto& cell : row) + { + cell = *(iter++); + } + } +} + +void branch(const map_t& map, sols_t& terminals, char height, Point pos) +{ + if (height == '9') + terminals.emplace((pos.Row << 16) + pos.Col); + else + { + if (pos.Row > 0 && map[pos.Row-1][pos.Col] == height+1) + { + branch(map, terminals, height+1, {pos.Row-1, pos.Col}); + } + if (pos.Row < map.size()-1 && map[pos.Row+1][pos.Col] == height+1) + { + branch(map, terminals, height+1, {pos.Row+1, pos.Col}); + } + if (pos.Col > 0 && map[pos.Row][pos.Col-1] == height+1) + { + branch(map, terminals, height+1, {pos.Row, pos.Col-1}); + } + if (pos.Col < map[0].size()-2 && map[pos.Row][pos.Col+1] == height+1) + { + branch(map, terminals, height+1, {pos.Row, pos.Col+1}); + } + } +} + +int64_t branch2(const map_t& map, char height, Point pos) +{ + if (height == '9') + return 1; + else + { + int64_t total = 0; + if (pos.Row > 0 && map[pos.Row-1][pos.Col] == height+1) + { + total += branch2(map, height+1, {pos.Row-1, pos.Col}); + } + if (pos.Row < map.size()-1 && map[pos.Row+1][pos.Col] == height+1) + { + total += branch2(map, height+1, {pos.Row+1, pos.Col}); + } + if (pos.Col > 0 && map[pos.Row][pos.Col-1] == height+1) + { + total += branch2(map, height+1, {pos.Row, pos.Col-1}); + } + if (pos.Col < map[0].size()-2 && map[pos.Row][pos.Col+1] == height+1) + { + total += branch2(map, height+1, {pos.Row, pos.Col+1}); + } + return total; + } +} + +void main1(const map_t& map) +{ + int total = 0; + // for (const auto& row : map) + // for (const auto& cell : row) + // std::cout << cell; + // std::cout << std::endl; + for (int16_t r = 0; r < map.size(); r++) + { + for (int16_t c = 0; c < map[r].size()-1; c++) + { + if (map[r][c] == '0') + { + sols_t terminals; + branch(map, terminals, '0', {r, c}); + total += terminals.size(); + } + } + } + std::cout << "Part1 " << total << std::endl; +} + +void main2(const map_t& map) +{ + int64_t total = 0; + for (int16_t r = 0; r < map.size(); r++) + { + for (int16_t c = 0; c < map[r].size()-1; c++) + { + if (map[r][c] == '0') + { + total += branch2(map, '0', {r, c}); + } + } + } + std::cout << "Part2 " << total << std::endl; +} + +int main() +{ + map_t map; + load_map(map, "10.txt"); + main1(map); + main2(map); + return 0; +} \ No newline at end of file diff --git a/10_extraquick.cpp b/10_extraquick.cpp new file mode 100644 index 0000000..b40a9bb --- /dev/null +++ b/10_extraquick.cpp @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#include +#include + +#define WIDTH 54 +#define HEIGHT 54 + +using map_t = std::array, HEIGHT>; + +struct Point +{ + int_fast8_t Row; + int_fast8_t Col; +}; + +struct sols_t +{ + std::bitset bits; + void emplace(Point point) + { + bits.set(point.Row * WIDTH + point.Col); + } + int size() const + { + return bits.count(); + } + void clear() + { + bits.reset(); + } +}; + +void load_map(map_t& map, const char* filepath) +{ + std::fstream in(filepath); + std::istreambuf_iterator iter(in); + for (auto& row : map) + { + for (auto& cell : row) + { + cell = *(iter++) - '0'; + } + iter++; + } +} + +void quick_branch(const map_t& map, sols_t& terminals, Point init) +{ + std::array path; + int_fast8_t height = 0; + path[0] = 0; + Point pos = init; + while (height >= 0) + { + // const auto& pos = path[height].pos; + switch (path[height]++) + { + case 0: + if (pos.Row > 0 && map[pos.Row-1][pos.Col] == height+1) + { + if (height == 8) + terminals.emplace({static_cast(pos.Row-1), pos.Col}); + else + { + path[++height] = 0; + pos.Row--; + } + } + break; + case 1: + if (pos.Col < WIDTH-1 && map[pos.Row][pos.Col+1] == height+1) + { + if (height == 8) + terminals.emplace({pos.Row, static_cast(pos.Col+1)}); + else + { + path[++height] = 0; + pos.Col++; + } + } + break; + case 2: + if (pos.Row < HEIGHT-1 && map[pos.Row+1][pos.Col] == height+1) + { + if (height == 8) + terminals.emplace({static_cast(pos.Row+1), pos.Col}); + else + { + path[++height] = 0; + pos.Row++; + } + } + break; + case 3: + if (pos.Col > 0 && map[pos.Row][pos.Col-1] == height+1) + { + if (height == 8) + terminals.emplace({pos.Row, static_cast(pos.Col-1)}); + else + { + path[++height] = 0; + pos.Col--; + } + } + break; + default: + if (height > 0) + //remember that the previous path was already incremented + switch (path[height-1]) + { + case 1: + pos.Row++; + break; + case 2: + pos.Col--; + break; + case 3: + pos.Row--; + break; + case 4: + pos.Col++; + break; + } + height--; + break; + } + } +} + +int quick_branch2(const map_t& map, Point init) +{ + std::array path; + int_fast8_t height = 0; + path[0] = 0; + int total = 0; + Point pos = init; + while (height >= 0) + { + switch (path[height]++) + { + case 0: + if (pos.Row > 0 && map[pos.Row-1][pos.Col] == height+1) + { + if (height == 8) + total++; + else + { + path[++height] = 0; + pos.Row--; + } + } + break; + case 1: + if (pos.Col < WIDTH-1 && map[pos.Row][pos.Col+1] == height+1) + { + if (height == 8) + total++; + else + { + path[++height] = 0; + pos.Col++; + } + } + break; + case 2: + if (pos.Row < HEIGHT-1 && map[pos.Row+1][pos.Col] == height+1) + { + if (height == 8) + total++; + else + { + path[++height] = 0; + pos.Row++; + } + } + break; + case 3: + if (pos.Col > 0 && map[pos.Row][pos.Col-1] == height+1) + { + if (height == 8) + total++; + else + { + path[++height] = 0; + pos.Col--; + } + } + break; + default: + if (height > 0) + //remember that the previous path was already incremented + switch (path[height-1]) + { + case 1: + pos.Row++; + break; + case 2: + pos.Col--; + break; + case 3: + pos.Row--; + break; + case 4: + pos.Col++; + break; + } + height--; + break; + } + } + return total; +} + +void main1(const map_t& map) +{ + int total = 0; + sols_t terminals; + terminals.clear(); + for (int8_t r = 0; r < map.size(); r++) + { + for (int8_t c = 0; c < map[r].size(); c++) + { + if (map[r][c] == 0) + { + quick_branch(map, terminals, {r, c}); + total += terminals.size(); + terminals.clear(); + } + } + } + std::cout << "Part1 " << total << std::endl; +} + +void main2(const map_t& map) +{ + int32_t total = 0; + for (int8_t r = 0; r < map.size(); r++) + { + for (int8_t c = 0; c < map[r].size(); c++) + { + if (map[r][c] == 0) + { + total += quick_branch2(map, {r, c}); + } + } + } + std::cout << "Part2 " << total << std::endl; +} + +int main() +{ + map_t map; + load_map(map, "10.txt"); + main1(map); + main2(map); + return 0; +} \ No newline at end of file diff --git a/dotnet/.gitignore b/dotnet/.gitignore new file mode 100644 index 0000000..5e57f18 --- /dev/null +++ b/dotnet/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/dotnet/05/05a.cs b/dotnet/05/05a.cs new file mode 100644 index 0000000..37f2d51 --- /dev/null +++ b/dotnet/05/05a.cs @@ -0,0 +1,167 @@ +void Main1() +{ + var lines = File.ReadAllLines(Path.Join("..", "..", "05a.txt")).Select(l => l.Trim()).ToList(); + if (lines.Last() == "") + lines.RemoveAt(lines.Count - 1); + + List rules = new(); + foreach (var line in lines.TakeWhile(l => !string.IsNullOrWhiteSpace(l))) + { + var parts = line.Split('|'); + rules.Add(new( + int.Parse(parts[0]), + int.Parse(parts[1]) + )); + } + + List collections = new(); + foreach (var line in lines.SkipWhile(l => !string.IsNullOrWhiteSpace(l)).Skip(1)) + { + var parts = line.Split(',').Select(int.Parse); + collections.Add(new(parts)); + } + + int total = 0; + foreach (var collection in collections.Where(c => rules.All(r => c.TestRule(r)))) + { + total += collection.Middle(); + } + + Console.WriteLine(total); +} + +void Main2() +{ + var lines = File.ReadAllLines(Path.Join("..", "..", "05a.txt")).Select(l => l.Trim()).ToList(); + if (lines.Last() == "") + lines.RemoveAt(lines.Count - 1); + + List rules = new(); + RuleList rulelist = new(); + foreach (var line in lines.TakeWhile(l => !string.IsNullOrWhiteSpace(l))) + { + var parts = line.Split('|'); + Rule rule = new( + int.Parse(parts[0]), + int.Parse(parts[1]) + ); + rulelist.Add(rule); + rules.Add(rule); + } + + List collections = new(); + foreach (var line in lines.SkipWhile(l => !string.IsNullOrWhiteSpace(l)).Skip(1)) + { + var parts = line.Split(',').Select(int.Parse); + collections.Add(new(parts)); + } + + var total = 0; + var count = 0; + foreach (var collection in collections) + { + var r = collection.Pairs() + .Select(p => rulelist.ExtractRule(p.Item1, p.Item2)) + .Where(r => r is not null) + .Select(r => (Rule)r) + .ToList(); + if (!rules.All(collection.TestRule)) + { + collection.Pages.Sort(rulelist.Compare); + total += collection.Pages[collection.Pages.Count / 2]; + count++; + } + } + Console.WriteLine($"Collections: {collections.Count}"); + Console.WriteLine($"With errors: {count}"); + Console.WriteLine($"Solution: {total}"); +} + +Main2(); + +record struct Rule(int First, int Second); +class RuleList +{ + Dictionary<(int,int), bool> Rules = new(); + public RuleList() + { + + } + public void Add(Rule rule) + { + bool ordered = rule.First < rule.Second; + var pair = ordered + ? (rule.First, rule.Second) + : (rule.Second, rule.First); + Rules.Add(pair, ordered); + } + //true if correct order, null if no rule + public bool? Check(int a, int b) + { + bool ordered = a < b; + var pair = ordered + ? (a, b) + : (b, a); + bool result; + return Rules.TryGetValue(pair, out result) ? result ^ ordered : null; + } + public int Compare(int a, int b) + { + var check = Check(a, b); + if (check is bool _check) + return _check ? -1 : 1; + return 0; + } + public Rule? ExtractRule(int a, int b) + { + var check = Check(a, b); + if (check is bool _check) + return _check ? new(a, b) : new(b, a); + return null; + } +} +class Collection +{ + public readonly List Pages; + public Collection(IEnumerable pages) + { + Pages = pages.ToList(); + } + public bool TestRule(Rule rule) + { + bool foundFirst = false; + bool foundSecond = false; + foreach (var page in Pages) + { + if (page == rule.First) + { + if (foundSecond) + return false; + foundFirst = true; + } + if (page == rule.Second) + { + if (foundFirst) + return true; + foundSecond = true; + } + } + return true; + } + public int Middle() + { + return Pages[Pages.Count / 2]; + } + public List<(int,int)> Pairs() + { + List<(int,int)> pairs = new(); + for (int i = 0; i < Pages.Count-1; i++) + { + for (int j = i+1; j < Pages.Count; j++) + { + pairs.Add((Pages[i], Pages[j])); + } + } + return pairs; + } +} diff --git a/dotnet/06/06.cs b/dotnet/06/06.cs new file mode 100644 index 0000000..0c3d162 --- /dev/null +++ b/dotnet/06/06.cs @@ -0,0 +1,238 @@ +void Main1() +{ + (var map, var pos) = LoadMap(Path.Join("..", "..", "06a.txt")); + Guard guard = new(pos, Direction.North); + HashSet<(int,int)> visited = new(); + while (map.InBounds(guard.position)) + { + var next = Next(guard); + if (map.Check(next.position)) + { + guard = new(guard.position, guard.direction.Turn()); + continue; + } + else + { + visited.Add(guard.position); + guard = next; + } + } + Console.WriteLine(visited.Count()); +} + +void Main2() +{ + (var map, var pos) = LoadMap(Path.Join("..", "..", "06a.txt")); + Guard guard = new(pos, Direction.North); + // for (int i = 0; i < 4; i++) + // { + // foreach (var obs in map.Obstacles) + // { + // var row = map.GetRow(obs.Item1 + 1).Where(c => c > obs.Item2); + // foreach (var candidate in row) + // { + // var col = map.GetColumn(candidate - 1).Where(r => r > candidate); + // foreach (var third in col) + // { + // var idea = (third - 1, obs.Item2 - 1); + // if (!map.Check(idea)) + // map.Ideas.Add(idea); + // } + // } + // } + // map = map.Rotated(); + // } + // Console.WriteLine($"Ideas {map.Ideas.Count()}"); + int count = 0; + // foreach (var idea in map.Ideas) + // { + // Guard guard = new(pos, Direction.North); + // // the 5th time the guard hits the obstacle, he must have hit twice from the same side + // int hits = 0; + // while (map.InBounds(guard.position)) + // { + // var next = Next(guard); + // if (next.position == idea) + // { + // hits++; + // if (hits >= 5) + // { + // count++; + // break; + // } + // guard = new(guard.position, guard.direction.Turn()); + // } + // else if (map.Check(next.position)) + // { + // guard = new(guard.position, guard.direction.Turn()); + // } + // else + // { + // guard = next; + // } + // } + // } + HashSet<(int,int)> visited = new(); + int ideaIndex = 0; + while (map.InBounds(guard.position)) + { + ideaIndex++; + var next = Next(guard); + if (map.Check(next.position)) + { + guard = new(guard.position, guard.direction.Turn()); + continue; + } + else + { + visited.Add(guard.position); + if (!visited.Contains(next.position) && TestIdea(next.position, guard, map)) + count++; + // Console.WriteLine($"Idea {ideaIndex}"); + guard = next; + } + } + Console.WriteLine($"Solution {count}"); +} + +// Main1(); +Main2(); + +(Map,(int,int)) LoadMap(string filename) +{ + var lines = File.ReadAllLines(filename) + .Where(s => !string.IsNullOrWhiteSpace(s)) + .ToList(); + var guard = (-1,-1); + Map map = new(); + for (int i = 0; i < lines.Count(); i++) + { + for (int j = 0; j < lines[i].Count(); j++) + { + if (lines[i][j] == '#') + map.Add((i, j)); + else if (lines[i][j] == '^') + guard = (i, j); + } + } + map.XBound = lines[0].Count(); + map.YBound = lines.Count(); + return (map, guard); +} + +bool TestIdea((int,int) idea, Guard guard, Map map) +{ + HashSet history = new(); + while (map.InBounds(guard.position)) + { + if (history.Contains(guard)) + return true; + history.Add(guard); + var next = Next(guard); + if (map.Check(next.position) || next.position == idea) + { + guard = new(guard.position, guard.direction.Turn()); + } + else + { + guard = next; + } + } + return false; +} + +//next position IF NO OBSTACLE +Guard Next(Guard guard) +{ + var pos = guard.position; + return new(guard.direction switch + { + Direction.North => (pos.Item1-1, pos.Item2), + Direction.East => (pos.Item1, pos.Item2+1), + Direction.South => (pos.Item1+1, pos.Item2), + Direction.West => (pos.Item1, pos.Item2-1), + _ => throw new Exception(), + }, guard.direction); +} + +class Map +{ + public HashSet<(int,int)> Obstacles = new(); + //1 greater than largest value + public int XBound = 0; + public int YBound = 0; + public HashSet<(int,int)> Ideas = new(); + public Map() + { + + } + public void Add((int,int) obstacle) + { + Obstacles.Add(obstacle); + } + public bool Check((int,int) pos) + { + return Obstacles.Contains(pos); + } + public bool InBounds((int,int) pos) + { + return pos.Item1 >= 0 && pos.Item2 >= 0 + && pos.Item1 < XBound && pos.Item2 < YBound; + } + //get list of columns with an obstacle in this row + public List GetRow(int row) + { + List items = []; + foreach (var pos in Obstacles) + { + if (pos.Item1 == row) + items.Add(pos.Item2); + } + items.Sort(); + return items; + } + //get list of rows with an obstacle in this column + public List GetColumn(int column) + { + List items = []; + foreach (var pos in Obstacles) + { + if (pos.Item2 == column) + items.Add(pos.Item1); + } + items.Sort(); + return items; + } + //counterclockwise rotation + public Map Rotated() + { + (int,int) rotate((int,int) o) => (o.Item2, XBound - o.Item1); + Map newmap = new(); + newmap.Obstacles = new(Obstacles.Select(rotate)); + newmap.Ideas = new(Ideas.Select(rotate)); + newmap.XBound = YBound; + newmap.YBound = XBound; + return newmap; + } +} + +enum Direction +{ + North, + East, + South, + West, +} +readonly record struct Guard((int,int) position, Direction direction); + +static class Extensions +{ + public static Direction Turn(this Direction direction) + { + return direction switch + { + Direction.West => Direction.North, + Direction d => d + 1, + }; + } +} diff --git a/dotnet/07/07a.cs b/dotnet/07/07a.cs new file mode 100644 index 0000000..bb75b51 --- /dev/null +++ b/dotnet/07/07a.cs @@ -0,0 +1,263 @@ +void Main1() +{ + var eqs = LoadEqs(Path.Join("..", "..", "07a.txt")); + long total = 0; + foreach (var eq in eqs) + { + if (eq.Test1()) + { + total += eq.Target; + } + } + Console.WriteLine($"Solution {total}"); +} + +void Main2() +{ + var eqs = LoadEqs(Path.Join("..", "..", "07a.txt")); + long total = 0; + foreach (var eq in eqs) + { + if (eq.Test2()) + { + total += eq.Target; + } + } + Console.WriteLine($"Solution1 {total}"); +} + +void Main2_take2() +{ + var eqs = LoadEqs(Path.Join("..", "..", "07a.txt")); + long total = 0; + foreach (var eq in eqs) + { + if (eq.Test3()) + { + total += eq.Target; + } + } + Console.WriteLine($"Solution (exp) {total}"); +} + +void Main2_take3() +{ + var eqs = LoadEqs(Path.Join("..", "..", "07a.txt")); + long total = 0; + foreach (var eq in eqs) + { + if (eq.Test4()) + { + total += eq.Target; + } + } + Console.WriteLine($"Solution {total}"); +} + +void Main2_take2and3() +{ + var eqs = LoadEqs(Path.Join("..", "..", "07a.txt")); + long total = 0; + foreach (var eq in eqs) + { + var t3 = eq.Test3(); + var t4 = eq.Test4(); + if (t3 != t4) + { + Console.WriteLine((t4 ? "Pass " : "Fail ") + eq.ToString()); + } + } +} + +// Main1(); +Main2(); +// Main2_take2(); +// Main2_take3(); +// Main2_take2and3(); + +List LoadEqs(string filepath) +{ + var lines = File.ReadAllLines(filepath).ToList(); + if (string.IsNullOrWhiteSpace(lines.Last())) + lines.RemoveAt(lines.Count()-1); + List eqs = new(); + foreach (var line in lines) + { + var parts = line.Split(':'); + eqs.Add(new( + long.Parse(parts[0]), + parts[1].Trim().Split(' ').Select(long.Parse) + )); + } + return eqs; +} + +class EQ +{ + public long Target; + public List Terms; + public EQ(long target, IEnumerable terms) + { + Target = target; + Terms = terms.ToList(); + } + public override string ToString() + { + return $"{Target}: {string.Join(' ', Terms)}"; + } + public bool Test1() + { + return InnerTest1(Target, Terms.First(), Terms.Skip(1)); + } + private static bool InnerTest1(long target, long current, IEnumerable terms) + { + if (current > target) + return false; + var term = terms.Cast().FirstOrDefault(); + if (term is long _term) + { + return InnerTest1(target, current + _term, terms.Skip(1)) + || InnerTest1(target, current * _term, terms.Skip(1)); + } + else + { + return target == current; + } + } + public bool Test2() + { + return InnerTest2(Target, Terms.First(), Terms, 1); + } + private static bool InnerTest2(long target, long current, IList terms, int index) + { + if (current > target) + return false; + if (index >= terms.Count()) + return target == current; + var term = terms[index]; + return InnerTest2(target, current + term, terms, index + 1) + || InnerTest2(target, current * term, terms, index + 1) + || InnerTest2(target, Concat(current, term), terms, index + 1); + } + public bool Test3() + { + return InnerTest3(Target, Terms.First(), Terms.Skip(1)) == Result.Success; + } + private static Result InnerTest3(long target, long current, IEnumerable terms) + { + if (current > target) + return Result.AllOverflow; + var term = terms.Cast().FirstOrDefault(); + var remaining = terms.Skip(1); + if (term is long _term) + { + return current switch + { + 1 => InnerTest3(target, _term, remaining) switch + { + Result.MixedFailures => InnerTest3(target, 1 + _term, remaining) switch + { + Result.Success => Result.Success, + Result.AllOverflow => Result.MixedFailures, + _ => InnerTest3(target, Concat(1, _term), remaining) switch + { + Result.Success => Result.Success, + _ => Result.MixedFailures, + }, + }, + Result res => res, + }, + 0 => InnerTest3(target, 0, remaining) switch + { + Result.MixedFailures => InnerTest3(target, _term, remaining) switch + { + Result.Success => Result.Success, + _ => Result.MixedFailures, + }, + Result res => res, + }, + long _current => _term switch + { + 1 => InnerTest3(target, _current, remaining) switch + { + Result.MixedFailures => InnerTest3(target, _current + 1, remaining) switch + { + Result.Success => Result.Success, + Result.MixedFailures => InnerTest3(target, _current * 10 + 1, remaining) switch + { + Result.Success => Result.Success, + _ => Result.MixedFailures, + }, + _ => Result.MixedFailures, + }, + Result res => res, + }, + _ => InnerTest3(target, _current + _term, remaining) switch + { + Result.MixedFailures => InnerTest3(target, _current * _term, remaining) switch + { + Result.Success => Result.Success, + Result.AllOverflow => Result.MixedFailures, + _ => InnerTest3(target, Concat(_current, _term), remaining) switch + { + Result.Success => Result.Success, + _ => Result.MixedFailures, + }, + }, + Result res => res, + }, + }, + }; + } + else + { + return (target - current) switch + { + //should be impossible due to earlier check + < 0 => Result.AllOverflow, + 0 => Result.Success, + > 0 => Result.MixedFailures, + }; + } + } + + private static long Concat(long first, long second) + { + return first * Shift(second) + second; + } + public bool Test4() + { + return InnerTest4(Target, Terms, Terms.Count() - 1); + } + private static bool InnerTest4(long current, IList terms, int index) + { + long term = terms[index]; + if (index == 0) + return current == term; + if (InnerTest4(current - term, terms, index - 1)) + return true; + if (current % term == 0 && InnerTest4(current / term, terms, index - 1)) + return true; + var shift = Shift(term); + if ((current % shift == term) && InnerTest4(current / shift, terms, index - 1)) + return true; + return false; + } + private static long Shift(long num) + { + var digits = ((long)Math.Log10(num+0.5)) + 1; + long shift = 1; + while (digits > 0) + { + shift *= 10; + digits--; + } + return shift; + } + enum Result + { + AllOverflow, + MixedFailures, + Success, + } +} diff --git a/dotnet/08/08a.cs b/dotnet/08/08a.cs new file mode 100644 index 0000000..d028eed --- /dev/null +++ b/dotnet/08/08a.cs @@ -0,0 +1,174 @@ +Main1(); +Main2(); + + +void Main1() +{ + var map = LoadMap(Path.Join("..", "..", "08a.txt")); + HashSet antinodes = new(); + foreach (var (ch, points) in map.Antennae) + { + for (int i = 0; i < points.Count-1; i++) + { + for (int j = i+1; j < points.Count; j++) + { + antinodes.UnionWith(points[i].GetAntinodes(points[j]).Where(map.Validate)); + } + } + } + Console.WriteLine($"Solution {antinodes.Count}"); +} + +void Main2() +{ + var map = LoadMap(Path.Join("..", "..", "08a.txt")); + HashSet antinodes = new(); + foreach (var (ch, points) in map.Antennae) + { + for (int i = 0; i < points.Count-1; i++) + { + for (int j = i+1; j < points.Count; j++) + { + antinodes.UnionWith(points[i].GetAntinodes2(points[j], map)); + } + } + } + Console.WriteLine($"Solution {antinodes.Count}"); +} + +Map LoadMap(string filepath) +{ + var lines = File.ReadAllLines(filepath) + .Where(l => !string.IsNullOrWhiteSpace(l)) + .Select(s => s.Trim()) + .ToList(); + Map map = new(); + foreach (var (line, row) in lines.Select((l, i) => (l, i))) + { + foreach (var (c, col) in line.Select((ch, i) => (ch, i))) + { + if (c != '.') + { + Point p = new(row, col); + if (map.Antennae.TryGetValue(c, out var points)) + { + points.Add(p); + } + else + { + map.Antennae[c] = new(Enumerable.Repeat(p, 1)); + } + } + } + } + map.Width = lines[0].Length; + map.Height = lines.Count; + return map; +} + +public static class Stuff +{ + //I forgot the good algorithm + public static int TerribleGcf(int first, int second) + { + int gcf = 1; + while (first % 2 == 0 && second % 2 == 0) + { + gcf *= 2; + first /= 2; + second /= 2; + } + for (int prime = 3; prime < first && prime < second; prime += 2) + { + while (first % prime == 0 && second % prime == 0) + { + gcf *= prime; + first /= prime; + second /= prime; + } + } + return gcf; + } + //I had to look up the right way + public static int EuclideanGcf(int first, int second) + { + if (first == 0 || second == 0) + return 0; + first = Math.Abs(first); + second = Math.Abs(second); + while (first != second) + { + if (second > first) + { + first = first ^ second; + second = first ^ second; + first = first ^ second; + } + first = first - second; + } + return first; + } +} + +class Map +{ + public Dictionary> Antennae = new(); + public int Width; + public int Height; + public Map() + { + + } + public bool Validate(Point p) + => p.Row >= 0 && p.Row < Width && p.Col >= 0 && p.Col < Height; +} + +record struct Point(int Row, int Col) +{ + public static Vector operator -(Point first, Point second) + => new(first.Row - second.Row, first.Col - second.Col); + public static Point operator +(Point first, Vector second) + => new(first.Row + second.Row, first.Col + second.Col); + public static Point operator -(Point first, Vector second) + => new(first.Row - second.Row, first.Col - second.Col); + public readonly IEnumerable GetAntinodes(Point other) + { + var diff = this - other; + yield return this + diff; + yield return other - diff; + if (diff.Row % 3 == 0 && diff.Col % 3 == 0) + { + Console.WriteLine("inline"); + yield return other + (diff / 3); + yield return other + (diff * 2 / 3); + } + } + public IEnumerable GetAntinodes2(Point other, Map map) + { + var diff = this - other; + // diff /= Stuff.TerribleGcf(diff.Row, diff.Col); + diff /= Stuff.EuclideanGcf(diff.Row, diff.Col); + var running = this; + while (map.Validate(running)) + { + yield return running; + running -= diff; + } + running = this + diff; + while (map.Validate(running)) + { + yield return running; + running += diff; + } + } +} + +record struct Vector(int Row, int Col) +{ + public static Vector operator +(Vector first, Vector second) + => new(first.Row + second.Row, first.Col + second.Col); + public static Vector operator *(Vector first, int second) + => new(first.Row * second, first.Col * second); + public static Vector operator /(Vector first, int second) + => new(first.Row / second, first.Col / second); +} \ No newline at end of file diff --git a/dotnet/09/09.cs b/dotnet/09/09.cs new file mode 100644 index 0000000..85fde14 --- /dev/null +++ b/dotnet/09/09.cs @@ -0,0 +1,138 @@ +using System.Numerics; +using System.Security.Cryptography.X509Certificates; + +// Main1(); +Main2(); + +void Main1() +{ + var data = LoadData1(Path.Join("..", "..", "09a.txt")); + int i = 0; + int j = data.Length - 1; + while (i < j) + { + if (data[i] == -1) + { + while (data[j] == -1) + j--; + data[i] = data[j]; + data[j] = -1; + } + i++; + } + i--; + BigInteger checksum = 0; + while (i >= 0) + { + if (data[i] < 0) + throw new Exception($"Index {i} Value {data[i]}"); + checksum += i * data[i]; + i--; + } + Console.WriteLine($"Part1: {checksum,15}"); +} + +void Main2() +{ + var (files, empties) = LoadData2(Path.Join("..", "..", "09a.txt")); + for (int i = files.Count-1; i >= 1; i--) + { + var file = files[i]; + for (int j = 0; j < empties.Count; j++) + { + var empty = empties[j]; + if (file.Location < empty.Location) + break; + if (file.Length <= empty.Length) + { + file.Location = empty.Location; + empties[j] = new(empty.Location + file.Length, empty.Length - file.Length); + break; + } + } + } + //long is big enough but changing it didn't help execution time so... + BigInteger checksum = 0; + foreach (var f in files) + { + for (int i = 0; i < f.Length; i++) + { + checksum += f.Id * (f.Location + i); + } + } + Console.WriteLine($"Part2: {checksum,15}"); +} + +int[] LoadData1(string filepath) +{ + int next_id = 0; + bool next_is_blank = false; + int GetId() + { + if (next_is_blank) + { + next_is_blank = false; + return -1; + } + else + { + next_is_blank = true; + return next_id++; + } + } + var data = File.ReadAllText(filepath).Trim().SelectMany(c => Enumerable.Repeat(GetId(), c - '0')).ToArray(); + return data; +} + +(List,List) LoadData2(string filepath) +{ + short next_id = 0; + bool next_is_blank = false; + int location = 0; + List files = []; + List empties = []; + foreach (char c in File.ReadAllText(filepath).Trim()) + { + int length = c - '0'; + if (next_is_blank) + { + if (length > 0) + empties.Add(new (location, length)); + next_is_blank = false; + location += length; + } + else + { + next_is_blank = true; + if (length > 0) + files.Add(new (location, length, next_id)); + location += length; + next_id++; + } + } + return (files,empties); +} + +class Filelike(int Location, int Length, short Id) +{ + public int Location = Location; + public int Length = Length; + public short Id = Id; +} +class Empty(int Location, int Length) +{ + public int Location = Location; + public int Length = Length; +} + +// class Filelike(int Location, int Length, int Id) +// { +// public int Location = Location; +// public int Length = Length; +// public int Id = Id; +// } +// class Empty(int Location, int Length) +// { +// public int Location = Location; +// public int Length = Length; +// } \ No newline at end of file