diff --git a/2022/R/day16.qmd b/2022/R/day16.qmd index a81833a..d997bd6 100644 --- a/2022/R/day16.qmd +++ b/2022/R/day16.qmd @@ -27,14 +27,135 @@ input <- read_lines("../input/day16.txt", skip_empty_rows = TRUE) |> ## Part 1 +Represent tunnels and valves as a graph: + ```{r} -edges <- input |> + +g <- input |> unnest(target) |> pmap(function(source, target, ...) c(source, target)) |> unique() |> unlist() |> - make_graph(directed = TRUE) + make_graph(directed = TRUE) |> + as_undirected() + +``` + +Get the list of valves with nonzero flow: + +```{r} + +flows <- input |> + filter(rate > 0 | source == "AA") |> + select(source, rate) |> + deframe() + +non_init_flows <- flows |> + discard_at("AA") + +valves <- names(flows) + +dists <- distances(g, valves, valves) + +``` + +List all permutations of possible valves to visit with a total distance less than 30: + +```{r} + +get_path <- function(choices, last, cur_length, max_length) { + if (cur_length >= max_length) + return(head(last, -1)) + if (length(choices) == 0) + return(last) + + ls <- list() + for (valve in choices) { + ls <- append( + ls, + list(get_path( + choices[choices != valve], + c(last, valve), + cur_length + dists[tail(last, 1), valve] + 1, + max_length + )) + ) + } + ls |> + discard(is_null) |> + list_flatten() |> + unique() +} + +combos <- get_path(names(non_init_flows), names(flows["AA"]), 0, 30) + +``` + +Compute total pressure released for each permutation: + +```{r} + +get_pressures <- function(paths, max_time) { + map_dbl(paths, \(path) { + valve <- tail(path, -1) + valve_lag <- head(path, -1) + flow <- tail(flows[path], -1) + + dist <- map2_int(valve_lag, valve, \(src, target) dists[src, target]) + time_start <- cumsum(dist) + 1:length(dist) + 1 + pressure <- (max_time - time_start + 1) * flow + + sum(pressure[time_start <= max_time]) + }) +} + +pressures <- get_pressures(combos, 30) + +``` + +Find the permutation that gives the maximum pressure: + +```{r} + +max_idx <- which.max(pressures) +pressures[max_idx] + +``` + +## Part 2 + +List all permutations of possible valves to visit with a total distance less than 26: + +```{r} + +el_combos <- get_path(names(non_init_flows), names(flows["AA"]), 0, 26) +el_pressures <- get_pressures(el_combos, 26) + +``` + +For each set of permutations, get the best pressure. + +```{r} + +el_best <- tibble(valves = map(el_combos, sort), pressure = el_pressures) |> + slice_max(pressure, by = valves, with_ties = FALSE) + +``` + +Get best combinations of permutations between yourself and the elephant: + +```{r} + +el_best |> + rename(el_valves = valves, el_pressure = pressure) |> + pmap_dbl(\(el_valves, el_pressure) { + el_valves <- el_valves[el_valves != "AA"] + el_pressure + el_best |> + filter(map_lgl(valves, ~ length(intersect(.x, el_valves)) == 0)) |> + pull(pressure) |> + max() + }) |> + max() -plot(edges) ``` diff --git a/2022/R/day17.qmd b/2022/R/day17.qmd new file mode 100644 index 0000000..416f18d --- /dev/null +++ b/2022/R/day17.qmd @@ -0,0 +1,24 @@ +--- +title: "Day 17" +date: 2022-12-17 +author: + name: https://adventofcode.com/2022/day/17 + url: https://adventofcode.com/2022/day/17 +--- + +## Setup + +```{r setup} + +# Libraries +library(tidyverse) + +# Read input from file +input <- read_lines("../input/day17.txt", skip_empty_rows = TRUE) + +``` + +```{r} + +``` + diff --git a/2022/input/day16.txt b/2022/input/day16.txt index 9f30acc..12c97e4 100644 --- a/2022/input/day16.txt +++ b/2022/input/day16.txt @@ -1,10 +1,61 @@ -Valve AA has flow rate=0; tunnels lead to valves DD, II, BB -Valve BB has flow rate=13; tunnels lead to valves CC, AA -Valve CC has flow rate=2; tunnels lead to valves DD, BB -Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE -Valve EE has flow rate=3; tunnels lead to valves FF, DD -Valve FF has flow rate=0; tunnels lead to valves EE, GG -Valve GG has flow rate=0; tunnels lead to valves FF, HH -Valve HH has flow rate=22; tunnel leads to valve GG -Valve II has flow rate=0; tunnels lead to valves AA, JJ -Valve JJ has flow rate=21; tunnel leads to valve II +Valve RT has flow rate=0; tunnels lead to valves EN, LZ +Valve VB has flow rate=0; tunnels lead to valves SZ, BF +Valve AD has flow rate=0; tunnels lead to valves EB, JF +Valve RE has flow rate=4; tunnels lead to valves QB, IF, XT, WF, KW +Valve RL has flow rate=0; tunnels lead to valves DQ, LZ +Valve OK has flow rate=0; tunnels lead to valves QH, BF +Valve RV has flow rate=0; tunnels lead to valves IU, JF +Valve TE has flow rate=0; tunnels lead to valves HE, XF +Valve WW has flow rate=0; tunnels lead to valves QH, YZ +Valve HB has flow rate=15; tunnel leads to valve OM +Valve IY has flow rate=14; tunnels lead to valves UH, KW, BN, LW, UY +Valve QF has flow rate=0; tunnels lead to valves JF, PL +Valve YZ has flow rate=0; tunnels lead to valves JG, WW +Valve QB has flow rate=0; tunnels lead to valves SP, RE +Valve SO has flow rate=0; tunnels lead to valves QH, SZ +Valve EB has flow rate=7; tunnels lead to valves IF, NH, AD, VI, DQ +Valve VL has flow rate=0; tunnels lead to valves JF, YV +Valve BF has flow rate=18; tunnels lead to valves OK, VB, OH, SX +Valve UC has flow rate=0; tunnels lead to valves SC, YV +Valve OQ has flow rate=0; tunnels lead to valves XT, AA +Valve YV has flow rate=6; tunnels lead to valves YX, TT, VL, UC, NH +Valve KJ has flow rate=0; tunnels lead to valves OH, JG +Valve QH has flow rate=20; tunnels lead to valves SO, OK, WW +Valve KW has flow rate=0; tunnels lead to valves RE, IY +Valve PL has flow rate=0; tunnels lead to valves JG, QF +Valve DQ has flow rate=0; tunnels lead to valves EB, RL +Valve AA has flow rate=0; tunnels lead to valves YI, EN, UK, OQ, VI +Valve XT has flow rate=0; tunnels lead to valves OQ, RE +Valve SZ has flow rate=24; tunnels lead to valves VB, SO +Valve IU has flow rate=25; tunnels lead to valves RV, HE, HQ +Valve OM has flow rate=0; tunnels lead to valves NY, HB +Valve YX has flow rate=0; tunnels lead to valves YV, SI +Valve SX has flow rate=0; tunnels lead to valves ZB, BF +Valve KD has flow rate=0; tunnels lead to valves XF, LW +Valve SP has flow rate=0; tunnels lead to valves XF, QB +Valve UY has flow rate=0; tunnels lead to valves UK, IY +Valve XF has flow rate=22; tunnels lead to valves SP, TE, KD, NY +Valve SC has flow rate=0; tunnels lead to valves LZ, UC +Valve UK has flow rate=0; tunnels lead to valves UY, AA +Valve LW has flow rate=0; tunnels lead to valves KD, IY +Valve FL has flow rate=0; tunnels lead to valves BN, LZ +Valve VI has flow rate=0; tunnels lead to valves AA, EB +Valve HW has flow rate=0; tunnels lead to valves JF, CY +Valve YI has flow rate=0; tunnels lead to valves AA, TT +Valve HE has flow rate=0; tunnels lead to valves IU, TE +Valve JG has flow rate=10; tunnels lead to valves PL, YZ, SI, KJ +Valve BN has flow rate=0; tunnels lead to valves IY, FL +Valve IF has flow rate=0; tunnels lead to valves EB, RE +Valve JF has flow rate=19; tunnels lead to valves HW, QF, VL, RV, AD +Valve SI has flow rate=0; tunnels lead to valves JG, YX +Valve WF has flow rate=0; tunnels lead to valves LZ, RE +Valve HQ has flow rate=0; tunnels lead to valves IU, UH +Valve LZ has flow rate=5; tunnels lead to valves SC, FL, WF, RL, RT +Valve UH has flow rate=0; tunnels lead to valves IY, HQ +Valve CY has flow rate=21; tunnel leads to valve HW +Valve NH has flow rate=0; tunnels lead to valves EB, YV +Valve TT has flow rate=0; tunnels lead to valves YV, YI +Valve OH has flow rate=0; tunnels lead to valves KJ, BF +Valve EN has flow rate=0; tunnels lead to valves RT, AA +Valve NY has flow rate=0; tunnels lead to valves OM, XF +Valve ZB has flow rate=8; tunnel leads to valve SX diff --git a/_freeze/2022/R/day16/execute-results/html.json b/_freeze/2022/R/day16/execute-results/html.json index 91bd116..09140c3 100644 --- a/_freeze/2022/R/day16/execute-results/html.json +++ b/_freeze/2022/R/day16/execute-results/html.json @@ -1,8 +1,8 @@ { - "hash": "6a25bc5739310e419033dcbae5670a06", + "hash": "ba1db0b8363fc37a2239575abad8dd21", "result": { "engine": "knitr", - "markdown": "---\ntitle: \"Day 16\"\ndate: 2022-12-16\nauthor:\n name: https://adventofcode.com/2022/day/16\n url: https://adventofcode.com/2022/day/16\n---\n\n\n\n\n\n## Setup\n\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Libraries\nlibrary(tidyverse)\nlibrary(igraph)\n\n# Read input from file\ninput <- read_lines(\"../input/day16.txt\", skip_empty_rows = TRUE) |> \n unglue::unglue_data(\n c(\n \"Valve {source} has flow rate={rate}; tunnels lead to valves {target}\",\n \"Valve {source} has flow rate={rate}; tunnel leads to valve {target}\"\n ),\n convert = TRUE\n ) |> \n mutate(target = map(target, \\(x) str_split_1(x, \", \")))\n```\n:::\n\n\n\n\n\n## Part 1\n\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nedges <- input |>\n unnest(target) |> \n pmap(function(source, target, ...) c(source, target)) |> \n unique() |> \n unlist() |> \n make_graph(directed = TRUE)\n\nplot(edges)\n```\n\n::: {.cell-output-display}\n![](day16_files/figure-html/unnamed-chunk-1-1.png){width=672}\n:::\n:::\n", + "markdown": "---\ntitle: \"Day 16\"\ndate: 2022-12-16\nauthor:\n name: https://adventofcode.com/2022/day/16\n url: https://adventofcode.com/2022/day/16\n---\n\n\n\n\n## Setup\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Libraries\nlibrary(tidyverse)\nlibrary(igraph)\n\n# Read input from file\ninput <- read_lines(\"../input/day16.txt\", skip_empty_rows = TRUE) |> \n unglue::unglue_data(\n c(\n \"Valve {source} has flow rate={rate}; tunnels lead to valves {target}\",\n \"Valve {source} has flow rate={rate}; tunnel leads to valve {target}\"\n ),\n convert = TRUE\n ) |> \n mutate(target = map(target, \\(x) str_split_1(x, \", \")))\n```\n:::\n\n\n\n\n## Part 1\n\nRepresent tunnels and valves as a graph:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ng <- input |>\n unnest(target) |> \n pmap(function(source, target, ...) c(source, target)) |> \n unique() |> \n unlist() |> \n make_graph(directed = TRUE) |> \n as_undirected()\n```\n:::\n\n\n\n\nGet the list of valves with nonzero flow:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nflows <- input |> \n filter(rate > 0 | source == \"AA\") |> \n select(source, rate) |> \n deframe()\n\nnon_init_flows <- flows |> \n discard_at(\"AA\")\n\nvalves <- names(flows)\n\ndists <- distances(g, valves, valves)\n```\n:::\n\n\n\n\nList all permutations of possible valves to visit with a total distance less than 30:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nget_path <- function(choices, last, cur_length, max_length) {\n if (cur_length >= max_length)\n return(head(last, -1))\n if (length(choices) == 0)\n return(last)\n \n ls <- list()\n for (valve in choices) {\n ls <- append(\n ls, \n list(get_path(\n choices[choices != valve], \n c(last, valve), \n cur_length + dists[tail(last, 1), valve] + 1,\n max_length\n ))\n )\n }\n ls |> \n discard(is_null) |> \n list_flatten() |> \n unique()\n}\n\ncombos <- get_path(names(non_init_flows), names(flows[\"AA\"]), 0, 30)\n```\n:::\n\n\n\n\nCompute total pressure released for each permutation:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nget_pressures <- function(paths, max_time) {\n map_dbl(paths, \\(path) {\n valve <- tail(path, -1)\n valve_lag <- head(path, -1)\n flow <- tail(flows[path], -1)\n \n dist <- map2_int(valve_lag, valve, \\(src, target) dists[src, target])\n time_start <- cumsum(dist) + 1:length(dist) + 1\n pressure <- (max_time - time_start + 1) * flow\n \n sum(pressure[time_start <= max_time])\n })\n}\n\npressures <- get_pressures(combos, 30)\n```\n:::\n\n\n\n\nFind the permutation that gives the maximum pressure:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmax_idx <- which.max(pressures)\npressures[max_idx]\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 1947\n```\n\n\n:::\n:::\n\n\n\n\n## Part 2\n\nList all permutations of possible valves to visit with a total distance less than 26:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nel_combos <- get_path(names(non_init_flows), names(flows[\"AA\"]), 0, 26)\nel_pressures <- get_pressures(el_combos, 26)\n```\n:::\n\n\n\n\nFor each set of permutations, get the best pressure.\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nel_best <- tibble(valves = map(el_combos, sort), pressure = el_pressures) |> \n slice_max(pressure, by = valves, with_ties = FALSE)\n```\n:::\n\n\n\n\nGet best combinations of permutations between yourself and the elephant:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nel_best |> \n rename(el_valves = valves, el_pressure = pressure) |> \n pmap_dbl(\\(el_valves, el_pressure) {\n el_valves <- el_valves[el_valves != \"AA\"]\n el_pressure + el_best |>\n filter(map_lgl(valves, ~ length(intersect(.x, el_valves)) == 0)) |> \n pull(pressure) |> \n max()\n }) |> \n max()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 2556\n```\n\n\n:::\n:::\n", "supporting": [ "day16_files" ], diff --git a/_freeze/site_libs/quarto-listing/list.min.js b/_freeze/site_libs/quarto-listing/list.min.js new file mode 100644 index 0000000..43dfd15 --- /dev/null +++ b/_freeze/site_libs/quarto-listing/list.min.js @@ -0,0 +1,2 @@ +var List;List=function(){var t={"./src/add-async.js":function(t){t.exports=function(t){return function e(r,n,s){var i=r.splice(0,50);s=(s=s||[]).concat(t.add(i)),r.length>0?setTimeout((function(){e(r,n,s)}),1):(t.update(),n(s))}}},"./src/filter.js":function(t){t.exports=function(t){return t.handlers.filterStart=t.handlers.filterStart||[],t.handlers.filterComplete=t.handlers.filterComplete||[],function(e){if(t.trigger("filterStart"),t.i=1,t.reset.filter(),void 0===e)t.filtered=!1;else{t.filtered=!0;for(var r=t.items,n=0,s=r.length;nv.page,a=new g(t[s],void 0,n),v.items.push(a),r.push(a)}return v.update(),r}m(t.slice(0),e)}},this.show=function(t,e){return this.i=t,this.page=e,v.update(),v},this.remove=function(t,e,r){for(var n=0,s=0,i=v.items.length;s-1&&r.splice(n,1),v},this.trigger=function(t){for(var e=v.handlers[t].length;e--;)v.handlers[t][e](v);return v},this.reset={filter:function(){for(var t=v.items,e=t.length;e--;)t[e].filtered=!1;return v},search:function(){for(var t=v.items,e=t.length;e--;)t[e].found=!1;return v}},this.update=function(){var t=v.items,e=t.length;v.visibleItems=[],v.matchingItems=[],v.templater.clear();for(var r=0;r=v.i&&v.visibleItems.lengthe},innerWindow:function(t,e,r){return t>=e-r&&t<=e+r},dotted:function(t,e,r,n,s,i,a){return this.dottedLeft(t,e,r,n,s,i)||this.dottedRight(t,e,r,n,s,i,a)},dottedLeft:function(t,e,r,n,s,i){return e==r+1&&!this.innerWindow(e,s,i)&&!this.right(e,n)},dottedRight:function(t,e,r,n,s,i,a){return!t.items[a-1].values().dotted&&(e==n&&!this.innerWindow(e,s,i)&&!this.right(e,n))}};return function(e){var n=new i(t.listContainer.id,{listClass:e.paginationClass||"pagination",item:e.item||"
  • ",valueNames:["page","dotted"],searchClass:"pagination-search-that-is-not-supposed-to-exist",sortClass:"pagination-sort-that-is-not-supposed-to-exist"});s.bind(n.listContainer,"click",(function(e){var r=e.target||e.srcElement,n=t.utils.getAttribute(r,"data-page"),s=t.utils.getAttribute(r,"data-i");s&&t.show((s-1)*n+1,n)})),t.on("updated",(function(){r(n,e)})),r(n,e)}}},"./src/parse.js":function(t,e,r){t.exports=function(t){var e=r("./src/item.js")(t),n=function(r,n){for(var s=0,i=r.length;s0?setTimeout((function(){e(r,s)}),1):(t.update(),t.trigger("parseComplete"))};return t.handlers.parseComplete=t.handlers.parseComplete||[],function(){var e=function(t){for(var e=t.childNodes,r=[],n=0,s=e.length;n]/g.exec(t)){var e=document.createElement("tbody");return e.innerHTML=t,e.firstElementChild}if(-1!==t.indexOf("<")){var r=document.createElement("div");return r.innerHTML=t,r.firstElementChild}}},a=function(e,r,n){var s=void 0,i=function(e){for(var r=0,n=t.valueNames.length;r=1;)t.list.removeChild(t.list.firstChild)},function(){var r;if("function"!=typeof t.item){if(!(r="string"==typeof t.item?-1===t.item.indexOf("<")?document.getElementById(t.item):i(t.item):s()))throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template.");r=n(r,t.valueNames),e=function(){return r.cloneNode(!0)}}else e=function(e){var r=t.item(e);return i(r)}}()};t.exports=function(t){return new e(t)}},"./src/utils/classes.js":function(t,e,r){var n=r("./src/utils/index-of.js"),s=/\s+/;Object.prototype.toString;function i(t){if(!t||!t.nodeType)throw new Error("A DOM element reference is required");this.el=t,this.list=t.classList}t.exports=function(t){return new i(t)},i.prototype.add=function(t){if(this.list)return this.list.add(t),this;var e=this.array();return~n(e,t)||e.push(t),this.el.className=e.join(" "),this},i.prototype.remove=function(t){if(this.list)return this.list.remove(t),this;var e=this.array(),r=n(e,t);return~r&&e.splice(r,1),this.el.className=e.join(" "),this},i.prototype.toggle=function(t,e){return this.list?(void 0!==e?e!==this.list.toggle(t,e)&&this.list.toggle(t):this.list.toggle(t),this):(void 0!==e?e?this.add(t):this.remove(t):this.has(t)?this.remove(t):this.add(t),this)},i.prototype.array=function(){var t=(this.el.getAttribute("class")||"").replace(/^\s+|\s+$/g,"").split(s);return""===t[0]&&t.shift(),t},i.prototype.has=i.prototype.contains=function(t){return this.list?this.list.contains(t):!!~n(this.array(),t)}},"./src/utils/events.js":function(t,e,r){var n=window.addEventListener?"addEventListener":"attachEvent",s=window.removeEventListener?"removeEventListener":"detachEvent",i="addEventListener"!==n?"on":"",a=r("./src/utils/to-array.js");e.bind=function(t,e,r,s){for(var o=0,l=(t=a(t)).length;o32)return!1;var a=n,o=function(){var t,r={};for(t=0;t=p;b--){var j=o[t.charAt(b-1)];if(C[b]=0===m?(C[b+1]<<1|1)&j:(C[b+1]<<1|1)&j|(v[b+1]|v[b])<<1|1|v[b+1],C[b]&d){var x=l(m,b-1);if(x<=u){if(u=x,!((c=b-1)>a))break;p=Math.max(1,2*a-c)}}}if(l(m+1,a)>u)break;v=C}return!(c<0)}},"./src/utils/get-attribute.js":function(t){t.exports=function(t,e){var r=t.getAttribute&&t.getAttribute(e)||null;if(!r)for(var n=t.attributes,s=n.length,i=0;i=48&&t<=57}function i(t,e){for(var i=(t+="").length,a=(e+="").length,o=0,l=0;o=i&&l=a?-1:l>=a&&o=i?1:i-a}i.caseInsensitive=i.i=function(t,e){return i((""+t).toLowerCase(),(""+e).toLowerCase())},Object.defineProperties(i,{alphabet:{get:function(){return e},set:function(t){r=[];var s=0;if(e=t)for(;s { + category = atob(category); + if (categoriesLoaded) { + activateCategory(category); + setCategoryHash(category); + } +}; + +window["quarto-listing-loaded"] = () => { + // Process any existing hash + const hash = getHash(); + + if (hash) { + // If there is a category, switch to that + if (hash.category) { + // category hash are URI encoded so we need to decode it before processing + // so that we can match it with the category element processed in JS + activateCategory(decodeURIComponent(hash.category)); + } + // Paginate a specific listing + const listingIds = Object.keys(window["quarto-listings"]); + for (const listingId of listingIds) { + const page = hash[getListingPageKey(listingId)]; + if (page) { + showPage(listingId, page); + } + } + } + + const listingIds = Object.keys(window["quarto-listings"]); + for (const listingId of listingIds) { + // The actual list + const list = window["quarto-listings"][listingId]; + + // Update the handlers for pagination events + refreshPaginationHandlers(listingId); + + // Render any visible items that need it + renderVisibleProgressiveImages(list); + + // Whenever the list is updated, we also need to + // attach handlers to the new pagination elements + // and refresh any newly visible items. + list.on("updated", function () { + renderVisibleProgressiveImages(list); + setTimeout(() => refreshPaginationHandlers(listingId)); + + // Show or hide the no matching message + toggleNoMatchingMessage(list); + }); + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Attach click handlers to categories + const categoryEls = window.document.querySelectorAll( + ".quarto-listing-category .category" + ); + + for (const categoryEl of categoryEls) { + // category needs to support non ASCII characters + const category = decodeURIComponent( + atob(categoryEl.getAttribute("data-category")) + ); + categoryEl.onclick = () => { + activateCategory(category); + setCategoryHash(category); + }; + } + + // Attach a click handler to the category title + // (there should be only one, but since it is a class name, handle N) + const categoryTitleEls = window.document.querySelectorAll( + ".quarto-listing-category-title" + ); + for (const categoryTitleEl of categoryTitleEls) { + categoryTitleEl.onclick = () => { + activateCategory(""); + setCategoryHash(""); + }; + } + + categoriesLoaded = true; +}); + +function toggleNoMatchingMessage(list) { + const selector = `#${list.listContainer.id} .listing-no-matching`; + const noMatchingEl = window.document.querySelector(selector); + if (noMatchingEl) { + if (list.visibleItems.length === 0) { + noMatchingEl.classList.remove("d-none"); + } else { + if (!noMatchingEl.classList.contains("d-none")) { + noMatchingEl.classList.add("d-none"); + } + } + } +} + +function setCategoryHash(category) { + setHash({ category }); +} + +function setPageHash(listingId, page) { + const currentHash = getHash() || {}; + currentHash[getListingPageKey(listingId)] = page; + setHash(currentHash); +} + +function getListingPageKey(listingId) { + return `${listingId}-page`; +} + +function refreshPaginationHandlers(listingId) { + const listingEl = window.document.getElementById(listingId); + const paginationEls = listingEl.querySelectorAll( + ".pagination li.page-item:not(.disabled) .page.page-link" + ); + for (const paginationEl of paginationEls) { + paginationEl.onclick = (sender) => { + setPageHash(listingId, sender.target.getAttribute("data-i")); + showPage(listingId, sender.target.getAttribute("data-i")); + return false; + }; + } +} + +function renderVisibleProgressiveImages(list) { + // Run through the visible items and render any progressive images + for (const item of list.visibleItems) { + const itemEl = item.elm; + if (itemEl) { + const progressiveImgs = itemEl.querySelectorAll( + `img[${kProgressiveAttr}]` + ); + for (const progressiveImg of progressiveImgs) { + const srcValue = progressiveImg.getAttribute(kProgressiveAttr); + if (srcValue) { + progressiveImg.setAttribute("src", srcValue); + } + progressiveImg.removeAttribute(kProgressiveAttr); + } + } + } +} + +function getHash() { + // Hashes are of the form + // #name:value|name1:value1|name2:value2 + const currentUrl = new URL(window.location); + const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined; + return parseHash(hashRaw); +} + +const kAnd = "&"; +const kEquals = "="; + +function parseHash(hash) { + if (!hash) { + return undefined; + } + const hasValuesStrs = hash.split(kAnd); + const hashValues = hasValuesStrs + .map((hashValueStr) => { + const vals = hashValueStr.split(kEquals); + if (vals.length === 2) { + return { name: vals[0], value: vals[1] }; + } else { + return undefined; + } + }) + .filter((value) => { + return value !== undefined; + }); + + const hashObj = {}; + hashValues.forEach((hashValue) => { + hashObj[hashValue.name] = decodeURIComponent(hashValue.value); + }); + return hashObj; +} + +function makeHash(obj) { + return Object.keys(obj) + .map((key) => { + return `${key}${kEquals}${obj[key]}`; + }) + .join(kAnd); +} + +function setHash(obj) { + const hash = makeHash(obj); + window.history.pushState(null, null, `#${hash}`); +} + +function showPage(listingId, page) { + const list = window["quarto-listings"][listingId]; + if (list) { + list.show((page - 1) * list.page + 1, list.page); + } +} + +function activateCategory(category) { + // Deactivate existing categories + const activeEls = window.document.querySelectorAll( + ".quarto-listing-category .category.active" + ); + for (const activeEl of activeEls) { + activeEl.classList.remove("active"); + } + + // Activate this category + const categoryEl = window.document.querySelector( + `.quarto-listing-category .category[data-category='${btoa( + encodeURIComponent(category) + )}']` + ); + if (categoryEl) { + categoryEl.classList.add("active"); + } + + // Filter the listings to this category + filterListingCategory(category); +} + +function filterListingCategory(category) { + const listingIds = Object.keys(window["quarto-listings"]); + for (const listingId of listingIds) { + const list = window["quarto-listings"][listingId]; + if (list) { + if (category === "") { + // resets the filter + list.filter(); + } else { + // filter to this category + list.filter(function (item) { + const itemValues = item.values(); + if (itemValues.categories !== null) { + const categories = decodeURIComponent( + atob(itemValues.categories) + ).split(","); + return categories.includes(category); + } else { + return false; + } + }); + } + } + } +} diff --git a/docs/2022/R/day16.html b/docs/2022/R/day16.html index a465c37..e8989fd 100644 --- a/docs/2022/R/day16.html +++ b/docs/2022/R/day16.html @@ -414,6 +414,7 @@

    Contents

    @@ -473,21 +474,111 @@

    Setup

    Part 1

    +

    Represent tunnels and valves as a graph:

    -
    edges <- input |>
    +
    g <- input |>
       unnest(target) |> 
       pmap(function(source, target, ...) c(source, target)) |> 
       unique() |> 
       unlist() |> 
    -  make_graph(directed = TRUE)
    -
    -plot(edges)
    -
    -
    -
    -

    -
    + make_graph(directed = TRUE) |> + as_undirected()
    +

    Get the list of valves with nonzero flow:

    +
    +
    flows <- input |> 
    +  filter(rate > 0 | source == "AA") |> 
    +  select(source, rate) |> 
    +  deframe()
    +
    +non_init_flows <- flows |> 
    +  discard_at("AA")
    +
    +valves <- names(flows)
    +
    +dists <- distances(g, valves, valves)
    +
    +

    List all permutations of possible valves to visit with a total distance less than 30:

    +
    +
    get_path <- function(choices, last, cur_length, max_length) {
    +  if (cur_length >= max_length)
    +    return(head(last, -1))
    +  if (length(choices) == 0)
    +    return(last)
    +  
    +  ls <- list()
    +  for (valve in choices) {
    +    ls <- append(
    +      ls, 
    +      list(get_path(
    +        choices[choices != valve], 
    +        c(last, valve), 
    +        cur_length + dists[tail(last, 1), valve] + 1,
    +        max_length
    +      ))
    +    )
    +  }
    +  ls |> 
    +    discard(is_null) |> 
    +    list_flatten() |> 
    +    unique()
    +}
    +
    +combos <- get_path(names(non_init_flows), names(flows["AA"]), 0, 30)
    +
    +

    Compute total pressure released for each permutation:

    +
    +
    get_pressures <- function(paths, max_time) {
    +  map_dbl(paths, \(path) {
    +    valve      <- tail(path, -1)
    +    valve_lag  <- head(path, -1)
    +    flow       <- tail(flows[path], -1)
    +    
    +    dist       <- map2_int(valve_lag, valve, \(src, target) dists[src, target])
    +    time_start <- cumsum(dist) + 1:length(dist) + 1
    +    pressure   <- (max_time - time_start + 1) * flow
    +    
    +    sum(pressure[time_start <= max_time])
    +  })
    +}
    +
    +pressures <- get_pressures(combos, 30)
    +
    +

    Find the permutation that gives the maximum pressure:

    +
    +
    max_idx <- which.max(pressures)
    +pressures[max_idx]
    +
    +
    [1] 1947
    +
    +
    +
    +
    +

    Part 2

    +

    List all permutations of possible valves to visit with a total distance less than 26:

    +
    +
    el_combos    <- get_path(names(non_init_flows), names(flows["AA"]), 0, 26)
    +el_pressures <- get_pressures(el_combos, 26)
    +
    +

    For each set of permutations, get the best pressure.

    +
    +
    el_best <- tibble(valves = map(el_combos, sort), pressure = el_pressures) |> 
    +  slice_max(pressure, by = valves, with_ties = FALSE)
    +
    +

    Get best combinations of permutations between yourself and the elephant:

    +
    +
    el_best |> 
    +  rename(el_valves = valves, el_pressure = pressure) |> 
    +  pmap_dbl(\(el_valves, el_pressure) {
    +    el_valves <- el_valves[el_valves != "AA"]
    +    el_pressure + el_best |>
    +      filter(map_lgl(valves, ~ length(intersect(.x, el_valves)) == 0)) |> 
    +      pull(pressure) |> 
    +      max()
    +  }) |> 
    +  max()
    +
    +
    [1] 2556
    diff --git a/docs/index.html b/docs/index.html index b9eb51f..9602559 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ - + Advent of Code: Worked Solutions