Skip to content
Open

Lab1 #43

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/by/alexbiliba/quizer/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package by.alexbiliba.quizer;

import by.alexbiliba.quizer.tasks.TextTask;
import by.alexbiliba.quizer.task_generators.GroupTaskGenerator;
import by.alexbiliba.quizer.task_generators.PoolTaskGenerator;
import by.alexbiliba.quizer.tasks.math_tasks.EquationTask;
import by.alexbiliba.quizer.tasks.math_tasks.ExpressionTask;
import by.alexbiliba.quizer.tasks.math_tasks.MathTask;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

public class Main {
/**
* @return тесты в {@link Map}, где
* ключ - название теста {@link String}
* значение - сам тест {@link Quiz}
*/
static Map<String, Quiz> getQuizMap() {
Map<String, Quiz> quizzes = new HashMap<String, Quiz>();

EnumSet<MathTask.Operation> enumSet1;
enumSet1 = EnumSet.of(MathTask.Operation.SUM,
MathTask.Operation.DIFFERENCE,
MathTask.Operation.MULTIPLICATION,
MathTask.Operation.DIVISION);
quizzes.put("Only expressions", new Quiz(new ExpressionTask.Generator(0, 1000, 3, enumSet1), 10));

EnumSet<MathTask.Operation> enumSet2;
enumSet2 = EnumSet.of(MathTask.Operation.SUM,
MathTask.Operation.MULTIPLICATION,
MathTask.Operation.DIVISION);
quizzes.put("Only equations", new Quiz(new EquationTask.Generator(0, 2000, 2, enumSet2), 10));

EnumSet<MathTask.Operation> enumSet3;
enumSet3 = EnumSet.of(
MathTask.Operation.MULTIPLICATION,
MathTask.Operation.DIVISION);
quizzes.put("Mixed math tasks", new Quiz(new GroupTaskGenerator(new ExpressionTask.Generator(0, 1000, 5, enumSet3),
new EquationTask.Generator(0, 1000, 6, enumSet3)), 10));

// Заготовка текстовых заданий
TextTask task1 = new TextTask("Do you love Java?", "Yes");
TextTask task2 = new TextTask("Do you love C++?", "Yes");
TextTask task3 = new TextTask("Do you love Assembly?", "No.....");
TextTask task4 = new TextTask("Do you love Python?", "Maybe");
TextTask task5 = new TextTask("Do you love WinAPI?", "No");
PoolTaskGenerator textTaskGen = new PoolTaskGenerator(false, task1, task2, task3, task4, task5);

EnumSet<MathTask.Operation> enumSet4;
enumSet4 = EnumSet.of(MathTask.Operation.SUM,
MathTask.Operation.DIFFERENCE);
quizzes.put("Mixed math tasks", new Quiz(new GroupTaskGenerator(textTaskGen,
new ExpressionTask.Generator(0, 1000, 10, enumSet4),
new EquationTask.Generator(0, 1000, 11, enumSet4)), 10));

quizzes.put("Only text", new Quiz(new PoolTaskGenerator(true, task1, task2, task3, task4, task5), 10));

return quizzes;
}
public static void main(String[] args) {
Map<String, Quiz> quizzes = getQuizMap();
Scanner input = new Scanner(System.in);
String quizName = null;
while (true) {
System.out.print("Enter the quiz name: ");
quizName = input.nextLine();
if (quizzes.containsKey(quizName)) {
break;
}
System.out.println("There is no quiz with this name!");
}
System.out.flush();

Quiz mainQuiz = quizzes.get(quizName);
System.out.println("Quiz started!");
int taskIndex = 1;
while (!mainQuiz.isFinished()) {
System.out.print(String.valueOf(taskIndex) + ") ");
Task currentTask = mainQuiz.nextTask();
System.out.println(currentTask.getText());
String userAnswer = input.nextLine();
mainQuiz.provideAnswer(userAnswer);
taskIndex++;
}
System.out.println("Total:");
System.out.println("Correct answers - " + String.valueOf(mainQuiz.AC_number));
System.out.println("Wrong answers - " + String.valueOf(mainQuiz.WA_number));
System.out.println("Incorrect input - " + String.valueOf(mainQuiz.II_number));
System.out.println("Your score: " + mainQuiz.getMark() * 100. + "%");
input.close();
}
}
91 changes: 91 additions & 0 deletions src/by/alexbiliba/quizer/Quiz.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package by.alexbiliba.quizer;

import java.util.ArrayList;

/**
* Class, который описывает один тест
*/
class Quiz {

ArrayList<Task> tasks = new ArrayList<>();
int current_task_index = -1;

int AC_number = 0;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Для этого предоставляют геттеры и сеттеры и делют их приватными.

int WA_number = 0;
int II_number = 0;

/**
* @param generator генератор заданий
* @param taskCount количество заданий в тесте
*/
Quiz(Task.Generator generator, int taskCount) {
while (taskCount > 0) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Почему нельзя делать это лениво?

Task new_task = generator.generate();
tasks.add(new_task);
taskCount--;
}
}

/**
* @return задание, повторный вызов вернет слелующее
* @see Task
*/
Task nextTask() {
current_task_index++;
Task current_task = tasks.get(current_task_index);
return current_task;
}

/**
* Предоставить ответ ученика. Если результат {@link Result#INCORRECT_INPUT}, то счетчик неправильных
* ответов не увеличивается, а {@link #nextTask()} в следующий раз вернет тот же самый объект {@link Task}.
*/
Result provideAnswer(String answer) {
Task current_task = tasks.get(current_task_index);
Result current_result = current_task.validate(answer);
if (current_result == Result.OK) {
AC_number++;
} else if (current_result == Result.WRONG) {
WA_number++;
} else {
II_number++;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вряд ли тут соблюдается контракт выше.

}
return current_result;
}

