├── .eslintrc.yaml ├── .gitignore ├── .tern-project ├── CNAME ├── LICENSE ├── README.md ├── index.html ├── package.json ├── src ├── DocumentMenu.js ├── TMDocument.js ├── TMDocumentController.js ├── TMSimulator.js ├── TMViz.js ├── TuringMachine.js ├── examples.js ├── examples │ ├── _template.yaml │ ├── binaryAdd.yaml │ ├── binaryIncrement.yaml │ ├── binaryMult.yaml │ ├── busyBeaver3.yaml │ ├── busyBeaver4.yaml │ ├── copy1s.yaml │ ├── divisibleBy3.yaml │ ├── divisibleBy3Base10.yaml │ ├── lengthMult.yaml │ ├── matchBinaryStrings.yaml │ ├── matchThreeLengths.yaml │ ├── palindrome.yaml │ ├── powersOfTwo.yaml │ ├── repeat01.yaml │ └── unaryMult.yaml ├── kbdshortcuts.js ├── main.js ├── parser.js ├── sharing │ ├── CheckboxTable.js │ ├── FileReaderPromise.js │ ├── export-panel.js │ ├── format.js │ ├── gist.js │ ├── import-panel.js │ └── import.js ├── state-diagram │ ├── StateGraph.js │ ├── StateViz.css │ └── StateViz.js ├── storage.js ├── tape │ ├── Tape.js │ ├── TapeViz.js │ └── tape.css ├── util.js └── watch.js ├── update-gh-pages.sh └── webpack.config.js /.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rules: 3 | ## Stylistic ## 4 | indent: 5 | - 1 6 | - 2 7 | - SwitchCase: 1 8 | VariableDeclarator: 9 | var: 2 10 | quotes: 11 | - 1 12 | - single 13 | linebreak-style: 14 | - 2 15 | - unix 16 | semi: 17 | - 1 18 | - always 19 | space-before-function-paren: 20 | - 1 21 | - anonymous: always 22 | named: never 23 | consistent-this: 24 | - 1 25 | - self 26 | ## Semantic ## 27 | no-invalid-this: 2 # prevent gotcha: closures inside methods don't inherit 'this' 28 | no-shadow: 29 | - 2 30 | - builtinGlobals: true 31 | no-shadow-restricted-names: 2 32 | no-unexpected-multiline: 2 33 | strict: 34 | - 2 35 | - global 36 | env: 37 | commonjs: true 38 | extends: eslint:recommended 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules/ 3 | .eslintcache 4 | 5 | 6 | /build/ 7 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "libs": [ 3 | "browser", 4 | "jquery" 5 | ], 6 | "loadEagerly": [ 7 | "src/*.js" 8 | ], 9 | "dontLoad": [ 10 | "node_modules/" 11 | ], 12 | "plugins": { 13 | "doc_comment": { 14 | "fullDocs": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | turingmachine.io 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright 2015-2021, Andy Li 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [turingmachine.io](http://turingmachine.io) 2 | 3 | This is a [Turing machine] visualizer designed for learning through visual thinking and creative exploration. 4 | 5 | Machines are described in a simple YAML-based format. 6 | As you code, each save updates the state diagram; this offers the speed and directness of code, combined with the visual intuitiveness of a graphical editor. 7 | 8 | Multiple example machines are provided, each one with commentary that touches on concepts like subroutines and inductive definitions / recursion. 9 | Many examples include exercises that build on the machines and deepen understanding. 10 | To encourage experimentation, the document system provides for quick snapshots and autosaving to browser local storage. 11 | 12 | All in all, this is the simulator I wish I had when taking automata theory. 13 | At the same time, I’ve tried to make it accessible to people who aren’t in computer science, or haven’t heard of a Turing machine before. 14 | 15 | Feel free to email me if you have any questions, comments, or feedback in general about the project. 16 | Bug reports and feature requests are also welcome on the [issue tracker]. 17 | Some known issues and ideas for improvement are outlined on the [wiki]. 18 | 19 | [Turing machine]: http://plato.stanford.edu/entries/turing-machine 20 | 21 | [issue tracker]: https://github.com/aepsilon/turing-machine-viz/issues 22 | [wiki]: https://github.com/aepsilon/turing-machine-viz/wiki 23 | 24 | 25 | ## Development Setup 26 | 27 | If you want to work on the site itself, here’s how to get started: 28 | 29 | Clone the repo and run `npm install` in the folder. Afterwards, use `npm start` to host the site locally on a [webpack server], by default at localhost:8080. 30 | 31 | `npm run depgraph` or `depgraph-noext` (requires [madge] and [Graphviz]) produces 32 | a visual dependency graph that’s good for getting a feel for the code layout. 33 | 34 | [webpack server]: https://webpack.github.io/docs/webpack-dev-server.html 35 | [madge]: https://github.com/pahen/madge 36 | [Graphviz]: http://www.graphviz.org/ 37 | 38 | 39 | ## Dependencies 40 | 41 | Thanks go to the authors of the following runtime dependencies: 42 | 43 | * [Ace] code editor 44 | * [bluebird.js] cancellable promises 45 | * [Bootstrap] with the [lumen] theme 46 | * [clipboard.js] one-click copy to clipboard 47 | * [D3] visualization and DOM manipulation library 48 | * [jQuery] 49 | * [js-yaml] parser & serializer 50 | * [lodash] and [lodash/fp] utilities 51 | 52 | [Ace]: https://ace.c9.io/ 53 | [bluebird.js]: http://bluebirdjs.com/ 54 | [Bootstrap]: https://getbootstrap.com/ 55 | [clipboard.js]: https://clipboardjs.com/ 56 | [D3]: https://d3js.org/ 57 | [jQuery]: https://jquery.com 58 | [js-yaml]: https://github.com/nodeca/js-yaml 59 | [lodash]: https://github.com/lodash/lodash 60 | [lodash/fp]: https://github.com/lodash/lodash/wiki/FP-Guide 61 | [lumen]: https://bootswatch.com/lumen/ 62 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 |529 | Run the machine to see it in action. 530 | At any time, you can step or pause to get a closer look, 531 | or reset to start over. 532 |
533 |There are over a dozen different example machines to explore.
534 |535 | Most of the examples take input. Experiment with different inputs to see what happens! 536 | Edit the code and click Load machine to sync your changes. 537 |
538 |The colored circles are states. The squares underneath are tape cells.
541 |The current state and tape cell are highlighted.
542 |At each step, a Turing machine reads its current state and tape symbol, 543 | and looks them up in its transition table for an instruction. 544 | Each instruction does 3 things:
545 |That’s it!
551 |This repeats step after step, until the machine reaches a combination of state and symbol 552 | that don’t have an instruction defined. At that point it halts. 553 |
554 |A Turing machine is an abstract device to model computation as rote symbol manipulation.
571 |Each machine has a finite number of states, and a finite number of possible symbols. 572 | These are fixed before the machine starts, and do not change as the machine runs.
573 |There are an infinite number of tape cells, however, extending endlessly to the left and right. 574 | Each tape cell bears a symbol. Any cell not part of the input or not yet written to bears the blank symbol by default. 575 | Notice that at any step, only finitely many cells bear a non-blank symbol.
576 |(As a mathematical model, a Turing machine has infinite memory (an infinite tape) so as to not artificially restrict its power. 577 | In practice, many machines of interest take finite memory, and can be fully simulated for manageable input sizes. 578 | Even machines that use infinite memory—and hence never halt—use at most one new tape cell per step, and so can be simulated to an extent.)
579 |The formal definition of a Turing machine has slight variations but essentially is a tuple (ordered list) comprising
593 |where Q, Σ, and Γ are finite nonempty sets. 602 | Some definitions also require that the blank symbol not be part of the input (b ∉ Σ).
603 | 604 |As an example, a formal description for the “binary increment” machine is as follows:
605 |
606 | Q = { right, carry, done }
607 |
q₀ = right
608 |
Σ = { 1, 0 }
609 |
Γ = { 1, 0, ' ' }
610 |
b = ' '
611 |
613 | δ(right, 1) = (1, R, right)
614 |
δ(right, 0) = (0, R, right)
615 |
δ(right, ' ') = (' ', L, carry)
616 |
δ(carry, 1) = (0, L, carry)
617 |
δ(carry, 0) = (1, L, done)
618 |
δ(carry, ' ') = (1, L, done)
619 |
Note that for simplicity, the simulator limits each symbol to one character. 621 | Furthermore, input is not checked for conformance with an input alphabet, in exchange for not having to define input and tape alphabets.
622 |(The behavior of a Turing machine can also be described in mathematical terms if desired. 623 | Without going into too much detail, this involves defining how a configuration 624 | of a machine—its state, tape contents, and tape head position (current cell)—leads to the next configuration, based on the transition function. 625 | To start with, the tape’s contents may be defined as a function from integers to symbols, 626 | with the head position as an integer, and each move {L, R} adding -1 or +1 respectively to the head position.)
627 |Some aspects of the definition vary from author to author, but the differences come down to preference and do not affect computational power. 641 | That is, machines on one model can be simulated or converted to run on another model.
642 |Some of the variations you may come across:
643 |The simulator was designed with these and other considerations in mind.
653 |670 | For a very readable introduction to Turing machines, including their significance and interesting implications, 671 | see the excellent entry in the Stanford Encyclopedia of Philosophy. 672 |
673 |Make spinoffs from the examples or your own creations by using 680 | Edit > Duplicate document. 681 | You can also start from scratch with a new blank document.
682 |All it takes to describe a Turing machine is a start state, blank symbol, and transition table.
683 |685 | # Adds 1 to a binary number. 686 | input: '1011' 687 | blank: ' ' 688 | start state: right 689 | table: 690 | # scan to the rightmost digit 691 | right: 692 | 1: R 693 | 0: R 694 | ' ': {L: carry} 695 | # then carry the 1 696 | carry: 697 | 1: {write: 0, L} 698 | 0: {write: 1, L: done} 699 | ' ': {write: 1, L: done} 700 | done: 701 |702 |
703 | Here the states are right
, carry
, and done
.
704 | The symbols are '1
', '0
', and '
'.
705 |
707 | We designate one state the start state, 708 | and one symbol the blank symbol (found on unmarked tape cells). 709 |
710 |
711 | A state and a symbol together map to an instruction.
712 | In the carry
state, for instance, the symbol 1
maps to the instruction {write: 0, L}
.
713 | When no instruction is defined, as in the done
state, the machine halts.
714 |
{write: symbol, move: state}718 |
{write: 1, L: done}
writes the symbol 1
,
720 | moves the tape head left (L
), and goes to the done
state.
721 | For brevity, you can omit the symbol and state if they stay the same.
724 |{L: carry}
writes the same symbol that was read,
726 | moves the tape head left, and goes to the carry
state.R
(shorthand for {R}) simply moves the tape head right.
728 | It writes back the same symbol and stays in the same state.More keyboard shortcuts are available on the full list.
745 |The code is written in YAML 1.2, a general-purpose data format.
761 |
762 | If you’re familiar with JSON, YAML is similar, but designed to be more readable.
763 | Mappings can use indent instead of brackets {}
, and strings can often be included directly without quotes.
764 |
766 | Some strings need to be quoted: for example, those that start/end with a space, or include certain characters that have special meaning in YAML. 767 | If a string is causing problems, try putting quotes around it. 768 |
769 |