From b0e761fb7aa409865b87039937bb1eaec9f1469d Mon Sep 17 00:00:00 2001 From: James Griffin Date: Wed, 15 Dec 2021 20:20:15 +0000 Subject: [PATCH] Part 1 and first pass at Part 2 --- README.md | 10 ++ fifteen/input.txt | 100 +++++++++++++++++++ fifteen/main.go | 25 +++++ fifteen/path.go | 215 +++++++++++++++++++++++++++++++++++++++++ fifteen/path_test.go | 44 +++++++++ fifteen/test_input.txt | 10 ++ main.go | 3 + 7 files changed, 407 insertions(+) create mode 100644 fifteen/input.txt create mode 100644 fifteen/main.go create mode 100644 fifteen/path.go create mode 100644 fifteen/path_test.go create mode 100644 fifteen/test_input.txt diff --git a/README.md b/README.md index f35a75a..0c16107 100644 --- a/README.md +++ b/README.md @@ -153,3 +153,13 @@ The solution for "fourteen" is: The result of subtracting the least from most common element quantities is 2988 The result of subtracting the least from most common element quantities is 3572761917024 ``` + +### Day fifteen + +```sh +$ ./aoc2021 --fifteen +The solution for "fifteen" is: +fifteen part 1 answer for path +fifteen part 2 answer for path +``` + diff --git a/fifteen/input.txt b/fifteen/input.txt new file mode 100644 index 0000000..bcc5b80 --- /dev/null +++ b/fifteen/input.txt @@ -0,0 +1,100 @@ +1153122486338196417261639921288211131723142991381714663988573539371125147579911789799911191116969182 +1831332932365721112271938859551961274184513439211372318789319176946137219492492161941188122228928142 +9821911543414142186827941122266167714126412612261328558992198212729611567923298114131222451713511114 +7246861617121926197913771333862216431691242331821373133472917112415411291112194329821255594119385913 +7283532811518311511133564162553362112249591513461311252729218443397781539589433111319711824661393631 +2515929137212718342949516922111713621859318118719617839125124564721161658335944181553941811143591517 +4916512552144322517215234299958319381621661767349167411222321248229439251953192958644239143882919241 +6262117322113477913692595649873914143546632433711128717141141195552948491953485631229194119276499991 +7392251899873812797958691238437453551415231331821364182879918291981738573962231152511911211128951113 +8413992251188993837397124261942199712837511841216512261395311785116811331719185479137512367447923291 +5231148122926582218424829117852548196215169569393712471373474748341292612868417935562413892295951885 +6969394124432223195175331296521928139597331582718251211495645114941612246194231312174117214121281842 +1492115983511981562257418211112925117322921195483112122256639228399618419541416852185938991328915818 +3337387528424632949433449211831892186689931141431821341112121116121183221372428184716111222586158651 +2919993831163121652312168296893876448879562949946693212289822132922233191147264817817431124414532533 +9831131365513121681981321111241225246211721245114513343139123311189247841338544122968113145391142716 +1727694314953352984564533684197836278119128336766459163262254212898918649112624992813951781316416374 +2271812917172151781117223114852112121981121667671421934421226898295554752996914271128911169789451951 +9641181231223141385164135392637559471954819529821233561311577143643837514229221871189471954194331152 +4842773719613551934224188641425166389122136165128121415358911721153164127212813948168736781136952951 +1192227966237198835311112231914836119223535631325132172552427754922112812179423656275381194611522453 +4587521661134142224185212119671223232647264672526518611961218313988518799959611424294177988911237867 +7841978128159981542211119531397179123564484381479727821915161363181216177352158299813648446813627222 +7284166795958241131999192919211621771144435542434154129323533329121215444282759763242637299473619699 +1521878281243112584389365171394192883659218227373853328197872435319181781919941925172732491338886311 +1327321441516991964782129484116368713248197522187147122388963111996334499727625711211235126217275463 +5432221784759463981982328941214217778116531411971739126861352255217191611697312757994113151311379972 +1185912419912167768598675227235243957241898718929234342122112138667448683289595212416151634918119782 +2142391197693165425931997914283877473934922668732952746725116377382215211222574165995121111118383226 +2517671922159312542191175127158214971341213911213276212516415975771618811321511144775331189114464662 +7422195152192114261215487181219928252132916876218849814118182116115931338892173123147871155216241119 +3619695411396123442155212519261891139921251199959962859246511384671182317569141243719313574613299114 +2895333123772993112294182624661491247795159971883633469119158351982981542649324118914796267121748913 +1421145424229377289371813129244589145113287748254253711637741529919416291278816369198475199772891934 +4226139942429431915575192843585749419348133173935216599874822673919238822771191128122524833751214529 +1682417751943991485271671248268311378571948341453293291196141934239152143595141717431161329855424112 +9916921853141162653286394526948121272378729683198391723494146711544133983626379417921189376352821798 +3251721727717131197339261311211519541459852173796114841169131848229719476992898439988142411881982514 +4224411911215323811873118144131911362211323994194273231611315238461136131411252251162414111299942115 +2245998155138161121631272285319936718281123752141998833128632147447117622119239893148242825136988411 +5128199191117746931424197696535944336182191931232292669562695112789951271493241291449919211342319956 +6185982121672329189115713515854662969113811769468312383127983222331916531821851915411131158716583266 +5447295461711381231589918947462282687649213121842921247116618391182167591292292272427141281715111177 +8257924948412473451961749898696413137392994416792374818227237143259116197488773961321624141163921432 +5189182291437314198489212141482184531697461226931512711191277526274712938812991613191947812232211244 +4555193184311911877999628197321551669874119131381183472179843972338461241911119924731168169352182272 +1121437621439149119353295941221222611786169917291122315558611419191633395499286111392381131171511238 +3181921181713184161942383164918982475421419929329239389548923261242417419233827235774153744131399151 +2144212113563135873312739193234226974131375159978272831447529333649424911425997613845276711174127394 +3139444361591195812958262711719931339591119823111113659752771219379921513182322111739482111579992212 +5621114341514728539451953111111724132613731214322289351224233177342291112529731353511549332152218981 +6158168164191463855184279714113662914367391459179668815811157124186552341548726599639264298312521815 +1995166266961996427961626535695212999191152112511338187611994115221111513691288611241921111251372396 +1339761931754125912894291611219167392229911558394529712234844524138351824911642926117836229449412319 +9127349377251112496211472777128795852299174781996397114134149188119193322618691616951273511925125149 +8979991927511499882118151229977284915581711491442571271831929283464123921696618123459172952156541118 +1911692955379514126841178174387511771789182282127314533841585231141954116191778276825221831612429254 +5812355192199983562136559621645794551755421236216311141149191254313741187262232164511315391297811915 +3424115732536482892978161186279711991592926127111589527519294376927741975118126955891355141746112114 +6989941658111289514721269122153856231312841221973781139894173114171591227833319376143957344117411911 +6125319278191932229114977252161577595177236842461172428859131892491678152164849198117325377432911476 +1152159324115134285596152231419112191947931122416535331212222762281719735281322382683941829919252797 +1119721171315374228473139951219963744542691955341851975111136422261596313992998971487819823291188481 +7916691142991816614421279131181771221333191348939869225827422531914334297979111781117184291912141817 +4459327512328523319571281171326141578961259819944448411558661132918284758431913397353129322141161339 +2636366417937791462122113461636413998893541599942374691221751914312218911394582119131724772161614249 +2312134166373181653911821772162314821142231391492122319111729983112421444715911629144339121416957937 +3112516582317416535542536957174341267787173494338391217911299591219692263281699341161832522294199592 +9514591666441193718119658181314241938166223118279113851527114813726452723842267929929348492111811581 +2482729124382111776179548733255881848149314161382118317221111921159882699921428496911916531781511634 +9673188569811459713271234169339644147411196161312836419131114224582591681121732551983658361231121738 +5977261429276572591351918817394787862812237116862142154391916283123565283389128193466927821786719949 +1769231445614929166298921531456368161915897211818781845929893127147256121829334316761162311125197837 +1312932111292124723831423127589975348261278421245946222431414328266141181139541218291313371199864618 +1591541125718121791926128149145611995157614226342145453466331146123719411716214432222151824877286273 +5619772119639321277117794132142411693117313872211776175416651697194197314115755297937932111148312514 +3178155419234246512532322711217369829144825612481941883499963679121511192214851616393725262185717671 +8114544152321812691913671222116334143125135245317392176495119442215315158941951195112914646111416558 +2741424121962339159791233465491165831161141431641127346424975111522251556164932982924154345265421893 +9921292358581466829119129911354441116986795112151124693382512674629191214183823931133116279292839481 +4569992111222111767136498792647332989342421348986559111618194724271412113395213251221446621936113217 +4991122344121493911982135121517399926352621891628211138999762133631115524112414391988299737366143123 +1114219232723168147329499525731115791152145213242183484163395711685154619941295185822161212821127794 +3839939524162212272145271115941119628111292192143171182921748857216541211912191929681297597929989911 +6189222318123913691725491531195561764199223114289691819733939824312544261311413928241912419255471755 +6426739442179681969621433347831187114554482194517792954314812523872919511933951481153159254111697312 +3891136638118997612371161161869992758221428676819193193631251844929339437511925493964819195151911142 +3115528121186224125618416185811129492665191334214154857416725217848287113213313571291989451911312351 +1921697432735261814811926199115788283324123249786652194311225419818513851175191913114233615261679173 +9444991493136334111115319771955169591434195411111175815119829517874288512561129573999727849941111891 +1431112211573298299618391113146347462491189192712317692165138111135921811621112921281114883152314218 +5349597921218431142281944271195411131831918391119511453181163891916131323533571231586827199329874375 +2393311319453249344541783217229449844183323339879189832259959321537131883822116122414429411226898557 +5457346279314981225362682181133799953141791522219253884328373198344561547931335524431911513277866156 +9699896735252183122231391818121491312934119311392547291169316419871163336631292698139515916993934313 +8556743922581192811645225163415825162574946272881497914233171916774511883981111996335911294624327449 +7521896193918149224732111989318369361944639558148182889252323156955979551215231329134223563528193297 +1911494977559119125389742991144919361368163938188656739221192361834613121494215789387959266616116631 +9511636215215555892846453398163358213162129919192181114219891142443311555291982463217261131119391179 +1549621141231921135259218425986586892253161313771915914851811321611989191411321126995515519721279591 \ No newline at end of file diff --git a/fifteen/main.go b/fifteen/main.go new file mode 100644 index 0000000..3b55855 --- /dev/null +++ b/fifteen/main.go @@ -0,0 +1,25 @@ +package fifteen + +import "fmt" + +type Fifteen struct { + path path +} + +func Init(filepath string) *Fifteen { + fifteen := &Fifteen{ + path: path{}, + } + + fifteen.path.load(filepath) + return fifteen +} + +func (d *Fifteen) Answer() string { + return fmt.Sprintf("The total risk of the least risky path is %d", d.path.totalRisk()) +} + +func (d *Fifteen) FollowUp() string { + scaled := d.path.scale(5, 5) + return fmt.Sprintf("The total risk of the least risky path is %d", scaled.totalRisk()) +} diff --git a/fifteen/path.go b/fifteen/path.go new file mode 100644 index 0000000..7a53d3d --- /dev/null +++ b/fifteen/path.go @@ -0,0 +1,215 @@ +package fifteen + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +type path struct { + riskLevel [][]int + width int + height int +} + +type point struct { + x int + y int +} + +func (p *path) load(filename string) error { + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + + p.riskLevel = [][]int{} + for scanner.Scan() { + row := []int{} + for _, n := range strings.Split(scanner.Text(), "") { + v, err := strconv.Atoi(string(n)) + if err != nil { + return err + } + + row = append(row, v) + } + p.riskLevel = append(p.riskLevel, row) + } + + p.height = len(p.riskLevel) + p.width = len(p.riskLevel[0]) + + return nil +} + +func (p *path) scale(sizeX int, sizeY int) *path { + scaledPath := &path{ + width: p.width * sizeX, + height: p.height * sizeY, + } + + scaledPath.riskLevel = make([][]int, scaledPath.height) + for i := 0; i < scaledPath.height; i++ { + scaledPath.riskLevel[i] = make([]int, scaledPath.width) + } + + for i := 0; i < sizeX; i++ { + for j := 0; j < sizeY; j++ { + for y := 0; y < p.height; y++ { + for x := 0; x < p.width; x++ { + risk := p.riskLevel[y][x] + i + j + for risk > 9 { + risk -= 9 + } + + scaledPath.riskLevel[(j*p.height)+y][(i*p.width)+x] = risk + } + } + } + } + + return scaledPath +} + +func (p *path) print() { + for y := 0; y < p.height; y++ { + row := "" + for x := 0; x < p.width; x++ { + row += fmt.Sprintf("%d", p.riskLevel[y][x]) + } + fmt.Println(row) + } +} + +func (p *path) totalRisk() int { + start := point{ + x: 0, + y: 0, + } + end := point{ + x: p.width - 1, + y: p.height - 1, + } + + path := p.path(start, end) + total := 0 + + for i, point := range path { + if i == 0 { + continue + } + total += p.riskLevel[point.y][point.x] + } + + return total +} + +func minValue(distance map[point]int, nodes []point) (point, []point) { + var min *point + remaining := []point{} + + for i := range nodes { + if min == nil { + min = &nodes[i] + continue + } + + if distance[nodes[i]] < distance[*min] { + remaining = append(remaining, *min) + min = &nodes[i] + } else { + remaining = append(remaining, nodes[i]) + } + } + + return *min, remaining +} + +func contains(nodes []point, x int, y int) bool { + for _, n := range nodes { + if n.x == x && n.y == y { + return true + } + } + return false +} + +func (p *path) path(start point, end point) []point { + dist := map[point]int{} + prev := map[point]point{} + nodes := []point{} + + for y := 0; y < p.height; y++ { + for x := 0; x < p.width; x++ { + point := point{x: x, y: y} + // Virtually infinite for worst case + dist[point] = 10 * (p.width + p.height) + nodes = append(nodes, point) + } + } + dist[start] = 0 + + for len(nodes) > 0 { + current, newNodes := minValue(dist, nodes) + + // Check neigbours + neighbours := []point{} + // left + if current.x > 0 && contains(newNodes, current.x-1, current.y) { + left := point{ + x: current.x - 1, + y: current.y, + } + neighbours = append(neighbours, left) + } + // up + if current.y > 0 && contains(newNodes, current.x, current.y-1) { + up := point{ + x: current.x, + y: current.y - 1, + } + neighbours = append(neighbours, up) + } + // right + if current.x < p.width-1 && contains(newNodes, current.x+1, current.y) { + right := point{ + x: current.x + 1, + y: current.y, + } + neighbours = append(neighbours, right) + } + // down + if current.y < p.height-1 && contains(newNodes, current.x, current.y+1) { + down := point{ + x: current.x, + y: current.y + 1, + } + neighbours = append(neighbours, down) + } + + for _, n := range neighbours { + cost := dist[current] + p.riskLevel[n.y][n.x] + if cost < dist[n] { + dist[n] = cost + prev[n] = current + } + } + + nodes = newNodes + } + + path := []point{end} + index := end + for index != start { + prefix := []point{prev[index]} + path = append(prefix, path...) + index = prev[index] + } + + return path +} diff --git a/fifteen/path_test.go b/fifteen/path_test.go new file mode 100644 index 0000000..b5b39ea --- /dev/null +++ b/fifteen/path_test.go @@ -0,0 +1,44 @@ +package fifteen + +import "testing" + +func Test_read(t *testing.T) { + p := path{} + if err := p.load("test_input.txt"); err != nil { + t.Log(err) + t.FailNow() + } + + if len(p.riskLevel) != 10 { + t.Logf("Expected 10 rows, found %d", len(p.riskLevel)) + t.Fail() + } + + if len(p.riskLevel[0]) != 10 { + t.Logf("Expected 10 rows, found %d", len(p.riskLevel[0])) + t.Fail() + } +} + +func Test_totalRisk(t *testing.T) { + p := path{} + p.load("test_input.txt") + + if value := p.totalRisk(); value != 40 { + t.Logf("Expected a total risk of 40, found %d", value) + t.Fail() + } +} + +func Test_totalRiskScaled(t *testing.T) { + p := path{} + p.load("test_input.txt") + p = *p.scale(5, 5) + + p.print() + + if value := p.totalRisk(); value != 315 { + t.Logf("Expected a total risk of 315, found %d", value) + t.Fail() + } +} \ No newline at end of file diff --git a/fifteen/test_input.txt b/fifteen/test_input.txt new file mode 100644 index 0000000..7d9d562 --- /dev/null +++ b/fifteen/test_input.txt @@ -0,0 +1,10 @@ +1163751742 +1381373672 +2136511328 +3694931569 +7463417111 +1319128137 +1359912421 +3125421639 +1293138521 +2311944581 \ No newline at end of file diff --git a/main.go b/main.go index 35036ad..5579cb5 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "unsupervised.ca/aoc2021/eight" "unsupervised.ca/aoc2021/eleven" + "unsupervised.ca/aoc2021/fifteen" "unsupervised.ca/aoc2021/five" "unsupervised.ca/aoc2021/four" "unsupervised.ca/aoc2021/fourteen" @@ -64,6 +65,8 @@ func main() { day = thirteen.Init("thirteen/input.txt") case "fourteen": day = fourteen.Init("fourteen/input.txt") + case "fifteen": + day = fifteen.Init("fifteen/input.txt") default: fmt.Printf("%q does not have a solution.\n", flagParts[1]) help()