/**
* @return завершен ли тест
*/
boolean isFinished() {
return current_task_index >= tasks.size() - 1;
}

/**
* @return количество правильных ответов
*/
int getCorrectAnswerNumber() {
return AC_number;
}

/**
* @return количество неправильных ответов
*/
int getWrongAnswerNumber() {
return WA_number;
}

/**
* @return количество раз, когда был предоставлен неправильный ввод
*/
int getIncorrectInputNumber() {
return II_number;
}

/**
* @return оценка, которая является отношением количества правильных ответов к количеству всех вопросов.
* Оценка выставляется только в конце!
*/
double getMark() {
return ((double) AC_number) / ((double) tasks.size());
}
}
10 changes: 10 additions & 0 deletions src/by/alexbiliba/quizer/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package by.alexbiliba.quizer;

/**
* Enum, который описывает результат ответа на задание
*/
public enum Result {
OK, // Получен правильный ответ
WRONG, // Получен неправильный ответ
INCORRECT_INPUT // Некорректный ввод. Например, текст, когда ожидалось число
}
30 changes: 30 additions & 0 deletions src/by/alexbiliba/quizer/Task.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package by.alexbiliba.quizer;

/**
* Interface, который описывает одно задание
*/
public interface Task {
public interface Generator {
/*
* Возвращает задание. При этом новый объект может не создаваться, если класс задания иммутабельный
*
* @return задание
* @see Task
*/
Task generate();
}
/*
@return текст задания
*/
String getText();
String getAnswer();

/*
* Проверяет ответ на задание и возвращает результат
*
* @param answer ответ на задание
* @return результат ответа
* @see Result
*/
Result validate(String answer);
}
47 changes: 47 additions & 0 deletions src/by/alexbiliba/quizer/task_generators/GroupTaskGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package by.alexbiliba.quizer.task_generators;

import by.alexbiliba.quizer.*;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не думаю, что здесь все нужно.


import java.util.*;

import java.util.concurrent.ThreadLocalRandom;

public class GroupTaskGenerator implements Task.Generator {
Collection<Task.Generator> generators = null;

/**
* Конструктор с переменным числом аргументов
*
* @param generators генераторы, которые в конструктор передаются через запятую
*/
public GroupTaskGenerator(Task.Generator... generators) {
this.generators = new ArrayList<Task.Generator>();
this.generators.addAll(Arrays.asList(generators));
}

/**
* Конструктор, который принимает коллекцию генераторов
*
* @param generators генераторы, которые передаются в конструктор в Collection (например, {@link ArrayList})
*/
GroupTaskGenerator(Collection<Task.Generator> generators) {
this.generators = generators;
}

/**
* @return результат метода generate() случайного генератора из списка.
* Если этот генератор выбросил исключение в методе generate(), выбирается другой.
* Если все генераторы выбрасывают исключение, то и тут выбрасывается исключение.
*/
public Task generate() {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не соблюдается контракт выше.

int generatorIndex = ThreadLocalRandom.current().nextInt(0, generators.size());
int currentGeneratorIndex = 0;
for (Task.Generator generator : generators) {
if (generatorIndex == currentGeneratorIndex) {
return generator.generate();
}
currentGeneratorIndex++;
}
return null;
}
}
79 changes: 79 additions & 0 deletions src/by/alexbiliba/quizer/task_generators/PoolTaskGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package by.alexbiliba.quizer.task_generators;

import by.alexbiliba.quizer.*;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

public class PoolTaskGenerator implements Task.Generator {
boolean allowDuplicate;
int tasksAllow;
Collection<Task> tasks = null;
ArrayList<Boolean> task_used = new ArrayList<>();

/**
* Конструктор с переменным числом аргументов
*
* @param allowDuplicate разрешить повторения
* @param tasks задания, которые в конструктор передаются через запятую
*/
public PoolTaskGenerator(
boolean allowDuplicate,
Task... tasks
) {
tasksAllow = tasks.length;
this.allowDuplicate = allowDuplicate;
this.tasks = new ArrayList<Task>();
this.tasks.addAll(Arrays.asList(tasks));
for (int i = 0; i < tasks.length; i++) {
task_used.add(false);
}
}

/**
* Конструктор, который принимает коллекцию заданий
*
* @param allowDuplicate разрешить повторения
* @param tasks задания, которые передаются в конструктор в Collection (например, {@link LinkedList})
*/
PoolTaskGenerator(
boolean allowDuplicate,
Collection<Task> tasks
) {
tasksAllow = tasks.size();
this.allowDuplicate = allowDuplicate;
this.tasks = tasks;
for (int i = 0; i < tasks.size(); i++) {
task_used.add(false);
}
}

/**
* @return случайная задача из списка
*/
public Task generate() {
Task newTask = null;
int taskIndex = 0;
if (allowDuplicate) {
taskIndex = ThreadLocalRandom.current().nextInt(0, tasks.size());
} else {
if (tasksAllow == 0) {
return null;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Почему не исключение?

}
while (task_used.get(taskIndex)) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Супер неэффективно.

taskIndex = ThreadLocalRandom.current().nextInt(0, tasks.size());
}
tasksAllow--;
task_used.set(taskIndex, true);
}

int currentTaskIndex = 0;
for (Task task : tasks) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Чтобы достать задачу по известному индексу нам точно надо O(n) дейсвтий? Мб стоит выбрать другую коллекцию?

if (taskIndex == currentTaskIndex) {
newTask = task;
break;
}
currentTaskIndex++;
}
return newTask;
}
}
Loading