yatm 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 +7 -0
- data/lib/yatm/error.rb +11 -0
- data/lib/yatm/machine/machine.rb +80 -0
- data/lib/yatm/state_machine/state_machine.rb +73 -0
- data/lib/yatm/tape/tape.rb +92 -0
- data/lib/yatm/version.rb +5 -0
- data/lib/yatm.rb +14 -0
- metadata +57 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: be3ead1b208b860b2ef2021496657196eff8a1bc42fc25c569cf77d3be6f37ff
|
|
4
|
+
data.tar.gz: a502d0f27f32c4a8686f5edca9aaf6e53f842a524b3e6cd26f34140528966bc5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8f63ffe798d7500425b9d2de058fbc4704584b5a9b3fbc20ac440677df16b5b1a1d1fb512cc5c3efcf5e97fb5c89d974c5cf15560cf8fad22bf54e511bdd9602
|
|
7
|
+
data.tar.gz: fa8a1cfef51c8cc0673a17c461e53319ab3d953e7cc8b85803e6136a3f010665c27992d7ae26f83f0bcfa162369691e9778414d88e9391ef31f88b1212bb8e5d
|
data/lib/yatm/error.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class YATM::Machine
|
|
4
|
+
attr_reader :tape, :state_machine, :history
|
|
5
|
+
|
|
6
|
+
def initialize(position: 0, content: [nil])
|
|
7
|
+
@tape = YATM::Tape.new(content, position: position)
|
|
8
|
+
@state_machine = YATM::StateMachine.new
|
|
9
|
+
@history = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initial_state(...); @state_machine.initial_state(...); end
|
|
13
|
+
|
|
14
|
+
def final_state(...); @state_machine.final_state(...); end
|
|
15
|
+
|
|
16
|
+
def states(...); @state_machine.states(...); end
|
|
17
|
+
|
|
18
|
+
def events(...); @state_machine.events(...); end
|
|
19
|
+
|
|
20
|
+
def event(...); @state_machine.event(...); end
|
|
21
|
+
|
|
22
|
+
def reset(...)
|
|
23
|
+
@history = []
|
|
24
|
+
@tape.reset(...)
|
|
25
|
+
@state_machine.reset
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_h
|
|
29
|
+
{
|
|
30
|
+
state: @state_machine.current_state,
|
|
31
|
+
final: @state_machine.final_states.include?(@state_machine.current_state),
|
|
32
|
+
position: @tape.pos
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_s; to_h.to_s; end
|
|
37
|
+
|
|
38
|
+
def to_txt
|
|
39
|
+
<<~TO_S
|
|
40
|
+
,_______________
|
|
41
|
+
| State Machine
|
|
42
|
+
`---------------
|
|
43
|
+
#{@state_machine}
|
|
44
|
+
,______
|
|
45
|
+
| Tape
|
|
46
|
+
`------
|
|
47
|
+
#{@tape}
|
|
48
|
+
TO_S
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def step!(n = 1)
|
|
52
|
+
return if n < 1
|
|
53
|
+
|
|
54
|
+
(1..n).each do
|
|
55
|
+
result = @state_machine.process!(@tape.read)
|
|
56
|
+
@history << result
|
|
57
|
+
break if result[:final]
|
|
58
|
+
|
|
59
|
+
@tape.write result[:write]
|
|
60
|
+
@tape.move result[:move]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
@history.last
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def step(...)
|
|
67
|
+
step!(...) rescue YATM::Error
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def run!(max = Float::INFINITY)
|
|
71
|
+
(1..max).each do
|
|
72
|
+
latest = step!
|
|
73
|
+
break to_h if latest[:final]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def run(...)
|
|
78
|
+
run!(...) rescue YATM::Error
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "state_machine_errors"
|
|
4
|
+
require_relative "event"
|
|
5
|
+
|
|
6
|
+
class YATM::StateMachine
|
|
7
|
+
attr_reader :current_state, :events, :final_states, :initial_state
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@events = {}
|
|
11
|
+
@final_states = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def reset
|
|
15
|
+
@current_state = @initial_state
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
<<~TO_S.chomp
|
|
20
|
+
| states: #{states}
|
|
21
|
+
| current: #{@current_state}
|
|
22
|
+
| events: #{@events.map(&:name)}
|
|
23
|
+
TO_S
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def states
|
|
27
|
+
@events.map do |_name, event|
|
|
28
|
+
event.keys + event.map { |_, val| val[:to] }
|
|
29
|
+
end.flatten.uniq
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initial_state(state)
|
|
33
|
+
@initial_state = self.class.statify(state)
|
|
34
|
+
@current_state = @initial_state
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def final_state(*states)
|
|
38
|
+
states.each do |state|
|
|
39
|
+
(@final_states << self.class.statify(state)).uniq!
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def event(name, **transitions)
|
|
44
|
+
@events[name] = YATM::Event.new(name, **transitions)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def process(value)
|
|
48
|
+
process!(value)
|
|
49
|
+
rescue StateMachineError
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def process!(value)
|
|
54
|
+
return { final: @current_state } if @final_states.include?(@current_state)
|
|
55
|
+
raise InitialStateNotSet unless @current_state
|
|
56
|
+
raise InvalidEvent, value unless (event = @events[value])
|
|
57
|
+
raise InvalidTransition.new(@current_state, event) unless (
|
|
58
|
+
transition = event[@current_state] || event[YATM::ANY]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@current_state = transition[:to] unless transition[:to] == YATM::SAME
|
|
62
|
+
transition
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.statify(state)
|
|
66
|
+
raise InvalidState, state unless state.respond_to?(:to_s)
|
|
67
|
+
|
|
68
|
+
state = state.to_s
|
|
69
|
+
raise InvalidState, state unless state.respond_to?(:to_sym)
|
|
70
|
+
|
|
71
|
+
state.to_sym
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tape_errors"
|
|
4
|
+
|
|
5
|
+
class YATM::Tape
|
|
6
|
+
attr_accessor :pos
|
|
7
|
+
|
|
8
|
+
def initialize(...)
|
|
9
|
+
reset(...)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def reset(content = [nil], position: 0)
|
|
13
|
+
@pos = position
|
|
14
|
+
@p_tape = content
|
|
15
|
+
@n_tape = [nil]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def read
|
|
19
|
+
tape[table_pos]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def write(value)
|
|
23
|
+
tape[table_pos] = value
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def move(direction = YATM::NONE)
|
|
27
|
+
case direction
|
|
28
|
+
when YATM::RIGHT
|
|
29
|
+
@pos += 1
|
|
30
|
+
expand if table_pos == tape.size
|
|
31
|
+
when YATM::LEFT
|
|
32
|
+
@pos -= 1
|
|
33
|
+
expand if table_pos > tape.size
|
|
34
|
+
when YATM::NONE
|
|
35
|
+
else
|
|
36
|
+
raise InvalidMove
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_s
|
|
41
|
+
full = @n_tape.reverse + @p_tape
|
|
42
|
+
full.map.with_index do |val, idx|
|
|
43
|
+
cell_txt(val, idx)
|
|
44
|
+
end.join(" ")
|
|
45
|
+
.gsub(/^\[_\] +/, "")
|
|
46
|
+
.gsub(/(\[_\] )*\[_\]\z/, "")
|
|
47
|
+
.gsub(/ \z/, "")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_txt
|
|
51
|
+
full = @n_tape.reverse + @p_tape
|
|
52
|
+
str = ""
|
|
53
|
+
full.each_with_index do |val, idx|
|
|
54
|
+
str += (idx - @n_tape.size).to_s.rjust(4) + " | #{val.inspect}".ljust(8)
|
|
55
|
+
str += " <=" if idx == abs_pos
|
|
56
|
+
str += "\n"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
str
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def cell_txt(val, idx)
|
|
65
|
+
str = idx == @n_tape.size ? "|:| " : ""
|
|
66
|
+
str += idx == abs_pos ? ">|" : "["
|
|
67
|
+
str += val.nil? ? "_" : val.to_s
|
|
68
|
+
str += idx == abs_pos ? "|<" : "]"
|
|
69
|
+
str
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def tape
|
|
73
|
+
@pos >= 0 ?
|
|
74
|
+
@p_tape :
|
|
75
|
+
@n_tape
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def abs_pos
|
|
79
|
+
@pos + @n_tape.size
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def table_pos
|
|
83
|
+
@pos >= 0 ?
|
|
84
|
+
@pos :
|
|
85
|
+
-@pos - 1
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def expand
|
|
89
|
+
current_size = tape.size
|
|
90
|
+
(1..current_size).each { tape << nil }
|
|
91
|
+
end
|
|
92
|
+
end
|
data/lib/yatm/version.rb
ADDED
data/lib/yatm.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "yatm/version"
|
|
4
|
+
require_relative "yatm/tape/tape"
|
|
5
|
+
require_relative "yatm/state_machine/state_machine"
|
|
6
|
+
require_relative "yatm/machine/machine"
|
|
7
|
+
|
|
8
|
+
module YATM
|
|
9
|
+
ANY = :*
|
|
10
|
+
SAME = :_
|
|
11
|
+
LEFT = :l
|
|
12
|
+
RIGHT = :r
|
|
13
|
+
NONE = nil
|
|
14
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: yatm
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- tiago-macedo
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2022-08-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: |-
|
|
14
|
+
This gem provides you with the module `YATM`.
|
|
15
|
+
The class YATM::Machine, specifically, allows you to program a functioning
|
|
16
|
+
turing machine and load it with a tape containing arbitrary symbols.
|
|
17
|
+
|
|
18
|
+
Check out files `lib/example_*.rb` to see it in action.
|
|
19
|
+
email:
|
|
20
|
+
- tiagomacedo@ufrj.br
|
|
21
|
+
executables: []
|
|
22
|
+
extensions: []
|
|
23
|
+
extra_rdoc_files: []
|
|
24
|
+
files:
|
|
25
|
+
- lib/yatm.rb
|
|
26
|
+
- lib/yatm/error.rb
|
|
27
|
+
- lib/yatm/machine/machine.rb
|
|
28
|
+
- lib/yatm/state_machine/state_machine.rb
|
|
29
|
+
- lib/yatm/tape/tape.rb
|
|
30
|
+
- lib/yatm/version.rb
|
|
31
|
+
homepage: https://github.com/tiago-macedo/yatm
|
|
32
|
+
licenses:
|
|
33
|
+
- MIT
|
|
34
|
+
metadata:
|
|
35
|
+
homepage_uri: https://github.com/tiago-macedo/yatm
|
|
36
|
+
source_code_uri: https://github.com/tiago-macedo/yatm
|
|
37
|
+
changelog_uri: https://github.com/tiago-macedo/yatm
|
|
38
|
+
post_install_message:
|
|
39
|
+
rdoc_options: []
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 3.0.0
|
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
requirements: []
|
|
53
|
+
rubygems_version: 3.2.3
|
|
54
|
+
signing_key:
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: Yet Another Turing Machine implementation.
|
|
57
|
+
test_files: []
|