commit 1889c660a6d39f7ff398bb190a44cc0045dcb06a Author: Maxim Slipenko <36362599+Maks1mS@users.noreply.github.com> Date: Wed Sep 15 22:39:37 2021 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5391d87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f2d90cb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.linting.enabled": true +} \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ae0ef1f --- /dev/null +++ b/setup.py @@ -0,0 +1,16 @@ +from setuptools import setup + +setup( + name='turinglab', + version='0.1.0', + author='Maxim Slipenko', + packages=['turinglab'], + install_requires = [ + 'python-docx' + ], + entry_points = { + 'console_scripts': [ + 'turinglab = turinglab.__main__:main' + ] + } +) \ No newline at end of file diff --git a/turinglab/__init__.py b/turinglab/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/turinglab/__main__.py b/turinglab/__main__.py new file mode 100644 index 0000000..e93533a --- /dev/null +++ b/turinglab/__main__.py @@ -0,0 +1,23 @@ +import sys +from turinglab.input import from_tur +from turinglab.emulator import Emulator +from turinglab.output import to_docx + + +def main(): + tur, input_string, docx = sys.argv[1:] + + [program,_,_] = from_tur(tur) + + tm = Emulator(program, input_string) + + data = [tm.info()] + + while not tm.stopped: + tm.step() + data.append(tm.info()) + + to_docx(docx, data) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/turinglab/emulator.py b/turinglab/emulator.py new file mode 100644 index 0000000..6808c3f --- /dev/null +++ b/turinglab/emulator.py @@ -0,0 +1,49 @@ +from collections import defaultdict + + +class Emulator(): + ''' + A class used to emulate an Turing machine + ''' + + def __init__(self, instructions, input_string: str = '', blank_symbol: chr = 'λ'): + self.head = 0 + self.current_state = 0 + + self.blank_symbol = blank_symbol + self.instructions = instructions + + self.stopped = False + + self.tape = defaultdict(lambda: self.blank_symbol, dict(enumerate(input_string))) + + def step(self): + if self.stopped == True: + raise RuntimeError('Turing machine is stopped!') + + symbol = self.tape[self.head] + + try: + symbol, direction, state = self.instructions[self.current_state][symbol] + self.tape[self.head] = symbol + + self.current_state = state + self.head += 1 if direction == '>' else -1 + + self.tape[self.head] = self.tape[self.head] + + if self.head < 0: + self.tape = defaultdict(lambda: self.blank_symbol, (sorted(self.tape.items()))) + + if self.current_state == -1: + self.stopped = True + + except: + self.stopped = True + + def info(self): + return [self.head, self.current_state, defaultdict(lambda: self.blank_symbol, self.tape)] + + + + diff --git a/turinglab/input.py b/turinglab/input.py new file mode 100644 index 0000000..3c01bcb --- /dev/null +++ b/turinglab/input.py @@ -0,0 +1,49 @@ +import csv +import pprint + +def from_tur(filename): + f = open(filename, "rb") + raw = [] + byte = f.read(1) + while byte: + raw.append(byte) + byte = f.read(1) + indx = [0] + empty = [b'\x00', b'\x00', b'\x00'] + for i in range(len(raw) - 2): + if raw[i:i+3] == empty: + indx.append(i) + indx.append(i+3) + + data = [] + for i in range(1, len(indx)): + packet = raw[indx[i - 1]:indx[i]] + if packet != empty: + data.append(packet) + + task = b''.join(data[1]).decode('cp1251') + description = b''.join(data[4]).decode('cp1251') + solution = b''.join(data[3][:-2]).decode('cp1251') + solution = list(csv.reader(solution.split('\r\n'), delimiter='\t')) + + header = solution[:1][0][1:] + + solution_dict = [dict() for x in range(len(header))] + + for x in solution[1:]: + symbol = x[0] if x[0] != ' ' else 'λ' + + for (i, action) in enumerate(x[1:]): + action = list(action) + if len(action) == 0: + continue + + if action[0] == '_': + action[0] = 'λ' + + action[2] = int(action[2]) - 1 + + + solution_dict[i][symbol] = action + + return solution_dict, task, description \ No newline at end of file diff --git a/turinglab/output.py b/turinglab/output.py new file mode 100644 index 0000000..1380a6b --- /dev/null +++ b/turinglab/output.py @@ -0,0 +1,45 @@ +from docx import Document +from docx.oxml import OxmlElement +from docx.oxml.ns import qn +from docx.shared import Pt +from docx.enum.text import WD_LINE_SPACING + +def to_docx(filename, data): + document = Document() + section = document.sections[0] + + sectPr = section._sectPr + cols = sectPr.xpath('./w:cols')[0] + cols.set(qn('w:num'),'2') + + style = document.styles['Normal'] + + font = style.font + font.name = 'Times New Roman' + font.size = Pt(14) + + for i in range(len(data)): + p = document.add_paragraph('K') + + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.line_spacing_rule = WD_LINE_SPACING.DOUBLE + + index_text = p.add_run(str(i)) + index_text.font.subscript = True + + p.add_run(': ') + + head, state, tape = data[i] + offset = list(tape.keys())[0] + head -= offset + tape_str = ''.join(tape.values()) + + p.add_run(tape_str[:head].lstrip('λ') + 'q') + + index_text = p.add_run(str('z' if state == -1 else state)) + index_text.font.subscript = True + + p.add_run(tape_str[head] + tape_str[head + 1:].rstrip('λ')) + + document.save(filename) \ No newline at end of file