diff --git a/2016/11/task.ts b/2016/11/task.ts index 3a1d041..c2f2424 100644 --- a/2016/11/task.ts +++ b/2016/11/task.ts @@ -1,4 +1,92 @@ -export async function taskOne(_input: string[]): Promise { +import {JsonSet, Queue, Stack} from '../../base/simpleStructure' + +export async function taskOne(input: string[]): Promise { + task(parse(input)) +} + +export async function taskTwo(input: string[]): Promise { + const floors = parse(input) + const newElementCount = 4 + for (let f = 0; f < floors.length; f++) { + for (let i = 0; i < newElementCount; i++) floors[f].push(false) + } + for (let i = floors[0].length-newElementCount; i < floors[0].length; i++) { + floors[0][i] = true + } + task(floors) +} + +function task(floors: boolean[][]) { + const floorCount = floors.length + interface State1 { + f:boolean[][] + } + interface State extends State1 { + c:number + e:number + } + const Q:Queue = new Queue() + const V:Map = new Map() + Q.push({ + f: floors, + e: 0, + c:0 + }) + + while(!Q.isEmpty()) { + const q = Q.pop() + + if (q.f[floorCount-1].every(i => i)) { + console.log(q.c) + return + } + + const h = hash(q.f, q.e) + const hF = V.get(h) + const rep = floorToRep(q.f) + if (hF) { + if (hF.some(r => repEqual(rep, r))) continue + hF.push(rep) + } else { + V.set(h, [rep]) + } + + for (const de of [-1,1]) { + if(q.e+de < 0 || q.e+de >= floorCount) continue + for (let i = 0; i < floors[q.e].length; i++) { + if(!q.f[q.e][i]) continue + if (de > 0) { + for (let j = i+1; j < floors[q.e].length; j++) { + if(!q.f[q.e][j]) continue + const newF = copy(q.f) + newF[q.e+de][i] = true + newF[q.e+de][j] = true + newF[q.e][i] = false + newF[q.e][j] = false + if (!isValidFloor(newF[q.e]) || !isValidFloor(newF[q.e+de])) continue + Q.push({ + c: q.c+1, + e: q.e+de, + f:newF + }) + } + } + + const newF = copy(q.f) + newF[q.e+de][i] = true + newF[q.e][i] = false + if (!isValidFloor(newF[q.e]) || !isValidFloor(newF[q.e+de])) continue + Q.push({ + c: q.c+1, + e: q.e+de, + f:newF + }) + } + } + } +} + +function parse(_input: string[]): boolean[][] { const input = _input.map(i=> i.split("contains")[1]) let id = 0 let floorCount = input.length @@ -40,117 +128,10 @@ export async function taskOne(_input: string[]): Promise { throw "2 " + i + " | " + j }) }) - interface State { - floors: boolean[][] - e: number - steps: number - } - //debug(floors) - const Q: State[] = [{floors: copy(floors), e: 0, steps:0}] - const visited: Set = new Set() - //console.log(nameMap) - //console.log(floors) - let curMin = Infinity - while(Q.length > 0) { - const q = Q.pop() as State - if (visited.has(JSON.stringify({floors: q.floors, e: q.e}))) continue - visited.add(JSON.stringify({floors: q.floors, e: q.e})) - - // check for final - if (q.floors[floorCount-1].every(i=>i)) { - console.log(q.steps) - debug(q.floors) - if (q.steps < curMin) curMin = q.steps - continue - } - // check for validity - //if (q.steps >= curMin) continue - let validity = true - for (let f = 0; f < floorCount; f++) { - let hasRTG = false - for (let i = 0; i < q.floors[f].length*2; i+=2) { - if (q.floors[f][i]) hasRTG = true - } - if (hasRTG) { - //console.log("rtg on: ", f) - for (let i = 1; i < q.floors[f].length*2; i+=2) { - if (q.floors[f][i] && !q.floors[f][i-1]) validity = false - } - } - - } - //console.log(validity, q.e) - //debug(copy(q.floors)) - if (!validity) { - //console.log("invalid") - //debug(copy(q.floors)) - continue - } else { - //console.log("valid", q.e) - //debug(copy(q.floors)) - } - - - for (let i = 0; i < q.floors[q.e].length; i++) { - if (!q.floors[q.e][i]) continue - let moveP = copy(q) - let moveM = copy(q) - moveP.e++ - moveM.steps++ - moveP.steps++ - moveM.e-- - if (moveM.e >= 0) { - moveM.floors[q.e][i] = false - moveM.floors[q.e-1][i] = true - //console.log("M1", moveM) - Q.push(moveM) - } - if (moveP.e < floorCount) { - moveP.floors[q.e][i] = false - moveP.floors[q.e+1][i] = true - // console.log("P1",i, moveP, q.e) - Q.push(moveP) - //console.log(Q) - } - } - - - for (let i = 0; i < q.floors[q.e].length; i++) { - if (!q.floors[q.e][i]) continue - for (let j = i+1; j < q.floors[q.e].length; j++) { - if (!q.floors[q.e][j]) continue - let moveP = copy(q) - let moveM = copy(q) - moveP.e++ - moveM.e-- - moveM.steps++ - moveP.steps++ - if (moveM.e >= 0) { - moveM.floors[q.e][i] = false - moveM.floors[q.e-1][i] = true - moveM.floors[q.e][j] = false - moveM.floors[q.e-1][j] = true - // console.log("M2", moveM) - Q.push(moveM) - } - if (moveP.e < floorCount) { - //debug(moveP.floors) - moveP.floors[q.e][i] = false - moveP.floors[q.e+1][i] = true - moveP.floors[q.e][j] = false - moveP.floors[q.e+1][j] = true - // console.log("P2", moveP) - Q.push(moveP) - } - } - } - } - console.log(curMin) + return floors } -export async function taskTwo(input: string[]): Promise { - console.log("Unimplemented"); -} +type Representation = [number, number][] function copy(s: T): T { return JSON.parse(JSON.stringify(s)) @@ -159,4 +140,57 @@ function copy(s: T): T { function debug(arr: boolean[][]) { copy(arr).reverse().forEach(i => console.log(i.map(b => b?'#':'.').join(''))) console.log("") +} + +function isValidFloor(floor: boolean[]) { + let hasGenerator = false + for (let i = 0; i < floor.length; i+=2) { + if (floor[i]) hasGenerator = true + } + if (!hasGenerator) return true + + for (let i = 1; i < floor.length; i+=2) { + if (!floor[i]) continue + if(!floor[i-1]) return false + } + return true +} + +function floorToRep(floors: boolean[][]): Representation { + const r: Representation = [] + for (let x = 0; x < floors[0].length; x+=2) { + let gF = -1 + for (let i = 0; i < floors.length; i++) { + if (floors[i][x]) gF = i + } + let cF = -1 + for (let i = 0; i < floors.length; i++) { + if (floors[i][x]) cF = i + } + r.push([gF, cF]) + } + return r.sort(([_1, a], [_2, b]) => a-b).sort(([a,_a], [b,_b]) => a-b) +} + +function repEqual(a: Representation, b: Representation) { + for (let i = 0; i < a.length; i++) { + if (a[i][0] != b[i][0]) return false + if (a[i][1] != b[i][1]) return false + } + return true +} + +function hash(floors: boolean[][], e: number) { + function floorHash(floor: boolean[]) { + let pairs = 0 + let generators = 0 + let chips = 0 + for (let i = 0; i < floor.length; i+=2) { + if (floor[i]) generators++ + if (floor[i+1]) chips++ + if (floor[i] && floor[i+1]) pairs++ + } + return `${pairs}A${generators}${chips}` + } + return floors.map(floorHash).join('B') + 'C' + e } \ No newline at end of file diff --git a/2016/19/task.ts b/2016/19/task.ts index f1803d0..af70f50 100644 --- a/2016/19/task.ts +++ b/2016/19/task.ts @@ -1,3 +1,5 @@ +import {Stack, Queue} from '../../base/simpleStructure' + export async function taskOne(input: string[]): Promise { const l = parseInt(input[0]) let circle = {c: 1, i: 1} as Node @@ -21,36 +23,106 @@ export async function taskOne(input: string[]): Promise { export async function taskTwo(input: string[]): Promise { let l = parseInt(input[0]) - let circle = {c: 1, i: 1} as Node - let first = circle - for (let i = 1; i < l; i++) { - const n = {c: 1, i:i+1, r:circle} as Node - circle.l = n - circle = n + let lL = 0 + let lR = 0 + const left = new Deque() + const right = new Deque + for (let i = 1; i <= l; i++) { + if (i < Math.floor(l/2)+1) { + left.pushR(i) + lL++ + } else { + right.pushL(i) + lR++ + } } - circle.l = first - first.r = circle - circle = first - //print(circle) - let i = 0 - while(circle.i != circle.l.i) { - i++ - const toGo = Math.floor(l/2) - let n = circle - for (let i = 0; i < toGo; i++) { - n = n.l + while(lL > 0 && lR > 0) { + if (lL > lR) { + left.popR() + lL-- + } else { + right.popR() + lR-- } - //console.log('Steal:',circle.i, n.i) - n.l.r = n.r - n.r.l = n.l - circle = circle.l - l-- - if (i %1000 == 0) { - console.log(i) + right.pushL(left.popL()) + left.pushR(right.popR()) + } + if (lL == 0) console.log(right.head()) + else console.log(left.head()) +} + +class Deque { + + constructor() {} + h: N|null = null + t: N|null = null + + head() {return this.h?.v??-1} + isEmpty() {return this.h != null} + popL() { + if (this.h == null) throw "empty" + const n = this.h.v + this.h = this.h.r + if (this.h == null) this.t = null + else this.h.l = null + return n + } + popR() { + if (this.t == null) throw "empty" + const n = this.t.v + this.t = this.t.l + if (this.t == null) this.h = null + else this.t.r = null + return n + } + + pushL(v: number) { + const n: N = { + v, + l: null, + r: null + } + if (this.h == null) { + this.h = n + this.t = n + return } + this.h.l = n + n.r = this.h + this.h = n } - console.log(circle.i) + pushR(v: number) { + const n: N = { + v, + l: null, + r: null + } + if (this.t == null) { + this.h = n + this.t = n + return + } + this.t.r = n + n.l = this.t + this.t = n + } + + asArray() { + const r: number[] = [] + let n = this.h + while(n != null) { + r.push(n.v) + n = n.r + } + return r + } +} + +interface N { + l: N|null + r: N|null + v: number } interface Node { diff --git a/2016/22/task.ts b/2016/22/task.ts index 8b1a69e..2a6eba3 100644 --- a/2016/22/task.ts +++ b/2016/22/task.ts @@ -19,72 +19,56 @@ export async function taskOne(input: string[]): Promise { export async function taskTwo(input: string[]): Promise { const grid = parse(input) - const V: JsonSet = new JsonSet() - const Q: Record> = {0:new Queue()} - Q[0].push({ - g: grid,c:0,p:[grid.length-1,0] - }) - let p = {} as Record - while(true) { - const keys = Object.keys(Q).map(Number).sort((a,b) => a-b) - let q: State|null = null - for (const i of keys) { - if (!Q[i].isEmpty()) { - q = Q[i].pop() - break; - } + const goal = [0,0] + let data: [number, number] = [grid.length-1,0] + let empty: [number, number] = [-1,-1] + for (let x = 0; x < grid.length; x++) { + for (let y = 0; y < grid[x].length; y++) { + if (grid[x][y].used == 0) empty = [x,y] } - /*let s = 0 - for (const i of keys) s += Q[i].asArray().length - console.log(s)*/ - - - if(!q) break - - if (V.has(q.g)) continue - if (q.p[0] == 0 && q.p[1] == 0) { - /*for(let i = q; i != undefined; i = p[JSON.stringify(i)]) { - // print(i) - // console.log('') - }*/ + } + const V: JsonSet = new JsonSet() + const Q: Queue = new Queue() + Q.push({ + c:0,d:data,e:empty + }) + while(!Q.isEmpty()) { + const q = Q.pop() + if (q.d[0] == goal[0] && q.d[1] == goal[1]) { console.log(q.c) return } - V.add(q.g) - for (let x = 0; x < grid.length; x++) { - for (let y = 0; y < grid[x].length; y++) { - for (const offset of [[1,0],[-1,0],[0,1],[0,-1]]) { - let dx = x+offset[0] - let dy = y+offset[1] - if (dx < 0 || dy < 0 || dx >= grid.length || dy >= grid[0].length) continue - if (q.g[x][y].used > q.g[dx][dy].avail) continue - const nq = copy(q) - nq.g[dx][dy].avail -= nq.g[x][y].used - nq.g[dx][dy].used += nq.g[x][y].used - nq.g[x][y].used = 0 - nq.g[x][y].avail = nq.g[x][y].size + if (V.has([q.d[0],q.d[1],q.e[0],q.e[1]])) continue + V.add([q.d[0],q.d[1],q.e[0],q.e[1]]) - if (nq.p[0] == x && nq.p[1] == y) { - nq.p = [dx, dy] - } - - nq.c++ - p[JSON.stringify(nq)] = q - const d1 = dx+dy - const d2 = Math.abs(q.p[0]- dx) + Math.abs(q.p[1]- dy) - const d = Math.min(d1, d2) - if (Q[d] == undefined) Q[d] = new Queue() - Q[d].push(nq) - } + for(const dir of [[1,0],[0,1],[-1,0],[0,-1]]) { + const dx = q.e[0]+dir[0] + const dy = q.e[1]+dir[1] + if (dx < 0 || dx >= grid.length) continue + if (dy < 0 || dy >= grid[dx].length) continue + if (grid[q.e[0]][q.e[1]].size < grid[dx][dy].used) continue + if (dx == q.d[0] && dy == q.d[1]) { + Q.push({ + c: q.c+1, + d: q.e, + e: [dx, dy] + }) + } else { + Q.push({ + c: q.c+1, + d: q.d, + e: [dx, dy] + }) } } } + } interface State { - g: Plate[][] c: number, - p: [number, number] + d: [number, number] + e: [number, number] } function parse(_input: string[]): Plate[][] { @@ -121,13 +105,3 @@ interface Plate { function copy(t:T):T { return JSON.parse(JSON.stringify(t)) } - -function print(s: State) { - function p(s1:Plate) { - return s1.used.toString().padStart(2, ' ') + '/' + s1.size.toString().padStart(2, ' ') - } - for (const r of s.g) { - r.map(p).join(' - ') - console.log(' - '.repeat(r.length)) - } -} \ No newline at end of file