Repository: ealter/vim_turing_machine
Branch: master
Commit: 7a7647f3e5b2
Files: 36
Total size: 66.4 KB
Directory structure:
gitextract_mhyv690l/
├── .coveragerc
├── .deactivate.sh
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── Makefile
├── README.md
├── decode_hours.sh
├── requirements-dev.txt
├── setup.cfg
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── machines/
│ │ ├── __init__.py
│ │ ├── is_number_even_test.py
│ │ └── merge_overlapping_intervals/
│ │ ├── __init__.py
│ │ ├── decode_intervals_test.py
│ │ ├── encode_intervals_test.py
│ │ ├── merge_overlapping_intervals_test.py
│ │ └── vim_merge_overlapping_intervals_test.py
│ └── turing_machine_test.py
├── tox.ini
├── vim_turing_machine/
│ ├── __init__.py
│ ├── constants.py
│ ├── machines/
│ │ ├── __init__.py
│ │ ├── is_number_even.py
│ │ ├── merge_overlapping_intervals/
│ │ │ ├── __init__.py
│ │ │ ├── decode_intervals.py
│ │ │ ├── encode_intervals.py
│ │ │ ├── merge_overlapping_intervals.py
│ │ │ └── vim_merge_overlapping_intervals.py
│ │ └── vim_is_number_even.py
│ ├── struct.py
│ ├── turing_machine.py
│ ├── vim_constants.py
│ └── vim_machine.py
└── vimrc
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveragerc
================================================
[run]
branch = True
source =
.
omit =
.tox/*
/usr/*
setup.py
[report]
show_missing = True
skip_covered = True
exclude_lines =
# Have to re-enable the standard pragma
\#\s*pragma: no cover
# Don't complain if tests don't hit defensive assertion code:
^\s*raise AssertionError\b
^\s*raise NotImplementedError\b
^\s*return NotImplemented\b
^\s*raise$
# Don't complain if non-runnable code isn't run:
^if __name__ == ['"]__main__['"]:$
[html]
directory = coverage-html
# vim:ft=dosini
================================================
FILE: .deactivate.sh
================================================
deactivate
================================================
FILE: .gitignore
================================================
*.egg-info
*.py[co]
/.cache
/.coverage
/.tox
/coverage-html
/dist
/venv
machine.vim
*.swp
================================================
FILE: .pre-commit-config.yaml
================================================
- repo: https://github.com/pre-commit/pre-commit-hooks
sha: v0.9.2
hooks:
- id: trailing-whitespace
language_version: python3.6
- id: end-of-file-fixer
language_version: python3.6
exclude: ^\.activate\.sh$
- id: autopep8-wrapper
language_version: python3.6
- id: check-docstring-first
language_version: python3.6
- id: check-executables-have-shebangs
language_version: python3.6
- id: check-merge-conflict
language_version: python3.6
- id: check-yaml
language_version: python3.6
- id: debug-statements
language_version: python3.6
- id: double-quote-string-fixer
language_version: python3.6
- id: name-tests-test
language_version: python3.6
- id: flake8
language_version: python3.6
- id: check-added-large-files
language_version: python3.6
exclude: ^\.activate\.sh$
- id: check-byte-order-marker
language_version: python3.6
- repo: https://github.com/asottile/reorder_python_imports
sha: v0.3.5
hooks:
- id: reorder-python-imports
language_version: python3.6
- repo: https://github.com/asottile/pyupgrade
sha: v1.2.0
hooks:
- id: pyupgrade
language_version: python3.6
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
.PHONY: minimal
minimal: venv
venv:
tox -e venv
.PHONY: install-hooks
install-hooks: venv
venv/bin/pre-commit install-hooks
venv/bin/pre-commit install
.PHONY: test
test:
tox
.PHONY: clean
clean:
find . -name '*.pyc' -delete
find . -name '__pycache__' -delete
rm -rf .tox
rm -rf venv
rm machine.vim
.PHONY: run
run: venv
venv/bin/python -m vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals '[[1,2],[2,3],[5,8]]' 5
.PHONY: run-vim
build-vim: venv
venv/bin/python -m vim_turing_machine.machines.merge_overlapping_intervals.vim_merge_overlapping_intervals '[[1,2],[2,3],[5,8]]' 5
open-vim-machine: build-vim
vim -u vimrc machine.vim
run-vim-machine: build-vim
vim -u vimrc machine.vim -c ':normal gg0yy@"'
================================================
FILE: README.md
================================================
Vim Turing Machine
==================
Ever wish you could run your code in your editor? Tired of installing huge
dependencies like bash or python to run your scripts? Love Vim so much that you
never want to leave it? Why not run your code... in your editor itself? Enter
vim_turing_machine: a tool to allow you to run a Turing machine using only
normal mode Vim commands.
And now you might ask, but what can we do on a Turing machine! To demonstrate
its capabilities, we implemented a solution to the Merge Overlapping Intervals
question and defined all the state transitions needed to solve this
glorious problem. So next time you need to merge some intervals, don't
hand-write a 10-line python program. Instead, take out your favorite editor and
watch it solve the problem in less than a minute with 1400 state transitions!
But a simple naysayer may say, 'We already have vimscript! Why in God's name
would I want to use a Turing machine instead?' To that, we retort: our Turing
machine only uses normal mode. So you could theoretically just type in the
program and then execute it without running a single script! No ex mode either!
This project proves that normal mode in Vim is as powerful as any computer!
Merging your favorite intervals
===============================
Given a set of sorted potentially overlapping open/close intervals, merge the
overlapping intervals together.
Example:
```
[[1, 5], [6, 7]] -> [[1, 5], [6, 7]]
[[1, 5], [2, 3], [5, 7], [12, 15]] -> [[1, 7], [12, 15]]
```
Running the Python Turing Machine: `make run`
Opening the Vim Turing Machine without running it: `make open-vim-machine`
Opening and then running the Vim Turing Machine: `make run-vim-machine`
So Vim did what? Wait. How does it even?
========================================
So you run this program, and it works. Great! So what happened? Well the most
common thing you're going to see is `y$@"`. What this does is yank from the
current cursor to the end of the line and then executes the default register as
a macro. This allows us to encode motions in lines and then execute them. We
then chain lines together by ending lines with moving to a mark, or a search
result, and then yanking and executing that line.
Using that nifty trick, we begin by yanking the first line and executing it.
That then sets off our mark initialization. We then search for `_<someletter>`
and then mark that position with the corresponding letter. Generally the first
initial of whatever the thing we're marking is. Once everything is marked, we
then begin the state transitions.
We begin a state transition by executing a long command (located at `_n:`)
which jumps to the tape marker, yanks it, then jumps to the current state
marker, yanks that too, and then searches for some transition that contains both
the state and tape values. Once it gets to that line, it jumps to the command
string and then executes our trusty `y$@"` to execute it. To make sure we keep
transitioning, each state transition ends with `` `ny$@ `` which tells it to jump
to our "next state" marker and then execute it again, which kicks off the search
for the next state.
The execution halts when it can't find a new state to transition to. The state
search includes an "or" operator where it will fall back to matching `---`,
which tells it to print the current state and halt.
Most transitions themselves involve changing a tape value or a state value and
then moving in some direction on the tape. Changing values consists of jumping
to the tape or state marks (`` `t `` or `` `k `` respectively) and then using
`cw` or `C` to change the value. We then move the pointer by jumping to the tape
position (`` `t ``) and then moving a word forward (`W`) or backward (`B`), and
then marking the new tape position.
The last real piece of complication is extending the tape. We're living in a
world with unlimited tapes! What a time to be alive! This is done through a
series of nifty hacks. First, we have a modeline that sets `whichwrap+b,s`. This
allows us to move across line breaks and keep the tape all in the screen. Next,
the line directly under the tape contains a "fake" value that, when added to our
state search, will prevent it from matching any real state transitions and
instead match a "transition" for adding a line to the tape. This line tells us
to jump to the end of the tape, and then insert a full line of empty values (we
use `X`), and then go back to our original tape location and execute the next
state transition!
And there you have it! A simple `ggyy@"` will kick off all of these sequences
until execution completes. The cool thing is that this isn't special to the
intervals problem. In fact, you can write your own state machine and use the
provided Vim adapter to create a new Vim machine to solve any problem that can
be solved by a Turing Machine!
To see some more details about various common commands, you can take a look at
`vim_turing_machine/vim_constants.py`. That file contains some constants that
are used repeatedly in the generated `machine.vim` file and their names are
fairly descriptive. Also, if you'd like to step through manually, you can edit
the Vim machine in `vim_turing_machine/machines/vim_is_number_even.py` and tell
it not to auto step and then step through manually using `y$@"`.
Happy hacking!
Dependencies
============
To run this code, you will need `python3.6`, `tox`, and `vim` installed on your
machine. This code hasn't been tested on other versions of python3, but they'll
probably work if you change the pinned version in `tox.ini`. This code is not
python2 compatible.
Contributors
============
eliot and ifij wrote this project in July 2017 for Yelp's Hackathon 23. It was inspired by [vimmmex](https://github.com/xoreaxeaxeax/vimmmex): a Brainfuck interpretor written in Vim.
[modeline]: # ( vim: set fenc=utf-8 spell spl=en textwidth=80: )
================================================
FILE: decode_hours.sh
================================================
#! /bin/bash
venv/bin/python -m vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals "$1" $2
================================================
FILE: requirements-dev.txt
================================================
coverage
flake8
pre-commit>=0.15
pytest
================================================
FILE: setup.cfg
================================================
[wheel]
universal = True
================================================
FILE: setup.py
================================================
from setuptools import find_packages
from setuptools import setup
setup(
name='vim-turing-machine',
version='1.0.0',
classifiers=[
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
],
install_requires=[
'colored',
],
packages=find_packages(exclude=('tests*', 'testing*')),
)
================================================
FILE: tests/__init__.py
================================================
================================================
FILE: tests/machines/__init__.py
================================================
================================================
FILE: tests/machines/is_number_even_test.py
================================================
import pytest
from vim_turing_machine.constants import BLANK_CHARACTER
from vim_turing_machine.constants import NO_FINAL_STATE
from vim_turing_machine.constants import YES_FINAL_STATE
from vim_turing_machine.machines.is_number_even import number_is_even_state_transitions
from vim_turing_machine.turing_machine import TuringMachine
def assert_tape(machine, expected_tape):
# Ignore any blanks at the end
assert expected_tape == ''.join(machine.tape).rstrip(BLANK_CHARACTER)
def run_machine(transitions, tape):
machine = TuringMachine(list(transitions), quiet=True)
machine.run(tape[:], max_steps=10000)
assert_tape(machine, tape)
return machine
@pytest.mark.parametrize('tape, is_even', [
('', False),
('1', False),
('0', True),
('1001', False),
('1010', True),
])
def test_is_number_even(tape, is_even):
machine = run_machine(number_is_even_state_transitions, tape)
if is_even:
assert machine.current_state == YES_FINAL_STATE
else:
assert machine.current_state == NO_FINAL_STATE
================================================
FILE: tests/machines/merge_overlapping_intervals/__init__.py
================================================
================================================
FILE: tests/machines/merge_overlapping_intervals/decode_intervals_test.py
================================================
from vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals import decode_intervals
def test_encode_intervals():
assert decode_intervals('{}{}'.format('01010', '11111'), 5) == [[10, 31]]
================================================
FILE: tests/machines/merge_overlapping_intervals/encode_intervals_test.py
================================================
import pytest
from vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_in_x_bits
from vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_intervals
@pytest.mark.parametrize('number, encoded', [
(0, '00000'),
(10, '01010'),
(31, '11111'),
])
def test_encode_in_x_bits(number, encoded):
assert encode_in_x_bits(number, num_bits=5) == encoded
def test_encode_intervals():
assert encode_intervals([(10, 31)], num_bits=5) == '{}{}'.format('01010', '11111')
================================================
FILE: tests/machines/merge_overlapping_intervals/merge_overlapping_intervals_test.py
================================================
from unittest import mock
import pytest
import vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals
import vim_turing_machine.struct
import vim_turing_machine.turing_machine
from vim_turing_machine.constants import INITIAL_STATE
from vim_turing_machine.constants import NO_FINAL_STATE
from vim_turing_machine.constants import YES_FINAL_STATE
from vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals import decode_intervals
from vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_intervals
from vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals import invert_bit
from vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals import invert_direction
from vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals import MergeOverlappingIntervalsGenerator
from vim_turing_machine.struct import BACKWARDS
from vim_turing_machine.struct import FORWARDS
from vim_turing_machine.turing_machine import TuringMachine
@pytest.yield_fixture(autouse=True)
def mock_blank_character():
"""Change the blank character to be a space so that it's easier to write test cases."""
with mock.patch.object(
vim_turing_machine.turing_machine,
'BLANK_CHARACTER',
' ',
):
with mock.patch.object(
vim_turing_machine.struct,
'VALID_CHARACTERS',
('0', '1', ' '),
):
with mock.patch.object(
vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals,
'BLANK_CHARACTER',
' ',
):
with mock.patch.object(
vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals,
'VALID_CHARACTERS',
('0', '1', ' '),
):
yield
@pytest.fixture
def merger():
return MergeOverlappingIntervalsGenerator(num_bits=3)
def run_machine(transitions, tape, initial_position=0, assert_tape_not_changed=False):
machine = TuringMachine(list(transitions), quiet=True)
machine.run(tape[:], max_steps=10000, initial_cursor_position=initial_position)
if assert_tape_not_changed:
assert_tape(machine, tape)
return machine
def assert_cursor_at_end_of_output(machine):
end = len(machine.tape) - 1
while end > 0 and machine.tape[end] == ' ':
end -= 1
assert machine.cursor_position == end
def assert_cursor_is_at_beginning_of_input(machine):
i = 0
while i < len(machine.tape) and machine.tape[i] == ' ':
i += 1
assert machine.cursor_position == i
def assert_tape(machine, expected_tape):
# Ignore any blanks at the end
assert expected_tape == ''.join(machine.tape).rstrip()
def test_invert_bit():
assert invert_bit('0') == '1'
assert invert_bit('1') == '0'
with pytest.raises(AssertionError):
invert_bit('not_valid')
def test_invert_direction():
assert invert_direction(FORWARDS) == BACKWARDS
assert invert_direction(BACKWARDS) == FORWARDS
with pytest.raises(AssertionError):
invert_direction('not_valid')
def test_move_n_bits(merger):
machine = run_machine(
merger.move_n_bits(
initial_state=INITIAL_STATE,
direction=FORWARDS,
final_state=YES_FINAL_STATE,
num_bits=4,
),
tape='01010111',
assert_tape_not_changed=True,
)
assert machine.cursor_position == 4
def test_move_to_blank_spaces(merger):
machine = run_machine(
merger.move_to_blank_spaces(
initial_state=INITIAL_STATE,
direction=FORWARDS,
final_state=YES_FINAL_STATE,
final_character=' ',
final_direction=BACKWARDS,
num_blanks=2,
),
tape='01 1111 10',
assert_tape_not_changed=True,
)
assert machine.cursor_position == 6 # End of the 1111
def test_copy_bits_to_end_of_output(merger):
machine = run_machine(
merger.copy_bits_to_end_of_output(
initial_state=INITIAL_STATE,
num_bits=3,
final_state=YES_FINAL_STATE,
),
tape='10111 01',
)
assert_tape(machine, ' 11 01101')
assert_cursor_at_end_of_output(machine)
@pytest.mark.parametrize('tape, final_state', [
('101 100110', NO_FINAL_STATE),
('101 100100', YES_FINAL_STATE),
('101 111100', YES_FINAL_STATE),
])
def test_compare_two_sequential_numbers(merger, tape, final_state):
machine = run_machine(
merger.compare_two_sequential_numbers(
initial_state=INITIAL_STATE,
greater_than_or_equal_to_state=YES_FINAL_STATE,
less_than_state=NO_FINAL_STATE,
),
tape=tape,
initial_position=len(tape) - 1,
assert_tape_not_changed=True,
)
assert_cursor_at_end_of_output(machine)
assert machine.current_state == final_state
def test_erase_number(merger):
machine = run_machine(
merger.erase_number(
initial_state=INITIAL_STATE,
final_state=YES_FINAL_STATE,
),
tape='100101110',
initial_position=5, # end of 101
)
assert machine.cursor_position == 2
assert_tape(machine, '100 110')
def test_replace_number(merger):
tape = '100101110'
machine = run_machine(
merger.replace_number(
initial_state=INITIAL_STATE,
final_state=YES_FINAL_STATE,
),
tape=tape,
initial_position=len(tape) - 1,
)
assert_tape(machine, '100110')
assert_cursor_at_end_of_output(machine)
@pytest.mark.parametrize('tape, final_state', [
(' 100 101101', NO_FINAL_STATE),
(' 100101101', YES_FINAL_STATE),
])
def test_check_if_there_is_any_input_left(merger, tape, final_state):
machine = run_machine(
merger.check_if_there_is_any_input_left(
initial_state=INITIAL_STATE,
final_state=NO_FINAL_STATE, # The machine exits with Yes if there is no input left.
),
tape=tape,
initial_position=len(tape) - 1,
assert_tape_not_changed=True,
)
assert_cursor_is_at_beginning_of_input(machine)
assert machine.current_state == final_state
@pytest.mark.parametrize('initial_tape, final_tape', [
(' 100 001010001', ' 001100'), # 2nd pair's closing value is larger
(' 010 001110001', ' 001110'), # 2nd pair's closing value is smaller
(' 110 001110001', ' 001110'), # 2nd pair's closing value is equal
])
def test_copy_closing_value_and_merge(merger, initial_tape, final_tape):
machine = run_machine(
merger.copy_closing_value_and_merge(
initial_state=INITIAL_STATE,
final_state=YES_FINAL_STATE,
),
tape=initial_tape,
initial_position=len(initial_tape) - 1,
)
assert_cursor_at_end_of_output(machine)
assert_tape(machine, final_tape)
def test_copy_closing_value_without_merging(merger):
tape = ' 111 000010110'
machine = run_machine(
merger.copy_closing_value_without_merging(
initial_state=INITIAL_STATE,
final_state=YES_FINAL_STATE,
),
tape=tape,
initial_position=len(tape) - 1,
)
assert_cursor_at_end_of_output(machine)
assert_tape(machine, ' 000010110111')
@pytest.mark.parametrize(
'initial_intervals, final_intervals',
[
(
[[0, 1]],
[[0, 1]],
),
(
[[0, 1], [5, 6]],
[[0, 1], [5, 6]],
),
(
[[0, 5], [2, 3]],
[[0, 5]],
),
(
[[1, 3], [3, 4], [4, 5], [6, 7]],
[[1, 5], [6, 7]],
)
]
)
def test_merge_overlapping_intervals(merger, initial_intervals, final_intervals):
"""The true integration test!"""
tape = encode_intervals(initial_intervals, num_bits=3)
machine = run_machine(
merger.merge_overlapping_intervals_transitions(),
tape=tape,
)
assert final_intervals == decode_intervals(''.join(machine.tape), num_bits=3)
================================================
FILE: tests/machines/merge_overlapping_intervals/vim_merge_overlapping_intervals_test.py
================================================
import subprocess
from vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals import decode_intervals
from vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_intervals
from vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals import MergeOverlappingIntervalsGenerator
from vim_turing_machine.vim_constants import VIM_MACHINE_FILENAME
from vim_turing_machine.vim_machine import VimTuringMachine
NUM_BITS = 3
def run_vim_machine(intervals):
initial_tape = encode_intervals(intervals, NUM_BITS)
gen = MergeOverlappingIntervalsGenerator(NUM_BITS)
merge_overlapping_intervals = VimTuringMachine(gen.merge_overlapping_intervals_transitions(), debug=False)
# Write to the vim machine file
merge_overlapping_intervals.run(initial_tape=initial_tape)
subprocess.run(
[
'vim',
'-u',
'vimrc',
VIM_MACHINE_FILENAME,
'-c',
# Execute the vim machine and then save the resulting file
":execute 'normal gg0yy@\"' | :x",
],
timeout=10,
check=True,
)
def read_contents_of_tape():
with open(VIM_MACHINE_FILENAME, 'r') as f:
tape_lines = []
found_beginning_of_tape = False
for line in f:
# Look for the lines between '_t:' and 'notvalid'
if line.startswith('_t:'):
found_beginning_of_tape = True
elif line.startswith('notvalid'):
return convert_tape_to_string(tape_lines)
elif found_beginning_of_tape:
tape_lines.append(line)
raise AssertionError('Could not find the tape')
def convert_tape_to_string(tape_lines):
return ''.join(tape_lines).replace(' ', '').replace('\n', '')
def test_merge_intervals_in_vim():
run_vim_machine([[1, 2], [2, 3], [5, 7]])
tape = read_contents_of_tape()
intervals = decode_intervals(tape, num_bits=NUM_BITS)
assert intervals == [[1, 3], [5, 7]]
================================================
FILE: tests/turing_machine_test.py
================================================
import pytest
from vim_turing_machine.constants import FORWARDS
from vim_turing_machine.struct import StateTransition
from vim_turing_machine.turing_machine import DuplicateStateTransitionException
from vim_turing_machine.turing_machine import validate_state_transitions
def test_invalid_state_transition():
with pytest.raises(AssertionError):
validate_state_transitions([
StateTransition(
previous_state='foo',
previous_character='Not a valid character',
next_state='bar',
next_character='0',
tape_pointer_direction=FORWARDS,
)
])
def test_valid_states():
validate_state_transitions(
[
StateTransition(
previous_state='foo',
previous_character='0',
next_state='bar',
next_character='0',
tape_pointer_direction=FORWARDS,
),
StateTransition(
previous_state='foo',
previous_character='1',
next_state='bar',
next_character='1',
tape_pointer_direction=FORWARDS,
),
]
)
def test_duplicate_states():
state = StateTransition(
previous_state='foo',
previous_character='0',
next_state='bar',
next_character='0',
tape_pointer_direction=FORWARDS,
)
with pytest.raises(DuplicateStateTransitionException):
validate_state_transitions([state, state])
================================================
FILE: tox.ini
================================================
[tox]
envlist = py3
tox_pip_extensions_ext_pip_custom_platform = true
tox_pip_extensions_ext_venv_update = true
[testenv]
deps = -rrequirements-dev.txt
passenv = HOME SSH_AUTH_SOCK USER
commands =
coverage erase
coverage run -m pytest {posargs:tests}
coverage report
pre-commit install -f --install-hooks
pre-commit run --all-files
[testenv:venv]
basepython = python3
envdir = venv
commands =
[flake8]
max-line-length = 131
[pep8]
ignore = E265,E309,E501
================================================
FILE: vim_turing_machine/__init__.py
================================================
================================================
FILE: vim_turing_machine/constants.py
================================================
BLANK_CHARACTER = 'X'
INITIAL_STATE = 'InitialState'
YES_FINAL_STATE = 'YES'
NO_FINAL_STATE = 'NO'
BITS_PER_NUMBER = 5
FINAL_STATES = [YES_FINAL_STATE, NO_FINAL_STATE]
# Tape pointer direction
FORWARDS = 1
DO_NOT_MOVE = 0
BACKWARDS = -1
VALID_CHARACTERS = {'0', '1', BLANK_CHARACTER}
INVALID_STATE_CHARACTERS = ['_', '-', ':']
================================================
FILE: vim_turing_machine/machines/__init__.py
================================================
================================================
FILE: vim_turing_machine/machines/is_number_even.py
================================================
import sys
from vim_turing_machine.constants import BLANK_CHARACTER
from vim_turing_machine.constants import INITIAL_STATE
from vim_turing_machine.constants import NO_FINAL_STATE
from vim_turing_machine.constants import YES_FINAL_STATE
from vim_turing_machine.struct import BACKWARDS
from vim_turing_machine.struct import FORWARDS
from vim_turing_machine.struct import StateTransition
from vim_turing_machine.turing_machine import TuringMachine
ADVANCE_TO_END_OF_NUMBER = 'onward!'
FOUND_END_OF_NUMBER = 'eof'
number_is_even_state_transitions = (
# A number is not even if the initial tape is blank.
StateTransition(
previous_state=INITIAL_STATE,
previous_character=BLANK_CHARACTER,
next_state=NO_FINAL_STATE,
next_character=BLANK_CHARACTER,
tape_pointer_direction=FORWARDS,
),
# But any other number initially means that we should go find the end of the array
StateTransition(
previous_state=INITIAL_STATE,
previous_character='0',
next_character='0',
next_state=ADVANCE_TO_END_OF_NUMBER,
tape_pointer_direction=FORWARDS,
),
StateTransition(
previous_state=INITIAL_STATE,
previous_character='1',
next_character='1',
next_state=ADVANCE_TO_END_OF_NUMBER,
tape_pointer_direction=FORWARDS,
),
# Once we're looking for the end of the number, go until we hit a blank
StateTransition(
previous_state=ADVANCE_TO_END_OF_NUMBER,
previous_character='0',
next_character='0',
next_state=ADVANCE_TO_END_OF_NUMBER,
tape_pointer_direction=FORWARDS,
),
StateTransition(
previous_state=ADVANCE_TO_END_OF_NUMBER,
previous_character='1',
next_character='1',
next_state=ADVANCE_TO_END_OF_NUMBER,
tape_pointer_direction=FORWARDS,
),
# Once we're looking for the end of the number, go until we hit a blank.
# Then backtrack 1 space.
StateTransition(
previous_state=ADVANCE_TO_END_OF_NUMBER,
previous_character=BLANK_CHARACTER,
next_character=BLANK_CHARACTER,
next_state=FOUND_END_OF_NUMBER,
tape_pointer_direction=BACKWARDS,
),
# Now that we're on the last character, check if it is even or odd
StateTransition(
previous_state=FOUND_END_OF_NUMBER,
previous_character='0',
next_character='0',
next_state=YES_FINAL_STATE,
tape_pointer_direction=FORWARDS,
),
StateTransition(
previous_state=FOUND_END_OF_NUMBER,
previous_character='1',
next_character='1',
next_state=NO_FINAL_STATE,
tape_pointer_direction=FORWARDS,
),
)
if __name__ == '__main__':
even_odd_turing_machine = TuringMachine(number_is_even_state_transitions, debug=True)
even_odd_turing_machine.run(initial_tape=sys.argv[1])
================================================
FILE: vim_turing_machine/machines/merge_overlapping_intervals/__init__.py
================================================
================================================
FILE: vim_turing_machine/machines/merge_overlapping_intervals/decode_intervals.py
================================================
"""Decodes a binary string to a json representation of the intervals
after the merge overlapping intervals turing machine have processed them. Reads
json from the command line and outputs the initial tape."""
import json
import sys
from vim_turing_machine.constants import BITS_PER_NUMBER
from vim_turing_machine.constants import BLANK_CHARACTER
def decode_intervals(intervals, num_bits=BITS_PER_NUMBER):
result = []
clean_intervals = intervals.replace(BLANK_CHARACTER, '').replace(' ', '')
index = 0
while index < len(clean_intervals):
begin = clean_intervals[index:index + num_bits]
begin = int(begin, 2)
index += num_bits
end = clean_intervals[index:index + num_bits]
end = int(end, 2)
index += num_bits
result.append([begin, end])
return result
if __name__ == '__main__':
print(json.dumps(decode_intervals(sys.argv[1], int(sys.argv[2]))))
================================================
FILE: vim_turing_machine/machines/merge_overlapping_intervals/encode_intervals.py
================================================
"""Encodes a json representation of the intervals into the 5-bit binary
representation used by the merge overlapping intervals turing machine. It
takes input from stdin and outputs the initial tape."""
import json
import sys
from vim_turing_machine.constants import BITS_PER_NUMBER
def encode_intervals(intervals, num_bits=BITS_PER_NUMBER):
result = ''
for (begin, end) in intervals:
result += encode_in_x_bits(begin, num_bits)
result += encode_in_x_bits(end, num_bits)
return result
def encode_in_x_bits(number, num_bits):
encoded = '{:b}'.format(number)
assert len(encoded) <= num_bits
# Add leading zeros
return '0' * (num_bits - len(encoded)) + encoded
if __name__ == '__main__':
print(encode_intervals(json.load(sys.stdin)))
================================================
FILE: vim_turing_machine/machines/merge_overlapping_intervals/merge_overlapping_intervals.py
================================================
"""Our tape is defined in multiple segments, each separated by a blank character.
INPUT<Blank>OUTPUT
This program solves the "Merge Overlapping Intervals" problem: Given a sorted
list of possibly overlapping (opening, closing) intervals, merge them.
Example: [[1, 5], [2, 3], [4, 6], [9, 11]] -> [[1, 6], [9, 11]]
We do this... on a turing machine.
"""
import itertools
import json
import sys
from vim_turing_machine.constants import BITS_PER_NUMBER
from vim_turing_machine.constants import BLANK_CHARACTER
from vim_turing_machine.constants import INITIAL_STATE
from vim_turing_machine.constants import VALID_CHARACTERS
from vim_turing_machine.constants import YES_FINAL_STATE
from vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals import decode_intervals
from vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_intervals
from vim_turing_machine.struct import BACKWARDS
from vim_turing_machine.struct import DO_NOT_MOVE
from vim_turing_machine.struct import FORWARDS
from vim_turing_machine.struct import StateTransition
from vim_turing_machine.turing_machine import TuringMachine
class MergeOverlappingIntervalsGenerator(object):
def __init__(self, num_bits=BITS_PER_NUMBER):
self._num_bits = num_bits
def merge_overlapping_intervals_transitions(self):
"""This is the main orchestration point of the program"""
# This is the beginning of the loop that goes through the rest of the intervals.
CHECK_NEXT_SET_OF_HOURS = 'CheckNextSetOfHours'
# We begin the program by copying the first intervals pair into the output
# array. At the end of this, the cursor will be at the end of the
# output array.
transitions = list(
self.copy_bits_to_end_of_output(
initial_state=INITIAL_STATE,
num_bits=self._num_bits * 2,
final_state=CHECK_NEXT_SET_OF_HOURS,
)
)
BEGIN_COPY_NEXT_SET_OF_HOURS = 'CopyNextSetOfHours'
BEGIN_COMPARISON = 'BeginComparison'
# Then move back to the beginning of the input while checking if there is any input left
transitions.extend(
self.check_if_there_is_any_input_left(
initial_state=CHECK_NEXT_SET_OF_HOURS,
final_state=BEGIN_COPY_NEXT_SET_OF_HOURS,
)
)
# Now it's time to copy the opening intervals of the next pair.
transitions.extend(
self.copy_bits_to_end_of_output(
initial_state=BEGIN_COPY_NEXT_SET_OF_HOURS,
num_bits=self._num_bits,
final_state=BEGIN_COMPARISON,
)
)
OPEN_HOUR_IS_LESS_THAN = 'OpeningLessThan'
OPEN_HOUR_IS_GREATER_THAN = 'OpeningGreaterThan'
# Next we compare the closing intervals of the previous pair with the
# opening intervals of the current pair.
transitions.extend(
self.compare_two_sequential_numbers(
initial_state=BEGIN_COMPARISON,
greater_than_or_equal_to_state=OPEN_HOUR_IS_LESS_THAN,
less_than_state=OPEN_HOUR_IS_GREATER_THAN,
)
)
transitions.extend(
self.copy_closing_value_without_merging(
initial_state=OPEN_HOUR_IS_GREATER_THAN,
final_state=CHECK_NEXT_SET_OF_HOURS,
)
)
transitions.extend(
self.copy_closing_value_and_merge(
initial_state=OPEN_HOUR_IS_LESS_THAN,
final_state=CHECK_NEXT_SET_OF_HOURS,
)
)
return transitions
def copy_closing_value_without_merging(self, initial_state, final_state):
"""Things are super simple if we don't need to merge the intervals. We just need
to copy over the closing intervals from the input array.
Precondition: we are at the end of the output array. The opening intervals
have already been copied. The opening value is greater than the
previous pair's closing value.
Postcondition: we are at the end of the output array
"""
COPY_CLOSING_HOUR_WITHOUT_MERGING = 'CopyClosingHourWithoutMerging'
# First move back to the beginning of the input array since the copy
# function requires that.
transitions = self.move_to_blank_spaces(
initial_state=initial_state,
final_state=COPY_CLOSING_HOUR_WITHOUT_MERGING,
final_character=BLANK_CHARACTER,
final_direction=FORWARDS,
direction=BACKWARDS,
num_blanks=2,
)
# Then just copy the closing value from the input array to the output array.
transitions.extend(
self.copy_bits_to_end_of_output(
initial_state=COPY_CLOSING_HOUR_WITHOUT_MERGING,
num_bits=self._num_bits,
final_state=final_state,
)
)
return transitions
def copy_closing_value_and_merge(self, initial_state, final_state):
"""Call this if you need to merge in the 2nd set of intervals.
Precondition: we are at the end of the output array. The opening intervals
have already been copied. The opening value is less than or equal to
the previous pair's closing value.
Postcondition: we are at the end of the output array
"""
MOVE_BACK_TO_BEGINNING_TO_COPY_CLOSING_HOUR = 'MoveToBeginningToCopyClosingHour'
COPY_OVER_CLOSING_HOUR = 'CopyClosingHour'
COMPARE_CLOSING_HOUR = 'CompareClosingHour'
CLOSING_HOUR_IS_LARGER = 'ClosingHourIsLarger'
CLOSING_HOUR_IS_NOT_LARGER = 'ClosingHourIsNotLarger'
# If the opening value is less than the closing value of the previous pair,
# then we discard that opening value. So essentially, [2, 7, 5] becomes [2, 7].
transitions = self.erase_number(
initial_state=initial_state,
final_state=MOVE_BACK_TO_BEGINNING_TO_COPY_CLOSING_HOUR,
)
# Move back to the beginning of the array.
transitions.extend(
self.move_to_blank_spaces(
initial_state=MOVE_BACK_TO_BEGINNING_TO_COPY_CLOSING_HOUR,
final_state=COPY_OVER_CLOSING_HOUR,
final_character=BLANK_CHARACTER,
final_direction=FORWARDS,
direction=BACKWARDS,
num_blanks=2,
)
)
# Now after erasing that number, we need to copy over the closing value so
# that we can merge it in.
transitions.extend(
self.copy_bits_to_end_of_output(
initial_state=COPY_OVER_CLOSING_HOUR,
num_bits=self._num_bits,
final_state=COMPARE_CLOSING_HOUR,
)
)
# Now we take the max of the 2 pairs' closing intervals.
transitions.extend(
self.compare_two_sequential_numbers(
initial_state=COMPARE_CLOSING_HOUR,
less_than_state=CLOSING_HOUR_IS_LARGER,
greater_than_or_equal_to_state=CLOSING_HOUR_IS_NOT_LARGER,
)
)
# If the closing value is less than or equal to the previous closing value, just nuke it.
transitions.extend(
self.erase_number(
initial_state=CLOSING_HOUR_IS_NOT_LARGER,
final_state=final_state,
)
)
# But if the closing value is greater than the previous closing value, we
# should overwrite that closing value with our larger value.
transitions.extend(
self.replace_number(
initial_state=CLOSING_HOUR_IS_LARGER,
final_state=final_state,
)
)
return transitions
def noop_when_non_blank(self, state, direction):
return (
StateTransition(
previous_state=state,
previous_character='0',
next_state=state,
next_character='0',
tape_pointer_direction=direction,
),
StateTransition(
previous_state=state,
previous_character='1',
next_state=state,
next_character='1',
tape_pointer_direction=direction,
),
)
def move_n_bits(self, initial_state, direction, final_state, num_bits):
"""Moves 'num_bits' in the specified direction. Errors if it encounters a
blank space while doing so. Ends in the final_state."""
def state_name(bit_index):
if bit_index == 0:
return initial_state
elif bit_index == num_bits:
return final_state
else:
return '{}MovingBit{}'.format(initial_state, bit_index)
return itertools.chain.from_iterable([
[
StateTransition(
previous_state=state_name(bit_index),
previous_character=bit_value,
next_state=state_name(bit_index + 1),
next_character=bit_value,
tape_pointer_direction=direction,
)
for bit_index in range(num_bits)
]
for bit_value in ['0', '1']
])
def move_to_blank_spaces(
self,
initial_state,
final_state,
final_character,
final_direction,
direction,
num_blanks,
):
"""Moves along the array until it hits a certain number of blank spaces.
:param str initial_state: The state used to trigger this code
:param str final_state: The state we should finish with
:param str final_character: The character we should write on that state transition
:param int final_direction: Which direction we should move at the end
:param int direction: Which direction we should search in
:param int num_blanks: How many blanks to search for
"""
def state_name(blank_num):
return '{}Searching{}'.format(initial_state, blank_num)
transitions = [
# Rename our current state
StateTransition(
previous_state=initial_state,
previous_character=character,
next_state=state_name(blank_num=0),
next_character=character,
tape_pointer_direction=DO_NOT_MOVE,
)
for character in VALID_CHARACTERS
]
for blank_num in range(num_blanks):
transitions.extend(
# If we're looking for the first blank, then keep going until we hit it
self.noop_when_non_blank(state_name(blank_num=blank_num), direction=direction)
)
if blank_num == num_blanks - 1:
# This is the last blank
transitions.append(
StateTransition(
previous_state=state_name(blank_num),
previous_character=BLANK_CHARACTER,
next_state=final_state,
next_character=final_character,
tape_pointer_direction=final_direction,
)
)
else:
# This is not the last blank
transitions.append(
StateTransition(
previous_state=state_name(blank_num),
previous_character=BLANK_CHARACTER,
next_state=state_name(blank_num + 1),
next_character=BLANK_CHARACTER,
tape_pointer_direction=direction,
)
)
return transitions
def copy_bits_to_end_of_output(self, initial_state, num_bits, final_state):
"""
:param string initial_state: The state used before we start to move
:param int num_bits: The number of bits to copy
:param StateTransition final_state: The state to finish with when we are done copying
Note: This overwrites the copied section with blanks.
Precondition: We are at the beginning of the input array
Postcondition: We are at the end of the output array
:rtype: [StateTransition]
"""
def state_name(bit_index):
if bit_index == 0:
return initial_state
else:
return '{}Copy{}'.format(initial_state, bit_index)
def copy_bit(bit_index, bit_value):
base_copying_state = '{}Bit{}'.format(state_name(bit_index + 1), bit_value)
return [
# Let's start copying the character. Note how we replace it with a blank.
StateTransition(
previous_state=state_name(bit_index),
previous_character=bit_value,
next_state='{}Forward'.format(base_copying_state),
next_character=BLANK_CHARACTER,
tape_pointer_direction=FORWARDS,
),
*self.move_to_blank_spaces(
initial_state='{}Forward'.format(base_copying_state),
# If we're on the last character, don't go backwards
final_state=(
'{}Backwards'.format(base_copying_state)
if bit_index < num_bits - 1
else final_state
),
final_character=bit_value,
final_direction=DO_NOT_MOVE,
direction=FORWARDS,
num_blanks=2,
),
*self.move_to_blank_spaces(
initial_state='{}Backwards'.format(base_copying_state),
final_state=state_name(bit_index + 1),
final_character=BLANK_CHARACTER,
final_direction=FORWARDS,
direction=BACKWARDS,
num_blanks=2,
),
]
return itertools.chain.from_iterable(
(
*copy_bit(bit_index, bit_value='0'),
*copy_bit(bit_index, bit_value='1'),
)
for bit_index in range(num_bits)
)
def compare_two_sequential_numbers(self, initial_state, greater_than_or_equal_to_state, less_than_state):
"""
If the earlier number is greater than or equal to the later number, this
will end in the greater_than_or_equal_to_state. If the earlier number is
less than the later number, this will end in the less_than_state.
Precondition: The cursor is at the end of the output array
Postcondition: The cursor is at the end of the output array
"""
# We can't directly transition into the >= or < states since we need to end
# up at the end of the output array.
FOUND_GREATER_THAN_OR_EQUAL_TO_STATE = '{}FoundGreaterThanOrEqualTo'.format(initial_state)
FOUND_LESS_THAN_STATE = '{}FoundLessThan'.format(initial_state)
def already_have_one_bit_state(bit_index, bit_value):
"""This means that we've read a 'bit_value' at 'bit_index'. We are
currently searching for the equivalent bit in the other number."""
return '{}BitIndex{}BitValue{}'.format(initial_state, bit_index, bit_value)
def about_to_read_first_bit_state(bit_index):
"""This means that we're about to start reading/comparing the next bit
index. We always immediately transition from this state to the
'already_have_one_bit_state' after reading its value."""
if bit_index == self._num_bits:
# At this point, we know that the numbers are equal since we've compared every bit.
return FOUND_GREATER_THAN_OR_EQUAL_TO_STATE
else:
return '{}BitIndex{}'.format(initial_state, bit_index)
def about_to_compare_bits_state(bit_index, bit_value):
"""Our cursor is over the other bit we want to compare this one too."""
return '{}BitIndex{}CompareWithBitValue{}'.format(initial_state, bit_index, bit_value)
# Begin by moving to the beginning of the 2nd number.
transitions = list(
self.move_n_bits(
initial_state=initial_state,
direction=BACKWARDS,
final_state=about_to_read_first_bit_state(bit_index=0),
num_bits=self._num_bits - 1,
)
)
direction = BACKWARDS
# Then begin comparing the digits one by one from largest to smallest
for bit_index in range(self._num_bits):
for bit_value in ['0', '1']:
transitions.append(
# Read the current bit
StateTransition(
previous_state=about_to_read_first_bit_state(bit_index),
previous_character=bit_value,
next_state=already_have_one_bit_state(bit_index, bit_value),
next_character=bit_value,
tape_pointer_direction=direction,
)
)
# Then go to the equivalent bit in the other number. We already
# moved 1 space in that direction.
transitions.extend(
self.move_n_bits(
initial_state=already_have_one_bit_state(bit_index, bit_value),
direction=direction,
final_state=about_to_compare_bits_state(bit_index, bit_value),
num_bits=self._num_bits - 1,
)
)
# We've already read the 2nd number and now we're comparing it to
# the first. Now finally do the comparison
transitions.append(
# If the numbers are equal
StateTransition(
previous_state=about_to_compare_bits_state(bit_index, bit_value),
previous_character=bit_value,
next_state=about_to_read_first_bit_state(bit_index + 1),
next_character=bit_value,
tape_pointer_direction=FORWARDS,
)
)
transitions.append(
# If the numbers are not equal
StateTransition(
previous_state=about_to_compare_bits_state(bit_index, bit_value),
previous_character=invert_bit(bit_value),
next_state=(
FOUND_GREATER_THAN_OR_EQUAL_TO_STATE
if (
(bit_value == '1' and direction == FORWARDS) or
(bit_value == '0' and direction == BACKWARDS)
)
else FOUND_LESS_THAN_STATE
),
next_character=invert_bit(bit_value),
tape_pointer_direction=invert_direction(direction),
)
)
direction = invert_direction(direction)
# After we've determined the answer, we need to move to the end of the output array
transitions.extend(
self.move_to_blank_spaces(
initial_state=FOUND_GREATER_THAN_OR_EQUAL_TO_STATE,
final_state=greater_than_or_equal_to_state,
final_character=BLANK_CHARACTER,
final_direction=BACKWARDS,
direction=FORWARDS,
num_blanks=1,
)
)
transitions.extend(
self.move_to_blank_spaces(
initial_state=FOUND_LESS_THAN_STATE,
final_state=less_than_state,
final_character=BLANK_CHARACTER,
final_direction=BACKWARDS,
direction=FORWARDS,
num_blanks=1,
)
)
return transitions
def erase_number(self, initial_state, final_state):
"""Erases the number under the cursor by replacing it with blanks.
Precondition: The cursor is at the end of that number
Postcondition: The cursor is right before the beginning of that number
"""
def state_name(bit_index):
if bit_index == 0:
return initial_state
elif bit_index == self._num_bits:
return final_state
else:
return '{}ErasingBit{}'.format(initial_state, bit_index)
transitions = []
for bit_index in range(self._num_bits):
for bit_value in ['0', '1']:
transitions.append(
StateTransition(
previous_state=state_name(bit_index),
previous_character=bit_value,
next_state=state_name(bit_index + 1),
next_character=BLANK_CHARACTER,
tape_pointer_direction=BACKWARDS,
)
)
return transitions
def replace_number(self, initial_state, final_state):
"""Replaces the 2nd to last number with the last number. So, [1, 5, 7] would become [1, 7].
Precondition: The cursor is at the end of the output array
Postcondition: The cursor is at the end of the output array
"""
def need_to_read_bit(bit_index):
if bit_index == 0:
return initial_state
elif bit_index == self._num_bits:
return final_state
else:
return '{}ReadingBitIndexToMove{}'.format(initial_state, bit_index)
def read_bit(bit_index, bit_value):
return '{}ReadingBitIndexToMove{}Bit{}'.format(initial_state, bit_index, bit_value)
def overwrite_bit(bit_index, bit_value):
return '{}OverwritingBitIndex{}Bit{}'.format(initial_state, bit_index, bit_value)
def move_back_to_end(bit_index):
return '{}ReplacingNumberMovingBackToEnd{}'.format(initial_state, bit_index)
transitions = []
for bit_index in range(self._num_bits):
for bit_value in ['0', '1']:
# Start by reading the bit under the cursor. Replace it with a blank.
transitions.append(
StateTransition(
previous_state=need_to_read_bit(bit_index),
previous_character=bit_value,
next_state=read_bit(bit_index, bit_value),
next_character=BLANK_CHARACTER,
tape_pointer_direction=BACKWARDS,
)
)
# Then go to the equivalent bit in the other number.
transitions.extend(
self.move_n_bits(
initial_state=read_bit(bit_index, bit_value),
direction=BACKWARDS,
final_state=overwrite_bit(bit_index, bit_value),
num_bits=self._num_bits - 1,
)
)
# Then overwrite the current bit with the stored bit
transitions.extend(
StateTransition(
previous_state=overwrite_bit(bit_index, bit_value),
previous_character=bit_value_we_are_reading,
next_state=move_back_to_end(bit_index),
next_character=bit_value,
tape_pointer_direction=FORWARDS,
)
for bit_value_we_are_reading in ['0', '1']
)
# Lastly move back to the end of the output array
transitions.extend(
self.move_to_blank_spaces(
initial_state=move_back_to_end(bit_index),
final_state=need_to_read_bit(bit_index + 1),
final_character=BLANK_CHARACTER,
final_direction=BACKWARDS,
direction=FORWARDS,
num_blanks=1,
)
)
return transitions
def check_if_there_is_any_input_left(self, initial_state, final_state):
"""
Precondition: We are at the end of the output array
Postcondition: We are at the beginning of the input array
If there is no more input left, this ends the program
"""
CHECK_IF_ANY_HOURS_LEFT = '{}CheckIfAnyHoursLeft'.format(initial_state)
# Then move back to the beginning of the input
transitions = self.move_to_blank_spaces(
initial_state=initial_state,
final_state=CHECK_IF_ANY_HOURS_LEFT,
final_character=BLANK_CHARACTER,
final_direction=FORWARDS,
direction=BACKWARDS,
num_blanks=2,
)
# If we moved back 2 blanks and still ended on a blank, then there is
# nothing left in the input because we hit 2 blanks in a row.
transitions.append(
StateTransition(
previous_state=CHECK_IF_ANY_HOURS_LEFT,
previous_character=BLANK_CHARACTER,
next_state=YES_FINAL_STATE,
next_character=BLANK_CHARACTER,
tape_pointer_direction=FORWARDS,
)
)
# If we did not find a blank, then we just chill where we are
transitions.extend(
StateTransition(
previous_state=CHECK_IF_ANY_HOURS_LEFT,
previous_character=bit_value,
next_state=final_state,
next_character=bit_value,
tape_pointer_direction=DO_NOT_MOVE,
)
for bit_value in ['0', '1']
)
return transitions
def invert_bit(bit_value):
if bit_value == '0':
return '1'
elif bit_value == '1':
return '0'
else:
raise AssertionError('Invalid bit {}'.format(bit_value))
def invert_direction(direction):
if direction == BACKWARDS:
return FORWARDS
elif direction == FORWARDS:
return BACKWARDS
else: # pragma: no cover
raise AssertionError('Invalid direction {}'.format(direction))
if __name__ == '__main__':
input_string = json.loads(sys.argv[1])
num_bits = int(sys.argv[2])
initial_tape = encode_intervals(input_string, num_bits)
gen = MergeOverlappingIntervalsGenerator(num_bits)
merge_overlapping_intervals = TuringMachine(gen.merge_overlapping_intervals_transitions(), debug=True)
merge_overlapping_intervals.run(initial_tape=initial_tape, max_steps=5000)
print(decode_intervals(''.join(merge_overlapping_intervals.tape), num_bits))
================================================
FILE: vim_turing_machine/machines/merge_overlapping_intervals/vim_merge_overlapping_intervals.py
================================================
import json
import sys
from vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_intervals
from vim_turing_machine.machines.merge_overlapping_intervals.merge_overlapping_intervals import MergeOverlappingIntervalsGenerator
from vim_turing_machine.vim_machine import VimTuringMachine
if __name__ == '__main__':
input_string = json.loads(sys.argv[1])
num_bits = int(sys.argv[2])
initial_tape = encode_intervals(input_string, num_bits)
gen = MergeOverlappingIntervalsGenerator(num_bits)
merge_overlapping_intervals = VimTuringMachine(gen.merge_overlapping_intervals_transitions(), debug=False)
merge_overlapping_intervals.run(initial_tape=initial_tape)
================================================
FILE: vim_turing_machine/machines/vim_is_number_even.py
================================================
import sys
from vim_turing_machine.machines.is_number_even import number_is_even_state_transitions
from vim_turing_machine.vim_machine import VimTuringMachine
if __name__ == '__main__':
initial_tape = sys.argv[1]
even_odd_turing_machine = VimTuringMachine(number_is_even_state_transitions, debug=False)
even_odd_turing_machine.run(initial_tape=initial_tape)
================================================
FILE: vim_turing_machine/struct.py
================================================
from collections import namedtuple
from vim_turing_machine.constants import BACKWARDS
from vim_turing_machine.constants import DO_NOT_MOVE
from vim_turing_machine.constants import FORWARDS
from vim_turing_machine.constants import INVALID_STATE_CHARACTERS
from vim_turing_machine.constants import VALID_CHARACTERS
class StateTransition(namedtuple('StateTransition', [
'previous_state',
'previous_character',
'next_state',
'next_character',
'tape_pointer_direction',
])):
def validate(self):
assert self.tape_pointer_direction in (FORWARDS, DO_NOT_MOVE, BACKWARDS)
assert self.previous_character in VALID_CHARACTERS
assert self.next_character in VALID_CHARACTERS
for invalid_char in INVALID_STATE_CHARACTERS:
if invalid_char in self.previous_state:
raise AssertionError('{} is in {}'.format(invalid_char, self.previous_state))
if invalid_char in self.next_state:
raise AssertionError('{} is in {}'.format(invalid_char, self.next_state))
================================================
FILE: vim_turing_machine/turing_machine.py
================================================
from collections import defaultdict
import colored
from vim_turing_machine.constants import BLANK_CHARACTER
from vim_turing_machine.constants import FINAL_STATES
from vim_turing_machine.constants import INITIAL_STATE
class NegativeTapePositionException(Exception):
pass
class MissingStateTransition(Exception):
pass
class DuplicateStateTransitionException(Exception):
pass
class TooManyStepsException(Exception):
pass
class TuringMachine(object):
def __init__(self, state_transitions, debug=False, quiet=False):
validate_state_transitions(state_transitions)
self._state_transitions = state_transitions
self._state_transition_mapping = {
(state.previous_state, state.previous_character): state
for state in state_transitions
}
self._debug = debug
self._quiet = quiet
self.initialize_machine(tape=[])
def initialize_machine(self, tape, initial_cursor_position=0):
if tape:
self.tape = list(tape)[:] # Copy the initial tape since we mutate it
else:
self.tape = [BLANK_CHARACTER]
self.cursor_position = initial_cursor_position
self.current_state = INITIAL_STATE
self._num_steps = 0
def get_state_transition(self):
try:
return self._state_transition_mapping[
(self.current_state, self.tape[self.cursor_position])
]
except KeyError:
raise MissingStateTransition(
(self.current_state, self.tape[self.cursor_position])
)
def step(self):
"""This implements an infinitely long tape in the right direction, but
will error if you go beyond position 0"""
transition = self.get_state_transition()
self.tape[self.cursor_position] = transition.next_character
self.cursor_position += transition.tape_pointer_direction
if self.cursor_position < 0:
raise NegativeTapePositionException
# Make sure we haven't run more than 1 past the end of the tape. This
# should never happen since we append to the tape over time.
assert self.cursor_position <= len(self.tape)
if self.cursor_position >= len(self.tape):
# Fake the infinite tape by adding a blank character under the
# cursor.
self.tape.append(BLANK_CHARACTER)
self.current_state = transition.next_state
if self.current_state in FINAL_STATES:
self.final_state()
elif self._debug:
self.print_tape()
def final_state(self):
if not self._quiet:
print('Program complete. Final state: {}'.format(self.current_state))
print(
'The program completed in {} steps using a machine with {} transitions'.format(
self._num_steps,
len(self._state_transitions)
)
)
self.print_tape()
raise StopIteration
def run(self, initial_tape, max_steps=None, initial_cursor_position=0):
self.initialize_machine(initial_tape, initial_cursor_position=initial_cursor_position)
if self._debug:
self.print_tape()
try:
while(True):
self.step()
self._num_steps += 1
if max_steps is not None and self._num_steps >= max_steps:
raise TooManyStepsException
except StopIteration:
pass
def print_tape(self):
tape = ''
for i, character in enumerate(self.tape):
if i == self.cursor_position:
tape += '{}{}{}{}'.format(colored.bg('red'), colored.fg('white'), character, colored.attr('reset'))
else:
tape += character
if i != len(self.tape) - 1:
tape += ' | '
print(tape)
print('State: {}'.format(self.current_state))
print() # Add empty line
def validate_state_transitions(state_transitions):
seen = defaultdict(list)
for transition in state_transitions:
transition.validate()
key = (transition.previous_state, transition.previous_character)
seen[key].append(transition)
for transitions in seen.values():
if len(transitions) > 1:
raise DuplicateStateTransitionException(transitions)
================================================
FILE: vim_turing_machine/vim_constants.py
================================================
VIM_MACHINE_FILENAME = 'machine.vim'
VIM_NEXT_STATE = '`ny$@"'
VIM_MOVE_TAPE_FORWARDS = '`tWmt'
VIM_MOVE_TAPE_BACKWARDS = '`tBmt'
VIM_RUN_REGISTER = '@"'
VIM_TAPE_WRAP_POSITION = 40
VIM_LOG_TAPE_AND_STATE = '`ly$@"'
def create_pointer(name, direction='j'):
"""Creates a mark to a particular place on the tape."""
return '`h/_{name}:\rn{direction}m{name}'.format(name=name, direction=direction)
VIM_POINTERS = ''.join([
create_pointer('t'),
create_pointer('l'),
create_pointer('k'),
create_pointer('o'),
create_pointer('p'),
create_pointer('s', direction=''),
create_pointer('n'),
create_pointer('e', direction='k'),
])
VIM_TEMPLATE = """0/_v1\rnf-ly$@"
### launch with ggyy@" ###
# Init pointers
_v1-gg0mh{pointers}`ny$@"
_o: # Output
_k: # Current state
{initial_state}
_t: # Current tape
{initial_tape}
notvalid\|--addlinetotape
_e: # End of tape. Pointer is 1 line above this
_n: # Next state transition. Usage: `ny$@"
{logging}`t"tyiW`ky$`s/_"-t\|---\rf:ly$@"
_p: # Print state. Usage: `py$@"
`ky$`op
_l: # Log the tape and state Usage: `ly$@"
`tyipGopdd`kyyGp
_s: # State transitions
{state_transitions}
# End State transitions
# Add an extra line to the end of the tape
_--addlinetotape: `eO{characters_per_line}i{blank_character} 0mt`ny$@"
# Print state when unknown transition
_---: `py$@"
# vim: set whichwrap+=b,s
"""
================================================
FILE: vim_turing_machine/vim_machine.py
================================================
from vim_turing_machine.constants import BACKWARDS
from vim_turing_machine.constants import BLANK_CHARACTER
from vim_turing_machine.constants import FORWARDS
from vim_turing_machine.turing_machine import TuringMachine
from vim_turing_machine.vim_constants import VIM_LOG_TAPE_AND_STATE
from vim_turing_machine.vim_constants import VIM_MACHINE_FILENAME
from vim_turing_machine.vim_constants import VIM_MOVE_TAPE_BACKWARDS
from vim_turing_machine.vim_constants import VIM_MOVE_TAPE_FORWARDS
from vim_turing_machine.vim_constants import VIM_NEXT_STATE
from vim_turing_machine.vim_constants import VIM_POINTERS
from vim_turing_machine.vim_constants import VIM_RUN_REGISTER
from vim_turing_machine.vim_constants import VIM_TAPE_WRAP_POSITION
from vim_turing_machine.vim_constants import VIM_TEMPLATE
def create_initial_tape(input_tape):
"""Generates the initial tape by padding the input and wrapping"""
padding_length = VIM_TAPE_WRAP_POSITION - len(input_tape) % VIM_TAPE_WRAP_POSITION
input_tape += padding_length * [BLANK_CHARACTER]
initial_tape = []
for index, value in enumerate(input_tape):
if index % VIM_TAPE_WRAP_POSITION == 0:
initial_tape.append([])
initial_tape[index // VIM_TAPE_WRAP_POSITION].append(value)
return '\n'.join(' '.join(row) for row in initial_tape)
class VimStateTransitionAdapter(object):
def __init__(self, state_transition):
self.st = state_transition
def to_vim(self):
"""Returns vim command mapping of this transition"""
return (
'_{}-{}:{}{}{}{}'
).format(
self.st.previous_state,
self.st.previous_character,
self._change_state_to(),
self._change_tape_to(),
self._move_pointer(),
VIM_NEXT_STATE,
)
def _change_state_to(self):
"""Returns the vim commands to change current state to next"""
return '`k"_C{}'.format(self.st.next_state)
def _change_tape_to(self):
"""Returns the vim commands to change current tape value to next"""
return '`t"_cw{}'.format(self.st.next_character)
def _move_pointer(self):
"""Returns the vim commands to move the tape after transition"""
if self.st.tape_pointer_direction == FORWARDS:
return VIM_MOVE_TAPE_FORWARDS
elif self.st.tape_pointer_direction == BACKWARDS:
return VIM_MOVE_TAPE_BACKWARDS
else:
return ''
class VimTuringMachine(TuringMachine):
def run(self, initial_tape, auto_step=True):
"""Generates vim machine in an output file"""
self.initialize_machine(initial_tape)
with open(VIM_MACHINE_FILENAME, 'w') as machine:
machine.write(VIM_TEMPLATE.format(
initial_state=self.current_state,
initial_tape=create_initial_tape(self.tape),
characters_per_line=VIM_TAPE_WRAP_POSITION,
pointers=VIM_POINTERS,
blank_character=BLANK_CHARACTER,
logging=(
VIM_LOG_TAPE_AND_STATE if auto_step and self._debug else ''
),
state_transitions='\n'.join(
VimStateTransitionAdapter(state_transition).to_vim()
for state_transition in self._state_transitions
),
).replace(VIM_RUN_REGISTER, VIM_RUN_REGISTER if auto_step else ''))
print('Machine written to {}'.format(VIM_MACHINE_FILENAME))
================================================
FILE: vimrc
================================================
set whichwrap+=b,s
set cursorline
set cursorcolumn
gitextract_mhyv690l/ ├── .coveragerc ├── .deactivate.sh ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── Makefile ├── README.md ├── decode_hours.sh ├── requirements-dev.txt ├── setup.cfg ├── setup.py ├── tests/ │ ├── __init__.py │ ├── machines/ │ │ ├── __init__.py │ │ ├── is_number_even_test.py │ │ └── merge_overlapping_intervals/ │ │ ├── __init__.py │ │ ├── decode_intervals_test.py │ │ ├── encode_intervals_test.py │ │ ├── merge_overlapping_intervals_test.py │ │ └── vim_merge_overlapping_intervals_test.py │ └── turing_machine_test.py ├── tox.ini ├── vim_turing_machine/ │ ├── __init__.py │ ├── constants.py │ ├── machines/ │ │ ├── __init__.py │ │ ├── is_number_even.py │ │ ├── merge_overlapping_intervals/ │ │ │ ├── __init__.py │ │ │ ├── decode_intervals.py │ │ │ ├── encode_intervals.py │ │ │ ├── merge_overlapping_intervals.py │ │ │ └── vim_merge_overlapping_intervals.py │ │ └── vim_is_number_even.py │ ├── struct.py │ ├── turing_machine.py │ ├── vim_constants.py │ └── vim_machine.py └── vimrc
SYMBOL INDEX (74 symbols across 13 files)
FILE: tests/machines/is_number_even_test.py
function assert_tape (line 10) | def assert_tape(machine, expected_tape):
function run_machine (line 15) | def run_machine(transitions, tape):
function test_is_number_even (line 31) | def test_is_number_even(tape, is_even):
FILE: tests/machines/merge_overlapping_intervals/decode_intervals_test.py
function test_encode_intervals (line 4) | def test_encode_intervals():
FILE: tests/machines/merge_overlapping_intervals/encode_intervals_test.py
function test_encode_in_x_bits (line 12) | def test_encode_in_x_bits(number, encoded):
function test_encode_intervals (line 16) | def test_encode_intervals():
FILE: tests/machines/merge_overlapping_intervals/merge_overlapping_intervals_test.py
function mock_blank_character (line 22) | def mock_blank_character():
function merger (line 48) | def merger():
function run_machine (line 52) | def run_machine(transitions, tape, initial_position=0, assert_tape_not_c...
function assert_cursor_at_end_of_output (line 62) | def assert_cursor_at_end_of_output(machine):
function assert_cursor_is_at_beginning_of_input (line 70) | def assert_cursor_is_at_beginning_of_input(machine):
function assert_tape (line 78) | def assert_tape(machine, expected_tape):
function test_invert_bit (line 83) | def test_invert_bit():
function test_invert_direction (line 90) | def test_invert_direction():
function test_move_n_bits (line 97) | def test_move_n_bits(merger):
function test_move_to_blank_spaces (line 112) | def test_move_to_blank_spaces(merger):
function test_copy_bits_to_end_of_output (line 129) | def test_copy_bits_to_end_of_output(merger):
function test_compare_two_sequential_numbers (line 148) | def test_compare_two_sequential_numbers(merger, tape, final_state):
function test_erase_number (line 164) | def test_erase_number(merger):
function test_replace_number (line 178) | def test_replace_number(merger):
function test_check_if_there_is_any_input_left (line 198) | def test_check_if_there_is_any_input_left(merger, tape, final_state):
function test_copy_closing_value_and_merge (line 218) | def test_copy_closing_value_and_merge(merger, initial_tape, final_tape):
function test_copy_closing_value_without_merging (line 232) | def test_copy_closing_value_without_merging(merger):
function test_merge_overlapping_intervals (line 268) | def test_merge_overlapping_intervals(merger, initial_intervals, final_in...
FILE: tests/machines/merge_overlapping_intervals/vim_merge_overlapping_intervals_test.py
function run_vim_machine (line 13) | def run_vim_machine(intervals):
function read_contents_of_tape (line 37) | def read_contents_of_tape():
function convert_tape_to_string (line 54) | def convert_tape_to_string(tape_lines):
function test_merge_intervals_in_vim (line 58) | def test_merge_intervals_in_vim():
FILE: tests/turing_machine_test.py
function test_invalid_state_transition (line 9) | def test_invalid_state_transition():
function test_valid_states (line 22) | def test_valid_states():
function test_duplicate_states (line 43) | def test_duplicate_states():
FILE: vim_turing_machine/machines/merge_overlapping_intervals/decode_intervals.py
function decode_intervals (line 11) | def decode_intervals(intervals, num_bits=BITS_PER_NUMBER):
FILE: vim_turing_machine/machines/merge_overlapping_intervals/encode_intervals.py
function encode_intervals (line 10) | def encode_intervals(intervals, num_bits=BITS_PER_NUMBER):
function encode_in_x_bits (line 19) | def encode_in_x_bits(number, num_bits):
FILE: vim_turing_machine/machines/merge_overlapping_intervals/merge_overlapping_intervals.py
class MergeOverlappingIntervalsGenerator (line 30) | class MergeOverlappingIntervalsGenerator(object):
method __init__ (line 31) | def __init__(self, num_bits=BITS_PER_NUMBER):
method merge_overlapping_intervals_transitions (line 34) | def merge_overlapping_intervals_transitions(self):
method copy_closing_value_without_merging (line 99) | def copy_closing_value_without_merging(self, initial_state, final_state):
method copy_closing_value_and_merge (line 132) | def copy_closing_value_and_merge(self, initial_state, final_state):
method noop_when_non_blank (line 203) | def noop_when_non_blank(self, state, direction):
method move_n_bits (line 221) | def move_n_bits(self, initial_state, direction, final_state, num_bits):
method move_to_blank_spaces (line 246) | def move_to_blank_spaces(
method copy_bits_to_end_of_output (line 311) | def copy_bits_to_end_of_output(self, initial_state, num_bits, final_st...
method compare_two_sequential_numbers (line 374) | def compare_two_sequential_numbers(self, initial_state, greater_than_o...
method erase_number (line 502) | def erase_number(self, initial_state, final_state):
method replace_number (line 532) | def replace_number(self, initial_state, final_state):
method check_if_there_is_any_input_left (line 605) | def check_if_there_is_any_input_left(self, initial_state, final_state):
function invert_bit (line 651) | def invert_bit(bit_value):
function invert_direction (line 660) | def invert_direction(direction):
FILE: vim_turing_machine/struct.py
class StateTransition (line 10) | class StateTransition(namedtuple('StateTransition', [
method validate (line 17) | def validate(self):
FILE: vim_turing_machine/turing_machine.py
class NegativeTapePositionException (line 10) | class NegativeTapePositionException(Exception):
class MissingStateTransition (line 14) | class MissingStateTransition(Exception):
class DuplicateStateTransitionException (line 18) | class DuplicateStateTransitionException(Exception):
class TooManyStepsException (line 22) | class TooManyStepsException(Exception):
class TuringMachine (line 26) | class TuringMachine(object):
method __init__ (line 28) | def __init__(self, state_transitions, debug=False, quiet=False):
method initialize_machine (line 40) | def initialize_machine(self, tape, initial_cursor_position=0):
method get_state_transition (line 50) | def get_state_transition(self):
method step (line 60) | def step(self):
method final_state (line 88) | def final_state(self):
method run (line 101) | def run(self, initial_tape, max_steps=None, initial_cursor_position=0):
method print_tape (line 117) | def print_tape(self):
function validate_state_transitions (line 133) | def validate_state_transitions(state_transitions):
FILE: vim_turing_machine/vim_constants.py
function create_pointer (line 16) | def create_pointer(name, direction='j'):
FILE: vim_turing_machine/vim_machine.py
function create_initial_tape (line 16) | def create_initial_tape(input_tape):
class VimStateTransitionAdapter (line 30) | class VimStateTransitionAdapter(object):
method __init__ (line 32) | def __init__(self, state_transition):
method to_vim (line 35) | def to_vim(self):
method _change_state_to (line 48) | def _change_state_to(self):
method _change_tape_to (line 52) | def _change_tape_to(self):
method _move_pointer (line 56) | def _move_pointer(self):
class VimTuringMachine (line 66) | class VimTuringMachine(TuringMachine):
method run (line 68) | def run(self, initial_tape, auto_step=True):
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (73K chars).
[
{
"path": ".coveragerc",
"chars": 539,
"preview": "[run]\nbranch = True\nsource =\n .\nomit =\n .tox/*\n /usr/*\n setup.py\n\n[report]\nshow_missing = True\nskip_covered "
},
{
"path": ".deactivate.sh",
"chars": 11,
"preview": "deactivate\n"
},
{
"path": ".gitignore",
"chars": 90,
"preview": "*.egg-info\n*.py[co]\n/.cache\n/.coverage\n/.tox\n/coverage-html\n/dist\n/venv\nmachine.vim\n*.swp\n"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1323,
"preview": "- repo: https://github.com/pre-commit/pre-commit-hooks\n sha: v0.9.2\n hooks:\n - id: trailing-whitespace\n "
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "Makefile",
"chars": 758,
"preview": ".PHONY: minimal\nminimal: venv\n\nvenv:\n\ttox -e venv\n\n.PHONY: install-hooks\ninstall-hooks: venv\n\tvenv/bin/pre-commit instal"
},
{
"path": "README.md",
"chars": 5887,
"preview": "Vim Turing Machine\n==================\n\nEver wish you could run your code in your editor? Tired of installing huge\ndepend"
},
{
"path": "decode_hours.sh",
"chars": 113,
"preview": "#! /bin/bash\nvenv/bin/python -m vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals \"$1\" $2\n"
},
{
"path": "requirements-dev.txt",
"chars": 40,
"preview": "coverage\nflake8\npre-commit>=0.15\npytest\n"
},
{
"path": "setup.cfg",
"chars": 25,
"preview": "[wheel]\nuniversal = True\n"
},
{
"path": "setup.py",
"chars": 359,
"preview": "from setuptools import find_packages\nfrom setuptools import setup\n\n\nsetup(\n name='vim-turing-machine',\n version='1"
},
{
"path": "tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/machines/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/machines/is_number_even_test.py",
"chars": 1061,
"preview": "import pytest\n\nfrom vim_turing_machine.constants import BLANK_CHARACTER\nfrom vim_turing_machine.constants import NO_FINA"
},
{
"path": "tests/machines/merge_overlapping_intervals/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/machines/merge_overlapping_intervals/decode_intervals_test.py",
"chars": 211,
"preview": "from vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals import decode_intervals\n\n\ndef test_encode_"
},
{
"path": "tests/machines/merge_overlapping_intervals/encode_intervals_test.py",
"chars": 547,
"preview": "import pytest\n\nfrom vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_in_x_bits\nfro"
},
{
"path": "tests/machines/merge_overlapping_intervals/merge_overlapping_intervals_test.py",
"chars": 8271,
"preview": "from unittest import mock\n\nimport pytest\n\nimport vim_turing_machine.machines.merge_overlapping_intervals.merge_overlappi"
},
{
"path": "tests/machines/merge_overlapping_intervals/vim_merge_overlapping_intervals_test.py",
"chars": 2048,
"preview": "import subprocess\n\nfrom vim_turing_machine.machines.merge_overlapping_intervals.decode_intervals import decode_intervals"
},
{
"path": "tests/turing_machine_test.py",
"chars": 1559,
"preview": "import pytest\n\nfrom vim_turing_machine.constants import FORWARDS\nfrom vim_turing_machine.struct import StateTransition\nf"
},
{
"path": "tox.ini",
"chars": 479,
"preview": "[tox]\nenvlist = py3\ntox_pip_extensions_ext_pip_custom_platform = true\ntox_pip_extensions_ext_venv_update = true\n\n[testen"
},
{
"path": "vim_turing_machine/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vim_turing_machine/constants.py",
"chars": 333,
"preview": "BLANK_CHARACTER = 'X'\nINITIAL_STATE = 'InitialState'\n\nYES_FINAL_STATE = 'YES'\nNO_FINAL_STATE = 'NO'\n\nBITS_PER_NUMBER = 5"
},
{
"path": "vim_turing_machine/machines/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vim_turing_machine/machines/is_number_even.py",
"chars": 2889,
"preview": "import sys\n\nfrom vim_turing_machine.constants import BLANK_CHARACTER\nfrom vim_turing_machine.constants import INITIAL_ST"
},
{
"path": "vim_turing_machine/machines/merge_overlapping_intervals/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vim_turing_machine/machines/merge_overlapping_intervals/decode_intervals.py",
"chars": 929,
"preview": "\"\"\"Decodes a binary string to a json representation of the intervals\nafter the merge overlapping intervals turing machin"
},
{
"path": "vim_turing_machine/machines/merge_overlapping_intervals/encode_intervals.py",
"chars": 787,
"preview": "\"\"\"Encodes a json representation of the intervals into the 5-bit binary\nrepresentation used by the merge overlapping int"
},
{
"path": "vim_turing_machine/machines/merge_overlapping_intervals/merge_overlapping_intervals.py",
"chars": 27146,
"preview": "\"\"\"Our tape is defined in multiple segments, each separated by a blank character.\n\nINPUT<Blank>OUTPUT\n\nThis program solv"
},
{
"path": "vim_turing_machine/machines/merge_overlapping_intervals/vim_merge_overlapping_intervals.py",
"chars": 712,
"preview": "import json\nimport sys\n\nfrom vim_turing_machine.machines.merge_overlapping_intervals.encode_intervals import encode_inte"
},
{
"path": "vim_turing_machine/machines/vim_is_number_even.py",
"chars": 373,
"preview": "import sys\n\nfrom vim_turing_machine.machines.is_number_even import number_is_even_state_transitions\nfrom vim_turing_mach"
},
{
"path": "vim_turing_machine/struct.py",
"chars": 1051,
"preview": "from collections import namedtuple\n\nfrom vim_turing_machine.constants import BACKWARDS\nfrom vim_turing_machine.constants"
},
{
"path": "vim_turing_machine/turing_machine.py",
"chars": 4423,
"preview": "from collections import defaultdict\n\nimport colored\n\nfrom vim_turing_machine.constants import BLANK_CHARACTER\nfrom vim_t"
},
{
"path": "vim_turing_machine/vim_constants.py",
"chars": 1404,
"preview": "VIM_MACHINE_FILENAME = 'machine.vim'\n\nVIM_NEXT_STATE = '`ny$@\"'\n\nVIM_MOVE_TAPE_FORWARDS = '`tWmt'\n\nVIM_MOVE_TAPE_BACKWAR"
},
{
"path": "vim_turing_machine/vim_machine.py",
"chars": 3513,
"preview": "from vim_turing_machine.constants import BACKWARDS\nfrom vim_turing_machine.constants import BLANK_CHARACTER\nfrom vim_tur"
},
{
"path": "vimrc",
"chars": 51,
"preview": "set whichwrap+=b,s\nset cursorline\nset cursorcolumn\n"
}
]
About this extraction
This page contains the full source code of the ealter/vim_turing_machine GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (66.4 KB), approximately 15.8k tokens, and a symbol index with 74 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.