make the automaton one a little faster

This commit is contained in:
Rowan 2024-12-14 07:49:01 -06:00
parent 9716a10886
commit 6665b7030b
2 changed files with 55 additions and 91 deletions

View file

@ -43,12 +43,13 @@ export const Replace = Object.freeze({
x.push() x.push()
return x.symbol return x.symbol
}, },
Pop: x => x.pop(), Pop: x => x.pop().symbol,
Swap: x => { Swap: x => {
const tmp = x.pop() const a = x.pop()
x.push() const b = x.pop()
x.push(tmp) x.push(a)
return tmp.symbol x.push(b)
return b.symbol
}, },
ClearStack: tee(x => x.clear()), ClearStack: tee(x => x.clear()),
FromStack: x => x.peek().symbol, 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) a[i] = a[i].padEnd(spaces + diff)
return a return a
} }
const range = n => [...Array(n).keys()] const range = n => [...Array(n).keys()]
export class TuringMachine { export class TuringMachine {

View file

@ -3,84 +3,46 @@ import { resolve } from 'node:path'
import { Rules, Rule, Predicate, Replace, Tape, TuringMachine, Seek } from './automaton.js' import { Rules, Rule, Predicate, Replace, Tape, TuringMachine, Seek } from './automaton.js'
const { First, Last, Left, Right, Stay, SeekFromStack, JumpFromStack } = Seek const { First, Last, Left, Right, Stay, SeekFromStack, JumpFromStack } = Seek
const { ClearStack, Nothing, Push, Seq, Swap, With } = Replace const { ClearStack, Nothing, Pop, Push, Seq, Swap, With } = Replace
const { InBounds, Not, OutOfBounds, True } = Predicate const { Every, InBounds, Not, OutOfBounds, True } = Predicate
const State = Object.freeze({ const HasMemory = x => x.peek() != null
Start: 'start', const IsFree = Predicate.Equals('.')
ScanRight: 'scan-right', const IsFile = Not(IsFree)
FindFile: 'find-file', const IsMovingRight = x => {
ScanLeft: 'scan-left', return x.stack[0].position <= x.position
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 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 | // | From | To | Condition | Next Character | Move Direction |
// | ------------------------------------------------------------------------------| // | ------------------------------------------------------------------------------|
// new Rule('q0', 'q1', reader => reader.symbol === '1', (_reader) => '0', 1) // 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([ const rules = new Rules([
new Rule(State.Start, State.ScanRight, True, Nothing, Right), new Rule(State.Start, State.NextFree, True, Nothing, Right),
new Rule(State.ScanRight, State.FindFile, TrySkipping, ClearStack, Last), //
new Rule(State.ScanRight, State.FindFile, ShouldContinue, ClearStack, Stay), // find free space
new Rule(State.ScanRight, State.ScanRight, InBounds(Right), Push, Right), new Rule(State.NextFree, State.Halt, OutOfBounds(Right), Nothing, Stay),
new Rule(State.FindFile, State.ScanLeft, IsNotFree, Seq(ClearStack, Push), Stay), new Rule(State.NextFree, State.NextFile, Every(IsFree, HasMemory), Nothing, JumpFromStack),
new Rule(State.FindFile, State.FindFile, IsFreeSpace, Nothing, Left), new Rule(State.NextFree, State.NextFile, IsFree, Push, Last),
new Rule(State.ScanLeft, State.ScanLeft, InBounds(Left), Nothing, FirstOrStack), new Rule(State.NextFree, State.NextFree, IsFile, Nothing, Right),
new Rule(State.ScanLeft, State.FindSpace, OutOfBounds(Left), Nothing, Stay),
new Rule(State.FindSpace, State.ScanRight, IsFartherRight, ClearStack, Right), // find file
new Rule(State.FindSpace, State.ClearFile, IsFreeSpace, Swap, JumpFromStack), new Rule(State.NextFile, State.Halt, OutOfBounds(Left), Nothing, Stay),
new Rule(State.FindSpace, State.FindSpace, InBounds(Right), Nothing, Right), new Rule(State.NextFile, State.MoveFile, IsFile, Seq(Push, Swap, With('.')), SeekFromStack(true)),
new Rule(State.ClearFile, State.ScanRight, True, With('.'), SeekFromStack(false)), 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) 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 main = input => {
const expanded = expand(input) const expanded = expand(input)
console.log(expanded)
const compressed = compress(expanded) const compressed = compress(expanded)
console.log(compressed.filter(notFree).map(toInt))
const sum = checksum(compressed) const sum = checksum(compressed)
return sum return sum
} }
const tests = [ const tests = [
['2333133121414131402', 1928], //['12345', 486]
['1010101010101010101010', 385], // ['2333133121414131402', 1928],
['111111111111111111111', 290], //['1010101010101010101010', 385],
['10101010101010101010101', 506], //['111111111111111111111', 290],
['90909', 486] //['10101010101010101010101', 506],
//['91'.repeat(100), 506],
//['90909', 486]
] ]
tests.forEach(([input, expected]) => { tests.forEach(([input, expected], i) => {
console.log(`input length is ${input.length}`) //console.log(`input length is ${input.length}`)
const result = main(input) const result = main(input)
console.log(result === expected, result) console.log(i, result === expected, result)
}) })
//readFile(resolve('./input'), { encoding: 'utf8' }) readFile(resolve('./input'), { encoding: 'utf8' })
// .then(x => { .then(x => {
// console.log(`input length is ${x.length}`) console.log(`input length is ${x.length}`)
// return main(x) return main(x)
// }) })
// .then(console.log) .then(console.log)