turing_machine 0.0.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6270dca8cb1652af9e145537e52bb199d0cd7190
4
- data.tar.gz: 3f57b50ac59a9849fe4d59640d166aeaf8166446
3
+ metadata.gz: 6343fe9455c4501953afaaefc30d0705f348528a
4
+ data.tar.gz: 662f0eedd0069a630a6d3ac22a1cd3fa1a895b15
5
5
  SHA512:
6
- metadata.gz: 440063906e7969e16d560a98878e9ee2e3eb85916ffd06cb60cf438d6d4d7b836b6693da4e07d9edc607b509c2445d1104ae5b453d18a36f0c9ff527bbf56536
7
- data.tar.gz: fd2ee8011de8838ddb7ab259ae9b2ae2ed42d3664a2401202a4441e094cef67e4b5e974da29c651b334822db38cd2e0f043b045f86f86109149809fb72fdca23
6
+ metadata.gz: 40f2436cfdcc9da7fd82146e84fb81dbeb505914b6fa905b199cc091771b328cec3c8ed7d7b10cc2e43b8bc40d62f2c18ca4de10d2296678fa83191af83fdcc3
7
+ data.tar.gz: 3a67ca0e6a8bad420e241bc974979d627c2ccb45691be3a4af4d02d3a9c5f3c71e2b11d508452243289a2203c2d511c1f4afe529908bea2dbdac25a85d6ab798
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --format documentation
2
2
  --color
3
+ --order=random
data/README.md CHANGED
@@ -6,9 +6,7 @@ TuringMachine
6
6
 
7
7
  ![Photo of Alan Turing](alan-turing2.jpg)
8
8
 
9
- Currently, in version 0.0.2, you could just run the hardcoded 3 states busy beaver
10
- algorithm. There is nothing to tweak.
11
- I wish to be able to run any instruction sets in a very near future.
9
+ A Turing machine that can run (almost) (one day maybe) (I hope) any instruction set.
12
10
 
13
11
  ## Installation
14
12
 
@@ -18,11 +16,18 @@ Install it with:
18
16
 
19
17
  ## Usage
20
18
 
21
- $ turing_machine
19
+ Look at some well-known instruction sets in [instruction_sets](instruction_sets)
20
+ or create your own. Then run the Turing machine with, for example:
21
+
22
+ $ turing_machine instruction_sets/busy_beaver_1
23
+
24
+ Look at the
25
+ [InstructionsParser class](lib/turing_machine/instructions_parser.rb) for a
26
+ documentation of the instruction format.
22
27
 
23
28
  ## Contributing
24
29
 
