1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 | function skip_ws(line, i)
while true do
local c = line:sub(i, i)
if c == ' ' or c == '\t' then
i = i + 1
else
break
end
end
return i
end
function expect(line, phrase, i, lineno)
local start_i = i
local phrase_len = #phrase
for idx=1,phrase_len do
local c1 = phrase:sub(idx, idx)
local c2 = line:sub(i + idx - 1, i + idx - 1)
if c1 ~= c2 then
error("Expected \"" .. phrase .. "\" on ".. lineno .. ":" .. i)
end
end
return i + phrase_len
end
function parse_quoted(line, i, lineno)
i = expect(line, "\"", i, lineno)
local content = ""
local idx = 1
while true do
local c = line:sub(i + idx - 1, i + idx - 1)
if c == "\"" then
i = i + idx
break
elseif c == "\\" then
local nextc = line:sub(i + idx, i + idx)
local ch = ""
if nextc == "\\" then
ch = "\\"
elseif nextc == "\"" then
ch = "\""
elseif nextc == "t" then
ch = "\t"
elseif nextc == "n" then
ch = "\n"
else
error("Unknown escape sequence \"\\" .. nextc .. "\" on " .. (i + idx) .. ":" .. lineno)
end
content = content .. ch
idx = idx + 1
else
content = content .. c
end
idx = idx + 1
end
return content, i
end
function parse_num(line, i)
local final_num = ""
while true do
local c = line:sub(i, i)
local b = string.byte(c)
if not b then
break
end
if b >= string.byte('0') and b <= string.byte('9') then
final_num = final_num .. c
i = i + 1
else
break
end
end
return tonumber(final_num), i
end
function parse_ending(line, i, lineno)
while true do
local c = line:sub(i, i)
if c == "\0" or c == nil or c == "#" or #c == 0 then
break
elseif c ~= " " and c ~= "\t" then
error("Unexpected character '" .. c .. "' at " .. lineno .. ":" .. i)
end
i = i + 1
end
return i
end
function parse_line(line, lineno)
local line_index = 1
line_index = skip_ws(line, line_index)
local first_char = line:sub(line_index, line_index)
if first_char == '#' or #first_char == 0 then
return nil
end
local question_body = ""
local answers = {}
local correct_idx = 0
line_index = expect(line, "QUESTION", line_index, lineno)
line_index = skip_ws(line, line_index)
question_body, line_index = parse_quoted(line, line_index, lineno)
line_index = skip_ws(line, line_index)
line_index = expect(line, "ANSWERS", line_index, lineno)
line_index = skip_ws(line, line_index)
while true do
local c = line:sub(line_index, line_index)
if c ~= "\"" then
break
end
local answer = ""
answer, line_index = parse_quoted(line, line_index, lineno)
table.insert(answers, answer)
line_index = skip_ws(line, line_index)
end
line_index = expect(line, "CORRECT", line_index, lineno)
line_index = skip_ws(line, line_index)
correct_idx, line_index = parse_num(line, line_index)
line_index = parse_ending(line, line_index, lineno)
return {
question = question_body,
answers = answers,
correct_idx = correct_idx
}
end
function read_file(filename)
local file = io.open(filename, "r")
if not file then
error("Unable to load file")
end
local quiz_list = {}
local lineno = 1
for line in file:lines() do
local quiz = parse_line(line, lineno)
if not quiz then
goto continue
end
table.insert(quiz_list, quiz)
lineno = lineno + 1
::continue::
end
file:close()
return quiz_list
end
print("LyricLy quiz")
print()
local quiz_list = read_file("data.txt")
local total = #quiz_list
local correct = 0
local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i,quiz in ipairs(quiz_list) do
print(quiz.question)
for j,answer in ipairs(quiz.answers) do
print(alphabet:sub(j,j) .. ") " .. answer)
end
::take_input::
io.write("> ")
local ans = io.read("*l"):upper()
if #ans ~=1 or not (string.byte(ans) >= string.byte("A") and string.byte(ans) <= string.byte("Z")) then
print("Invalid input!")
goto take_input
end
local idx = string.byte(ans) - string.byte('A') + 1
if idx == quiz.correct_idx then
correct = correct + 1
end
end
print("Quiz is over, you got " .. correct .. " out of " .. total .. " correct.")
|
post a comment