implement question bank parsing

This commit is contained in:
Slavasil 2025-03-23 22:09:27 +03:00
parent e35b8520b4
commit 4ee8a06232
2 changed files with 112 additions and 1 deletions

103
App/Data/Database.cs Normal file
View File

@ -0,0 +1,103 @@
namespace Game.Data {
public class Database {
public List<Question> questions = new List<Question>();
public static Database ReadFromFile(string filename) {
var db = new Database();
using (StreamReader rd = new StreamReader(filename)) {
string? line;
int lineNumber = 1;
while ((line = rd.ReadLine()) != null) {
int i = 0;
int len = line.Length;
int state = 0;
int correctAnswer = -1;
List<string> answers = new List<string>();
// read question
while (i < len + 1) {
if (i == len) {
throw new DatabaseReadException(I18n.Message.ERROR_NO_ANSWER_OPTIONS, lineNumber, i);
} else if (line[i] == '|')
if (state == 1) {
++i;
break;
} else {
state = 1;
}
else state = 0;
++i;
}
string question = line.Substring(0, i - 2);
int currentAnswer = 0;
while (i < len) {
// read answer text
state = 0;
int answerStart = i;
while (i < len + 1) {
if (i == len) {
throw new DatabaseReadException(I18n.Message.ERROR_EXPECTED_ARROW_TOKEN, lineNumber, i);
} else if (state == 0) {
if (line[i] == '=')
state = 1;
} else if (state == 1) {
if (line[i] == '>') {
++i;
break;
} else {
state = 0;
}
}
++i;
}
string answer = line.Substring(answerStart, i - answerStart - 2);
// read True or False
if (line[i] == 'T') {
if (i + 3 < len && line[i + 1] == 'r' && line[i + 2] == 'u' && line[i + 3] == 'e') {
correctAnswer = currentAnswer;
i += 4;
} else {
throw new DatabaseReadException(I18n.Message.ERROR_EXPECTED_TRUE_OR_FALSE, lineNumber, i);
}
} else if (line[i] == 'F') {
if (i + 4 < len && line[i + 1] == 'a' && line[i + 2] == 'l' && line[i + 3] == 's' && line[i + 4] == 'e') {
i += 5;
} else {
throw new DatabaseReadException(I18n.Message.ERROR_EXPECTED_TRUE_OR_FALSE, lineNumber, i);
}
}
// consume separator
if (i + 1 < len && (line[i] != '|' || line[i + 1] != '|'))
throw new DatabaseReadException(I18n.Message.ERROR_EXPECTED_ANSWER_SEPARATOR, lineNumber, i);
i += 2;
answers.Add(answer);
++currentAnswer;
}
lineNumber++;
db.questions.Add(new Question(question, answers, correctAnswer));
}
}
return db;
}
}
public class DatabaseReadException : Exception {
public readonly int line, column;
public readonly I18n.Message messageId;
public DatabaseReadException(I18n.Message messageId) {
this.messageId = messageId;
line = -1;
column = -1;
}
public DatabaseReadException(I18n.Message messageId, int line, int column) {
this.messageId = messageId;
this.line = line;
this.column = column;
}
}
public record Question (string question, List<string> answers, int correctAnswer);
}

View File

@ -29,7 +29,15 @@ namespace Game {
return 2; return 2;
} }
string databaseFileName = opts.databaseFilename ?? gameConfig.databasePath; string databaseFileName = opts.databaseFilename ?? gameConfig.databasePath;
Database questionDatabase;
try {
questionDatabase = Database.ReadFromFile(databaseFileName);
} catch (DatabaseReadException e) {
display.ShowFatalError(string.Format(I18n.GetMessage(I18n.Message.SYNTAX_ERROR), I18n.GetMessage(e.messageId), e.line.ToString(), e.column.ToString()));
Console.ReadKey();
return 3;
}
display.ResetWindow(); display.ResetWindow();