make the automaton one a little faster
This commit is contained in:
parent
9716a10886
commit
6665b7030b
2 changed files with 55 additions and 91 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue