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()
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 {

View file

@ -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)