diff --git a/nine/src/automaton.js b/nine/src/automaton.js index 89c64ef..7a4e395 100644 --- a/nine/src/automaton.js +++ b/nine/src/automaton.js @@ -43,12 +43,13 @@ export const Replace = Object.freeze({ x.push() return x.symbol }, - Pop: x => x.pop(), + Pop: x => x.pop().symbol, Swap: x => { - const tmp = x.pop() - x.push() - x.push(tmp) - return tmp.symbol + const a = x.pop() + const b = x.pop() + x.push(a) + x.push(b) + return b.symbol }, ClearStack: tee(x => x.clear()), FromStack: x => x.peek().symbol, @@ -281,6 +282,7 @@ const highlight = (i, arr, col = colors.cyan, spaces = 0) => { a[i] = a[i].padEnd(spaces + diff) return a } + const range = n => [...Array(n).keys()] export class TuringMachine { diff --git a/nine/src/index.js b/nine/src/index.js index b80bc26..5f06e2b 100644 --- a/nine/src/index.js +++ b/nine/src/index.js @@ -3,84 +3,46 @@ import { resolve } from 'node:path' import { Rules, Rule, Predicate, Replace, Tape, TuringMachine, Seek } from './automaton.js' const { First, Last, Left, Right, Stay, SeekFromStack, JumpFromStack } = Seek -const { ClearStack, Nothing, Push, Seq, Swap, With } = Replace -const { InBounds, Not, OutOfBounds, True } = Predicate +const { ClearStack, Nothing, Pop, Push, Seq, Swap, With } = Replace +const { Every, InBounds, Not, OutOfBounds, True } = Predicate -const State = Object.freeze({ - Start: 'start', - ScanRight: 'scan-right', - FindFile: 'find-file', - ScanLeft: 'scan-left', - FindSpace: 'find-space', - ClearFile: 'clear-file', -}) - -const IsFreeSpace = Predicate.Equals('.') -const IsNotFree = Not(IsFreeSpace) -const IsFartherRight = x => x.peek().position <= x.position - -const dot = ch => ch.symbol === '.' -const notDot = ch => !dot(ch) -const TrySkipFiles = x => { - const stack = x.stack.slice() - const a = stack.skipUntil(dot).takeUntil(notDot) - const skip = !stack.done() - //console.log(a, 'skipping?', skip, !stack.done()) - return skip +const HasMemory = x => x.peek() != null +const IsFree = Predicate.Equals('.') +const IsFile = Not(IsFree) +const IsMovingRight = x => { + return x.stack[0].position <= x.position } -const FirstOrStack = x => { - // unwind the stack - const states = [] - let next - while (next = x.pop()) { - if (next.position < x.position) { - break - } else { - states.push(next) - next = null - } - } - - - // rewind it - states.reverse() - let tmp - while (tmp = states.pop()) { - x.push(tmp) - } - - return next ? next : First(x) - //return x.peek() ? x.pop().position : First(x) -} - -const TrySkipping = Seq(InBounds(Right), TrySkipFiles) - -const HasMoreFiles = x => { - const stack = x.stack.slice() - stack.skipUntil(dot).skipUntil(notDot) - return !stack.done() -} - -const ShouldContinue = Predicate.Every(OutOfBounds(Right), HasMoreFiles) - // | From | To | Condition | Next Character | Move Direction | // | ------------------------------------------------------------------------------| // new Rule('q0', 'q1', reader => reader.symbol === '1', (_reader) => '0', 1) +const State = Object.freeze({ + Start: 'start', + NextFree: 'next-free', + JumpToFile: 'jump-to-file', + NextFile: 'next-file', + JumpToFree: 'jump-to-free', + MoveFile: 'move-file', + Halt: 'halt' +}) const rules = new Rules([ - new Rule(State.Start, State.ScanRight, True, Nothing, Right), - new Rule(State.ScanRight, State.FindFile, TrySkipping, ClearStack, Last), - new Rule(State.ScanRight, State.FindFile, ShouldContinue, ClearStack, Stay), - new Rule(State.ScanRight, State.ScanRight, InBounds(Right), Push, Right), - new Rule(State.FindFile, State.ScanLeft, IsNotFree, Seq(ClearStack, Push), Stay), - new Rule(State.FindFile, State.FindFile, IsFreeSpace, Nothing, Left), - new Rule(State.ScanLeft, State.ScanLeft, InBounds(Left), Nothing, FirstOrStack), - new Rule(State.ScanLeft, State.FindSpace, OutOfBounds(Left), Nothing, Stay), - new Rule(State.FindSpace, State.ScanRight, IsFartherRight, ClearStack, Right), - new Rule(State.FindSpace, State.ClearFile, IsFreeSpace, Swap, JumpFromStack), - new Rule(State.FindSpace, State.FindSpace, InBounds(Right), Nothing, Right), - new Rule(State.ClearFile, State.ScanRight, True, With('.'), SeekFromStack(false)), + new Rule(State.Start, State.NextFree, True, Nothing, Right), + // + // find free space + new Rule(State.NextFree, State.Halt, OutOfBounds(Right), Nothing, Stay), + new Rule(State.NextFree, State.NextFile, Every(IsFree, HasMemory), Nothing, JumpFromStack), + new Rule(State.NextFree, State.NextFile, IsFree, Push, Last), + new Rule(State.NextFree, State.NextFree, IsFile, Nothing, Right), + + // find file + new Rule(State.NextFile, State.Halt, OutOfBounds(Left), Nothing, Stay), + new Rule(State.NextFile, State.MoveFile, IsFile, Seq(Push, Swap, With('.')), SeekFromStack(true)), + new Rule(State.NextFile, State.NextFile, IsFree, Nothing, Left), + + // move file + new Rule(State.MoveFile, State.Halt, IsMovingRight, Nothing, Stay), + new Rule(State.MoveFile, State.NextFree, True, Seq(Pop, Pop), Right), ]) const char = x => String.fromCodePoint(x) @@ -113,31 +75,31 @@ const checksum = input => input.filter(notFree).map(toInt).map(mul).reduce(add) const main = input => { const expanded = expand(input) - console.log(expanded) const compressed = compress(expanded) - console.log(compressed.filter(notFree).map(toInt)) const sum = checksum(compressed) return sum } const tests = [ - ['2333133121414131402', 1928], - ['1010101010101010101010', 385], - ['111111111111111111111', 290], - ['10101010101010101010101', 506], - ['90909', 486] + //['12345', 486] + // ['2333133121414131402', 1928], + //['1010101010101010101010', 385], + //['111111111111111111111', 290], + //['10101010101010101010101', 506], + //['91'.repeat(100), 506], + //['90909', 486] ] -tests.forEach(([input, expected]) => { - console.log(`input length is ${input.length}`) +tests.forEach(([input, expected], i) => { + //console.log(`input length is ${input.length}`) const result = main(input) - console.log(result === expected, result) + console.log(i, result === expected, result) }) -//readFile(resolve('./input'), { encoding: 'utf8' }) -// .then(x => { -// console.log(`input length is ${x.length}`) -// return main(x) -// }) -// .then(console.log) +readFile(resolve('./input'), { encoding: 'utf8' }) + .then(x => { + console.log(`input length is ${x.length}`) + return main(x) + }) + .then(console.log)