1
- module Play
2
-
3
- import .. GridWorlds as GW
4
- import REPL
5
-
6
1
const ESC = Char (0x1B )
7
2
const HIDE_CURSOR = ESC * " [?25l"
8
3
const SHOW_CURSOR = ESC * " [?25h"
@@ -19,30 +14,93 @@ close_maybe(io::Nothing) = nothing
19
14
20
15
write_maybe (io:: IO , content) = write (io, content)
21
16
write_maybe (io:: Nothing , content) = 0
22
- write_io1_maybe_io2 (io1:: IO , io2:: Union{Nothing, IO} , content) = write (io1, content) + write_maybe (io2, content)
17
+ write_maybe (io1, io2, content) = write_maybe (io1, content) + write_maybe (io2, content)
18
+
19
+ function play! (terminal:: REPL.Terminals.UnixTerminal , env:: AbstractGridWorld , file_name:: Union{Nothing, AbstractString} , frame_start_delimiter:: Union{Nothing, AbstractString} )
20
+ if ! isnothing (file_name) && isnothing (frame_start_delimiter)
21
+ error (" Please additionally specify a string for the keyword argument `frame_start_delimiter`, for example `frame_start_delimiter = \" FRAME_START_DELIMITER\" `. This is needed when you want to replay the recording." )
22
+ end
23
+ if isnothing (file_name) && ! isnothing (frame_start_delimiter)
24
+ error (" Please additionally specify a string for the keyword argument `file_name`, for example `file_name = \" recording.txt\" `. This is needed to save the recording in a text file and replay it later." )
25
+ end
26
+
27
+ terminal_out = terminal. out_stream
28
+ terminal_in = terminal. in_stream
29
+ file = open_maybe (file_name)
30
+
31
+ action_keys = get_action_keys (env)
32
+ key_bindings = " Key bindings to play: 'q': quit, 'r': GW.reset!, $(action_keys) : GW.act!"
33
+
34
+ char = nothing
35
+
36
+ write (terminal_out, CLEAR_SCREEN)
37
+ write (terminal_out, MOVE_CURSOR_TO_ORIGIN)
38
+ write (terminal_out, HIDE_CURSOR)
39
+
40
+ REPL. Terminals. raw! (terminal, true )
41
+
42
+ try
43
+ while true
44
+ write_maybe (file, frame_start_delimiter)
45
+
46
+ frame = key_bindings
47
+ frame = frame * " \n " * " Last play character read: $(char) "
48
+ frame = frame * " \n " * repr (MIME " text/plain" (), env)
49
+
50
+ write_maybe (terminal_out, file, frame)
51
+
52
+ char = read (terminal_in, Char)
53
+
54
+ if char == ' q'
55
+ write (terminal_out, SHOW_CURSOR)
56
+ close_maybe (file)
57
+ REPL. Terminals. raw! (terminal, false )
58
+ return nothing
59
+ elseif char == ' r'
60
+ reset! (env)
61
+ elseif char in action_keys
62
+ act! (env, findfirst (== (char), action_keys))
63
+ end
23
64
24
- show_maybe (io:: IO , mime:: MIME , content) = show (io, mime, content)
25
- show_maybe (io:: Nothing , mime:: MIME , content) = nothing
26
- function show_io1_maybe_io2 (io1:: IO , io2:: Union{Nothing, IO} , mime:: MIME , content)
27
- show (io1, mime, content)
28
- show_maybe (io2, mime, content)
65
+ write (terminal_out, EMPTY_SCREEN)
66
+ end
67
+ finally
68
+ write (terminal_out, SHOW_CURSOR)
69
+ close_maybe (file)
70
+ REPL. Terminals. raw! (terminal, false )
71
+ end
72
+
73
+ return nothing
29
74
end
30
75
31
- function replay (terminal:: REPL.Terminals.UnixTerminal , file_name:: AbstractString ; frame_rate = Union{Nothing, Real} = nothing )
76
+ play! (env:: AbstractGridWorld ; file_name = nothing , frame_start_delimiter = nothing ) = play! (REPL. TerminalMenus. terminal, env, file_name, frame_start_delimiter)
77
+
78
+ function replay (terminal:: REPL.Terminals.UnixTerminal , file_name:: AbstractString , frame_start_delimiter:: AbstractString , frame_rate = Union{Nothing, Real})
32
79
terminal_out = terminal. out_stream
33
- delimiter = EMPTY_SCREEN
34
- frames = split ( read (file_name, String), delimiter)
80
+ strings = split ( read (file_name, String), frame_start_delimiter)
81
+ frames = @view strings[ 2 : end ]
35
82
num_frames = length (frames)
36
83
84
+ write (terminal_out, CLEAR_SCREEN)
85
+ write (terminal_out, MOVE_CURSOR_TO_ORIGIN)
86
+ write (terminal_out, HIDE_CURSOR)
87
+
37
88
if isnothing (frame_rate)
38
89
terminal_in = terminal. in_stream
39
- REPL . Terminals . raw! (terminal, true )
90
+ replay_key_bindings = " Key bindings to replay: 'q': quit, 'f': first frame, 'n': next frame, 'p': previous frame "
40
91
current_frame = 1
92
+ char = nothing
93
+
94
+ REPL. Terminals. raw! (terminal, true )
95
+
41
96
try
42
97
while true
43
- write (terminal_out, frames[current_frame])
44
- println (terminal_out)
45
- println (terminal_out, " replay key bindings: 'q': quit, 'f': go to first frame, 'n': go to next frame, 'p': go to previous frame" )
98
+ replay_frame = replay_key_bindings
99
+ replay_frame = replay_frame * " \n " * " Last replay character read: $(char) "
100
+ replay_frame = replay_frame * " \n " * " ------------FRAME_START------------"
101
+ replay_frame = replay_frame * " \n " * frames[current_frame]
102
+
103
+ write (terminal_out, replay_frame)
46
104
47
105
char = read (terminal_in, Char)
48
106
@@ -66,63 +124,19 @@ function replay(terminal::REPL.Terminals.UnixTerminal, file_name::AbstractString
66
124
return nothing
67
125
end
68
126
else
127
+ write (terminal_out, CLEAR_SCREEN)
128
+ write (terminal_out, MOVE_CURSOR_TO_ORIGIN)
129
+ write (terminal_out, HIDE_CURSOR)
130
+
69
131
for frame in frames
70
132
write (terminal_out, frame)
71
133
sleep (1 / frame_rate)
72
- write (terminal_out, delimiter )
134
+ write (terminal_out, EMPTY_SCREEN )
73
135
end
74
- end
75
-
76
- return nothing
77
- end
78
-
79
- replay (file_name; frame_rate = nothing ) = replay (REPL. TerminalMenus. terminal, file_name, frame_rate = frame_rate)
80
136
81
- function play! (terminal:: REPL.Terminals.UnixTerminal , env:: GW.AbstractGridWorld ; file_name:: Union{Nothing, AbstractString} = nothing )
82
- REPL. Terminals. raw! (terminal, true )
83
-
84
- terminal_out = terminal. out_stream
85
- terminal_in = terminal. in_stream
86
- file = Play. open_maybe (file_name)
87
-
88
- write_io1_maybe_io2 (terminal_out, file, CLEAR_SCREEN)
89
- write_io1_maybe_io2 (terminal_out, file, MOVE_CURSOR_TO_ORIGIN)
90
- write_io1_maybe_io2 (terminal_out, file, HIDE_CURSOR)
91
-
92
- action_keys = GW. get_action_keys (env)
93
- action_names = GW. get_action_names (env)
94
- key_bindings = " play key bindings: 'q': quit, 'r': reset!, $(action_keys) : $(action_names) \n "
95
-
96
- try
97
- while true
98
- write_io1_maybe_io2 (terminal_out, file, key_bindings)
99
- show_io1_maybe_io2 (terminal_out, file, MIME " text/plain" (), env)
100
-
101
- char = read (terminal_in, Char)
102
-
103
- if char == ' q'
104
- write_io1_maybe_io2 (terminal_out, file, SHOW_CURSOR)
105
- close_maybe (file)
106
- REPL. Terminals. raw! (terminal, false )
107
- return nothing
108
- elseif char == ' r'
109
- GW. reset! (env)
110
- elseif char in action_keys
111
- GW. act! (env, findfirst (== (char), action_keys))
112
- end
113
-
114
- write_io1_maybe_io2 (terminal_out, file, EMPTY_SCREEN)
115
- write_io1_maybe_io2 (terminal_out, file, " Last character: $(char) \n " )
116
- end
117
- finally
118
- write_io1_maybe_io2 (terminal_out, file, SHOW_CURSOR)
119
- close_maybe (file)
120
- REPL. Terminals. raw! (terminal, false )
137
+ write (terminal_out, SHOW_CURSOR)
138
+ return nothing
121
139
end
122
-
123
- return nothing
124
140
end
125
141
126
- play! (env:: GW.AbstractGridWorld ; file_name = nothing ) = play! (REPL. TerminalMenus. terminal, env, file_name = file_name)
127
-
128
- end # module
142
+ replay (; file_name, frame_start_delimiter, frame_rate = nothing ) = replay (REPL. TerminalMenus. terminal, file_name, frame_start_delimiter, frame_rate)
0 commit comments