25
- 1. Fork it ( https://github.com/[my-github-username]/turing_machine/fork )
30
+ 1. Fork it ( https://github.com/lkdjiin/turing_machine/fork )
26
31
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
32
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
33
  4. Push to the branch (`git push origin my-new-feature`)
data/bin/turing_machine CHANGED
@@ -4,19 +4,26 @@ require 'turing_machine'
4
4
 
5
5
  include TuringMachine
6
6
 
7
- instructions = {
8
- ['0', 'A'] => {write: '1', move: 'R', next_state: 'B'},
9
- ['1', 'A'] => {write: '1', move: 'L', next_state: 'C'},
10
- ['0', 'B'] => {write: '1', move: 'L', next_state: 'A'},
11
- ['1', 'B'] => {write: '1', move: 'R', next_state: 'B'},
12
- ['0', 'C'] => {write: '1', move: 'L', next_state: 'B'},
13
- ['1', 'C'] => {write: '1', move: 'R', next_state: 'HALT'},
14
- }
7
+ if ARGV[0].nil?
8
+ exit(1)
9
+ else
10
+ filename = ARGV[0]
11
+ end
12
+
13
+ if File.exist?(filename)
14
+ raw_instructions = IO.read(filename)
15
+ else
16
+ exit(2)
17
+ end
18
+
19
+ parser = InstructionsParser.new(raw_instructions)
20
+ instructions = parser.parse
15
21
 
16
22
  initial_state = 'A'
17
23
 
18
24
  instance = Instance.new(instructions, initial_state)
19
25
 
26
+ # This should be testable.
20
27
  loop do
21
28
  puts instance.to_s
22
29
  break if instance.halted?
@@ -0,0 +1,9 @@
1
+ Examples of instruction sets for the Turing machine
2
+ ===================================================
3
+
4
+ - `busy_beaver_1` : Busy beaver one state
5
+ - `busy_beaver_2` : Busy beaver two states
6
+ - `busy_beaver_3` : Busy beaver three states
7
+ - `busy_beaver_3-2` : Another busy beaver three states
8
+ - `busy_beaver_4` : Busy beaver four states
9
+ - `write101` : Write the number 101
@@ -0,0 +1 @@
1
+ 0 A => 1 R HALT
@@ -0,0 +1,4 @@
1
+ 0 A => 1 R B
2
+ 1 A => 1 L B
3
+ 0 B => 1 L A
4
+ 1 B => 1 R HALT
@@ -0,0 +1,6 @@
1
+ 0 A => 1 R B
2
+ 1 A => 1 L C
3
+ 0 B => 1 L A
4
+ 1 B => 1 R B
5
+ 0 C => 1 L B
6
+ 1 C => 1 R HALT
@@ -0,0 +1,6 @@
1
+ 0 A => 1 R B
2
+ 1 A => 1 R HALT
3
+ 0 B => 1 L B
4
+ 1 B => 0 R C
5
+ 0 C => 1 L C
6
+ 1 C => 1 L A
@@ -0,0 +1,8 @@
1
+ 0 A => 1 R B
2
+ 1 A => 1 L B
3
+ 0 B => 1 L A
4
+ 1 B => 0 L C
5
+ 0 C => 1 R HALT
6
+ 1 C => 1 L D
7
+ 0 D => 1 R D
8
+ 1 D => 0 R A
@@ -0,0 +1,13 @@
1
+ 0 A => 1 L B
2
+ 0 B => 1 L C
3
+ 0 C => 1 N s1
4
+ 0 s1 => N N HALT
5
+ 1 s1 => 0 R s2
6
+ 0 s2 => 0 R s3
7
+ 1 s2 => 1 R s2
8
+ 0 s3 => 1 L s4
9
+ 1 s3 => 1 R s3
10
+ 0 s4 => 0 L s5
11
+ 1 s4 => 1 L s4
12
+ 0 s5 => 1 R s1
13
+ 1 s5 => 1 L s5
@@ -0,0 +1,3 @@
1
+ 0 A => 1 R B
2
+ 0 B => 0 R C
3
+ 0 C => 1 R HALT
@@ -4,7 +4,7 @@ module TuringMachine
4
4
  class Instance
5
5
 
6
6
  def initialize(instructions, initial_state)
7
- @instruction = Instruction.new(instructions)
7
+ @instructions = Instructions.new(instructions)
8
8
  @state = StateRegister.new(initial_state)
9
9
  @tape = Tape.new
10
10
  @sequence = 1
@@ -33,8 +33,9 @@ module TuringMachine
33
33
  end
34
34
 
35
35
  def update_tape(current_action)
36
- @tape.head = current_action[:write]
37
- current_action[:move] == 'L' ? @tape.shift_left : @tape.shift_right
36
+ @tape.head = current_action[:write] unless current_action[:write] == 'N'
37
+ @tape.shift_left if current_action[:move] == 'L'
38
+ @tape.shift_right if current_action[:move] == 'R'
38
39
  end
39
40
 
40
41
  def update_state(current_action)
@@ -42,7 +43,7 @@ module TuringMachine
42
43
  end
43
44
 
44
45
  def action
45
- @instruction.for(@tape.head, @state.current)
46
+ @instructions.get(@tape.head, @state.current)
46
47
  end
47
48
 
48
49
  def instr_to_s
@@ -1,13 +1,13 @@
1
1
  module TuringMachine
2
2
 
3
3
  # Public: The instruction table of a Turing machine.
4
- class Instruction
4
+ class Instructions
5
5
 
6
6
  def initialize(table)
7
7
  @table = table
8
8
  end
9
9
 
10
- def for(symbol, state)
10
+ def get(symbol, state)
11
11
  @table[[symbol, state]]
12
12
  end
13
13
 
@@ -0,0 +1,55 @@
1
+ module TuringMachine
2
+
3
+ # Public: Parser for a newline separated instruction set.
4
+ #
5
+ # Instruction format
6
+ # ------------------
7
+ #
8
+ # Here is an example file with four instructions :
9
+ #
10
+ # ```
11
+ # 0 A => 1 R B
12
+ # 1 A => 1 L B
13
+ # 0 B => 1 L A
14
+ # 1 B => 1 R HALT
15
+ # ```
16
+ #
17
+ # So each instruction is :
18
+ #
19
+ # ```
20
+ # scanned-symbol current-state => symbol-to-write move next-state
21
+ # ```
22
+ #
23
+ # `symbol-to-write` is usually `1` or `0`. Note that `N` is a special
24
+ # symbol meaning «write nothing».
25
+ #
26
+ # `move` could be either `L` for left, `R` for right, or `N` for no
27
+ # movement.
28
+ class InstructionsParser
29
+
30
+ def initialize(raw_instructions)
31
+ @lines = raw_instructions.split("\n")
32
+ @instructions = {}
33
+ end
34
+
35
+ def parse
36
+ build_instructions
37
+ @instructions
38
+ end
39
+
40
+ private
41
+
42
+ def build_instructions
43
+ @lines.each do |instruction|
44
+ keys, value = instruction.split('=>')
45
+ key_symbol, key_state = keys.split
46
+ write, move, next_state = value.split
47
+ @instructions[[key_symbol, key_state]] = {
48
+ write: write, move: move, next_state: next_state
49
+ }
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -6,8 +6,8 @@ module TuringMachine
6
6
  def initialize
7
7
  # @symbols = [ '0' ]
8
8
  # @index = 0
9
- @symbols = Array.new(10) { '0' }
10
- @index = 4
9
+ @symbols = Array.new(40) { '0' }
10
+ @index = 19
11
11
  end
12
12
 
13
13
  attr_reader :index
@@ -1,3 +1,3 @@
1
1
  module TuringMachine
2
- VERSION = "0.0.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,7 +1,8 @@
1
1
  require "turing_machine/version"
2
2
  require 'turing_machine/tape'
3
3
  require 'turing_machine/state_register'
4
- require 'turing_machine/instruction'
4
+ require 'turing_machine/instructions'
5
+ require 'turing_machine/instructions_parser'
5
6
  require 'turing_machine/instance'
6
7
 
7
8
  module TuringMachine
@@ -16,19 +16,46 @@ initial_state = 'A'
16
16
  describe Instance do
17
17
  it 'produces an output' do
18
18
  instance = Instance.new(instructions, initial_state)
19
- expected = " 1 0000000000 A -> 1RB\n" +
20
- " ^"
19
+ expected = " 1 0000000000000000000000000000000000000000 A -> 1RB\n" +
20
+ " ^"
21
21
  expect(instance.to_s).to eq expected
22
22
  end
23
23
 
24
24
  it 'computes a step' do
25
25
  instance = Instance.new(instructions, initial_state)
26
26
  instance.proceed
27
- expected = " 2 0000100000 B -> 1LA\n" +
28
- " ^"
27
+ expected = " 2 0000000000000000000100000000000000000000 B -> 1LA\n" +
28
+ " ^"
29
29
  expect(instance.to_s).to eq expected
30
30
  end
31
31
 
32
+ describe 'null movement' do
33
+ it 'does not move the head' do
34
+ instructions = {
35
+ ['0', 'A'] => {write: '1', move: 'N', next_state: 'HALT'}
36
+ }
37
+ instance = Instance.new(instructions, initial_state)
38
+ instance.proceed
39
+ expected = " 2 0000000000000000000100000000000000000000 HALT\n" +
40
+ " ^"
41
+ expect(instance.to_s).to eq expected
42
+ end
43
+ end
44
+
45
+ describe 'null write' do
46
+ it 'does not write the current cell' do
47
+ instructions = {
48
+ ['0', 'A'] => {write: 'N', move: 'N', next_state: 'HALT'}
49
+ }
50
+ instance = Instance.new(instructions, initial_state)
51
+ instance.proceed
52
+ expected = " 2 0000000000000000000000000000000000000000 HALT\n" +
53
+ " ^"
54
+ expect(instance.to_s).to eq expected
55
+
56
+ end
57
+ end
58
+
32
59
  context 'when halted' do
33
60
 
34
61
  it 'tells if the machine is halted' do
@@ -47,8 +74,8 @@ describe Instance do
47
74
  }
48
75
  instance = Instance.new(instructions, initial_state)
49
76
  instance.proceed
50
- expected = " 2 0000100000 HALT\n" +
51
- " ^"
77
+ expected = " 2 0000000000000000000100000000000000000000 HALT\n" +
78
+ " ^"
52
79
  expect(instance.to_s).to eq expected
53
80
  end
54
81
 
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ include TuringMachine
4
+
5
+ describe InstructionsParser do
6
+
7
+ let(:busy_beaver_1) { "0 A => 1 R HALT" }
8
+
9
+ let(:busy_beaver_2) do
10
+ "0 A => 1 R B\n1 A => 1 L B\n0 B => 1 L A\n1 B => 1 R HALT"
11
+ end
12
+
13
+ describe '#parse' do
14
+ it 'returns Instruction' do
15
+ parser = InstructionsParser.new(busy_beaver_1)
16
+ value = parser.parse
17
+ expect(value).to be_a Hash
18
+ end
19
+ end
20
+
21
+ context 'when parsing busy beaver 1 state' do
22
+ it 'parses the single instruction' do
23
+ parser = InstructionsParser.new(busy_beaver_1)
24
+ value = parser.parse
25
+ expected = {write: '1', move: 'R', next_state: 'HALT'}
26
+ expect(value[['0', 'A']]).to eq expected
27
+ end
28
+ end
29
+
30
+ context 'when parsing busy beaver 2 states' do
31
+ it 'parses all four instructions' do
32
+ parser = InstructionsParser.new(busy_beaver_2)
33
+ value = parser.parse
34
+ expected = {write: '1', move: 'R', next_state: 'HALT'}
35
+ expect(value[['1', 'B']]).to eq expected
36
+ end
37
+ end
38
+
39
+ end
@@ -2,17 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  include TuringMachine
4
4
 
5
- describe Instruction do
5
+ describe Instructions do
6
6
 
7
- let(:instruction) do
8
- Instruction.new({
7
+ let(:instructions) do
8
+ Instructions.new({
9
9
  ['0', 'A'] => {write: '1', move: 'R', next_state: 'B'},
10
10
  ['1', 'A'] => {write: '1', move: 'L', next_state: 'C'},
11
11
  })
12
12
  end
13
13
 
14
14
  it 'finds actions' do
15
- hash = instruction.for('0', 'A')
15
+ hash = instructions.get('0', 'A')
16
16
  expect(hash[:write]).to eq '1'
17
17
  expect(hash[:move]).to eq 'R'
18
18
  expect(hash[:next_state]).to eq 'B'
data/spec/tape_spec.rb CHANGED
@@ -44,7 +44,7 @@ describe Tape do
44
44
  end
45
45
 
46
46
  it 'has a string representation' do
47
- expect("#{tape}").to eq '0000000000'
47
+ expect("#{tape}").to eq '0' * 40
48
48
  end
49
49
 
50
50
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = TuringMachine::VERSION
9
9
  spec.authors = ["Xavier Nayrac"]
10
10
  spec.email = ["xavier.nayrac@gmail.com"]
11
- spec.summary = %q{Turing machine}
12
- spec.description = %q{Turing machine}
11
+ spec.summary = %q{A Turing machine}
12
+ spec.description = %q{A Turing machine that can run your instruction set}
13
13
  spec.homepage = "http://lkdjiin.github.com/turing_machine/"
14
14
  spec.license = "MIT"
15
15
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turing_machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xavier Nayrac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-01 00:00:00.000000000 Z
11
+ date: 2015-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.12'
97
- description: Turing machine
97
+ description: A Turing machine that can run your instruction set
98
98
  email:
99
99
  - xavier.nayrac@gmail.com
100
100
  executables:
@@ -112,14 +112,24 @@ files:
112
112
  - Rakefile
113
113
  - alan-turing2.jpg
114
114
  - bin/turing_machine
115
+ - instruction_sets/README.md
116
+ - instruction_sets/busy_beaver_1
117
+ - instruction_sets/busy_beaver_2
118
+ - instruction_sets/busy_beaver_3
119
+ - instruction_sets/busy_beaver_3-2
120
+ - instruction_sets/busy_beaver_4
121
+ - instruction_sets/copy_with_data
122
+ - instruction_sets/write101
115
123
  - lib/turing_machine.rb
116
124
  - lib/turing_machine/instance.rb
117
- - lib/turing_machine/instruction.rb
125
+ - lib/turing_machine/instructions.rb
126
+ - lib/turing_machine/instructions_parser.rb
118
127
  - lib/turing_machine/state_register.rb
119
128
  - lib/turing_machine/tape.rb
120
129
  - lib/turing_machine/version.rb
121
130
  - spec/instance_spec.rb
122
- - spec/instruction_spec.rb
131
+ - spec/instructions_parser_spec.rb
132
+ - spec/instructions_spec.rb
123
133
  - spec/spec_helper.rb
124
134
  - spec/state_register_spec.rb
125
135
  - spec/tape_spec.rb
@@ -148,10 +158,11 @@ rubyforge_project:
148
158
  rubygems_version: 2.4.5
149
159
  signing_key:
150
160
  specification_version: 4
151
- summary: Turing machine
161
+ summary: A Turing machine
152
162
  test_files:
153
163
  - spec/instance_spec.rb
154
- - spec/instruction_spec.rb
164
+ - spec/instructions_parser_spec.rb
165
+ - spec/instructions_spec.rb
155
166
  - spec/spec_helper.rb
156
167
  - spec/state_register_spec.rb
157
168
  - spec/tape_spec.rb