Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
cat24a committed Oct 9, 2024
0 parents commit 5523dc5
Show file tree
Hide file tree
Showing 14 changed files with 689 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target
.vscode
dependency-reduced-pom.xml
69 changes: 69 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>nanoquiz</groupId>
<artifactId>nanoquiz</artifactId>
<version>24w41a</version>

<properties>
<maven.compiler.release>17</maven.compiler.release>
<exec.mainClass>nanoquiz.Main</exec.mainClass>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/maven/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>nanoquiz.Main</mainClass>
</manifest>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>com.electronwill.night-config</groupId>
<artifactId>toml</artifactId>
<version>3.8.1</version>
</dependency>

<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240303</version>
</dependency>
</dependencies>
</project>
124 changes: 124 additions & 0 deletions src/main/java/nanoquiz/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package nanoquiz;

import java.awt.Color;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

import com.electronwill.nightconfig.core.file.FileConfig;

import nanoquiz.util.Timer;

public abstract class Main {
public static final Logger log = Logger.getLogger("nanoquiz");
static UI ui;
static List<Question> questions = new ArrayList<>();
static String answer;
private static final Object answerNotifier = new Object();
public static final Random random = new Random();
public static Path workdir = Path.of(".");
public static FileConfig config;

public static void main(String[] args) throws InterruptedException, InvocationTargetException {
ui = new UI(Thread.currentThread());
ui.setText("Uruchamianie NanoQuiz...", Color.GRAY, false, true);
setupFS();
loadConfig();
Updater.checkForUpdates();
QuestionLoader.loadQuestions();
if(questions.size() == 0) {
log.severe(()->"NO QUESTIONS");
ui.setText("BRAK PYTAŃ", Color.RED, false, true);
return;
}
Serialization.loadKnowledge();
try {
doQuizThing();
} catch(InterruptedException e) {
return;
} finally {
Serialization.saveKnowledge();
}
}

static void doQuizThing() throws InterruptedException {
Question question = chooseQuestion();
while(true) {
boolean good;
String correctAnswer;
synchronized(answerNotifier) {
answer = null;
}
ui.setText(question.question, Color.BLACK, true, true);
synchronized(answerNotifier) {
while (answer == null) {
answerNotifier.wait();
}
good = question.answer(answer);
}

if (good) {
ui.setText("DOBRZE!", Color.GREEN, false, false);
Thread.sleep(config.<Integer>get("delay.good"));
} else {
ui.setText("ŹLE: " + question.answerChecker.getCorrectAnswer(), Color.RED, false, false);
Thread.sleep(config.<Integer>get("delay.bad"));
}
if(config.<Integer>get("delay.cooldown") != 0) {
ui.hide();
}
Timer timer = new Timer(config.<Integer>get("delay.cooldown"));
question = chooseQuestion();
timer.join();

}
}

static void setupFS() {
try {
workdir = Path.of(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent();
} catch(URISyntaxException e) {}
}

static void loadConfig() {
config = FileConfig.builder(workdir.resolve("nq-config.toml"))
.defaultResource("/nanoquiz/default-config.toml")
.build();
config.load();
}

static Question chooseQuestion() {
Collections.shuffle(questions);
Question best = null;
float bestDifficulty = Float.NEGATIVE_INFINITY;
int checkedAmount = (int) (questions.size()*config.<Double>get("question_selector.confidence").floatValue());
if(checkedAmount > questions.size()){
checkedAmount = questions.size();
}
if(checkedAmount == 0) {
checkedAmount = 1;
}
for(int i = 0; i < checkedAmount; i++) {
Question question = questions.get(i);
float difficulty = (float) (System.currentTimeMillis() - question.lastQuizzed);
difficulty -= question.score * config.<Double>get("question_selector.score_factor").floatValue();
if(difficulty > bestDifficulty) {
best = question;
bestDifficulty = difficulty;
}
}
return best;
};

public static void handleSubmit(String answer) {
synchronized(answerNotifier) {
Main.answer = answer;
answerNotifier.notifyAll();
}
}
}
26 changes: 26 additions & 0 deletions src/main/java/nanoquiz/Question.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package nanoquiz;

import nanoquiz.checker.AnswerChecker;

public class Question {
public String question;
AnswerChecker answerChecker;
public long lastQuizzed = 0L;
public float score = 0F;

Question(String question, AnswerChecker answerChecker) {
this.question = question;
this.answerChecker = answerChecker;
}

public boolean answer(String answer) {
lastQuizzed = System.currentTimeMillis();
float scoreDecay = Main.config.<Double>get("question_selector.score_decay").floatValue();
score *= 1-scoreDecay;
if(answerChecker.check(answer)) {
score += scoreDecay;
return true;
}
return false;
}
}
45 changes: 45 additions & 0 deletions src/main/java/nanoquiz/QuestionLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package nanoquiz;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import nanoquiz.checker.CaseInsensitiveAnswerChecker;

public abstract class QuestionLoader {
static void loadQuestions() {
File quizDir = Main.workdir.resolve("quiz").toFile();
quizDir.mkdir();
for (File quizFile : quizDir.listFiles()) {
try {
parseSimpleQuiz(quizFile);
} catch(FileNotFoundException e) {
e.printStackTrace();
}
}
}

static void parseSimpleQuiz(File file) throws FileNotFoundException {
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
while (true) {
String question = reader.readLine();
String answer = reader.readLine();
if (question == null || answer == null) {
break;
}
Main.questions.add(new Question(question, new CaseInsensitiveAnswerChecker(answer)));
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
80 changes: 80 additions & 0 deletions src/main/java/nanoquiz/Serialization.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package nanoquiz;

import nanoquiz.util.Pair;
import nanoquiz.util.IOUtil;

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.HashMap;

public abstract class Serialization {
public static void loadKnowledge() {
File knowledgeFile = Main.workdir.resolve("knowledge").toFile();
if(!knowledgeFile.exists()) return;
BufferedInputStream reader = null;
HashMap<Integer, Pair<Long, Float>> data = new HashMap<>();
try {
reader = new BufferedInputStream(new FileInputStream(knowledgeFile));
while (true) {
int id;
long time;
float score;
try {
id = IOUtil.byteArrayToInt(IOUtil.readBytesOrWait(reader, 4));
time = IOUtil.byteArrayToLong(IOUtil.readBytesOrWait(reader, 8));
score = Float.intBitsToFloat(IOUtil.byteArrayToInt(IOUtil.readBytesOrWait(reader, 4)));
} catch(EOFException e) {
break;
}
data.put(id, new Pair<Long, Float>(time, score));
}
} catch(IOException e) {
e.printStackTrace();
return;
} finally {
try {
if (reader != null) {
reader.close();
}
} catch(IOException e) {
e.printStackTrace();
}
}
for(Question question : Main.questions) {
Pair<Long, Float> thisData = data.get(question.question.hashCode());
if (thisData == null) {
continue;
}
question.lastQuizzed = thisData.first();
question.score = thisData.second();
}
}

public static void saveKnowledge() {
File knowledgeFile = Main.workdir.resolve("knowledge").toFile();
BufferedOutputStream writer = null;
try {
writer = new BufferedOutputStream(new FileOutputStream(knowledgeFile));
for (Question question : Main.questions) {
writer.write(IOUtil.intToByteArray(question.question.hashCode()));
writer.write(IOUtil.longToByteArray(question.lastQuizzed));
writer.write(IOUtil.intToByteArray(Float.floatToIntBits(question.score)));
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
if(writer != null) {
writer.close();
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
Loading

0 comments on commit 5523dc5

Please sign in to comment.