SpreadQuiz/class/ReportBuilder.php
Epagris 144c62f9ad - LaTeX template improved: submission count, challenge fill and skip counts added
- "List best results only" option added to each report generation functionality
2024-10-01 15:55:30 +02:00

221 lines
5.6 KiB
PHP

<?php
require_once "GroupMgr.php";
require_once "TestMgr.php";
require_once "common_func.php";
class ReportBuilder
{
static public function getStatsByFilters(int $gameid, string $filter, string $groups, bool $bestOnly)
{
$groupMgr = new GroupMgr();
$testMgr = new TestMgr();
// get nicknames
$groups = explode_list($groups);
$nicknames = $groupMgr->getJoinedMembersByUniqueNames($groups);
$groupFilter = ["nickname", "IN", $nicknames];
// get IDs
$tests = $testMgr->getResultsByGameId($gameid, $filter, "", true, $bestOnly, $groupFilter);
$ids = array_map(fn($test) => $test["_id"], $tests);
// generate stats
return $testMgr->generateDetailedStats($gameid, $ids);
}
}
class TeXUtils
{
static public function processCodeInserts(string $str) : string
{
$parts = explode("`", $str);
$output = "";
for ($i = 0; $i < count($parts); $i++) {
$output .= $parts[$i];
if ($i < count($parts) - 1) {
if (($i % 2) === 0) {
$output .= "\\texttt{";
} else {
$output .= "}";
}
}
}
return $output;
}
static public function escape(string $str) : string {
return preg_replace("/([$#%&_~^])/", "\\\\$1", $str);
}
}
class Answer
{
const CORRECT = "Correct";
const INCORRECT = "Incorrect";
private string $text; // Answer's text
private string $type; // Answer's type
private float $ratio; // Answer's ratio
public function __construct(string $type, string $text, float $ratio)
{
$this->type = $type;
$this->text = $text;
$this->ratio = $ratio;
}
// Convert answer into TeX format.
public function genTeX(): string
{
return "\\answer" . $this->type . "{" . $this->ratio . "}{" . $this->text . "}\n";
}
// Get answer ratio.
public function getRatio(): float
{
return $this->ratio;
}
}
class Challenge
{
private string $question;
private array $answers;
private int $fillCount;
private int $skipCount;
// Sort answers by ratio.
private function sortAnswers() : void {
usort($this->answers, function($a, $b) {return $a->getRatio() < $b->getRatio();});
}
function __construct(array $data)
{
$this->question = $data["question"]; // store question
for ($i = 0; $i < count($data["answers"]); $i++) {
$answer = $data["answers"][$i];
$ratio = $data["answer_ratio"][$i];
$type = $answer === $data["correct_answer"] ? Answer::CORRECT : Answer::INCORRECT;
$this->answers[] = new Answer($type, $answer, $ratio);
}
$this->fillCount = array_sum($data["player_answers"]); // get fill count
$this->skipCount = $data["skipped"];
$this->sortAnswers(); // sort answers by fill ratio
}
public function getQuestion(): string
{
return $this->question;
}
public function getAnswers(): array
{
return $this->answers;
}
public function getFillCount(): int {
return $this->fillCount;
}
public function getSkipCount(): int {
return $this->skipCount;
}
public function getSubmissionCount() : int {
return $this->fillCount + $this->skipCount;
}
// Generate TeX representation.
public function genTeX(): string
{
$tex = "\\begin{question}{" . $this->question . "}{" . $this->fillCount . "}\n";
foreach ($this->answers as &$answer) {
$tex .= $answer->genTeX();
}
$tex .= "\\end{question}\n";
return $tex;
}
}
class ReportSection
{
private string $title;
private array $challenges;
private function getNumberOfSubmissions() : int {
return count($this->challenges) > 0 ? $this->challenges[0]->getSubmissionCount() : 0;
}
function __construct(string $title, array $challenges)
{
$this->title = $title;
$this->challenges = array_map(fn($ch) => new Challenge($ch), $challenges);
}
function getChallenges(): array
{
return $this->challenges;
}
function getTitle(): string
{
return $this->title;
}
// Generate TeX representation of this report.
function genTeX(): string
{
$tex = "\\begin{quiz}{" . $this->title . "}{" . $this->getMaxFillingCount() . "}\n";
foreach ($this->challenges as $challenge) {
$tex .= $challenge->genTeX();
}
$tex .= "\\end{quiz}\n";
return $tex;
}
}
class Report
{
private string $title;
private array $sections;
function __construct(string $title)
{
$this->title = $title;
$this->sections = [];
}
// Add a new section to the report.
function addSection(ReportSection &$section): void
{
$this->sections[] = $section;
}
// Generate TeX representation.
function genTeX(): string
{
$tex = "";
foreach ($this->sections as $section) {
$tex .= $section->genTeX() . "\n\n";
}
$tex = TeXUtils::processCodeInserts($tex);
$tex = TeXUtils::escape($tex);
return $tex;
}
const CONTENT_FILE = "content.tex";
const TITLE_FILE = "title.tex";
// Save TeX representation.
function saveTeX(string $dir): void
{
file_put_contents($dir . DIRECTORY_SEPARATOR . self::CONTENT_FILE, $this->genTeX());
file_put_contents($dir . DIRECTORY_SEPARATOR . self::TITLE_FILE, $this->title);
}
}