diff --git a/local/stats/amcstats b/local/stats/amcstats new file mode 100755 index 0000000..ef90bc8 --- /dev/null +++ b/local/stats/amcstats @@ -0,0 +1,58 @@ +#!/usr/bin/env php +addFile('maxime', $filename ); +} + + + + + +$EC->sortByTotalPoints(true); +$EC->filterByTeachers(array('maxime', 'perret'), true); +$EC->doStats(); + +exit; + +?> diff --git a/local/stats/lib/lib_amcstats.php b/local/stats/lib/lib_amcstats.php new file mode 100755 index 0000000..4751b68 --- /dev/null +++ b/local/stats/lib/lib_amcstats.php @@ -0,0 +1,245 @@ +filename = $filename; + + $this->teacher = $teacher; + + $raw_data = file($this->filename, FILE_IGNORE_NEW_LINES); + $this->raw_data = array(); + foreach($raw_data as $line) { + $line = array_map("clean_array", explode(';', $line)); + $line = array_map("decimal_conversion", $line); + $this->raw_data[] = $line; + } + $this->parseHeader(); + $this->parseStudents(); + } + + public function getStudents() { + return $this->students; + } + + protected function parseHeader() { + foreach($this->raw_data[0] as $col_id => $value) { + // Analyse header from CSV file, based on content + $item = array(); + switch ($value) { + case "ID": + case "NAME": + case "EMAIL": + case "SECTION": + case "Mark": + $item['name'] = $value; + $item['type'] = "info"; + break; + case "SCIPER": + $item['name'] = $value; + $item['type'] = "unique_id"; + break; + default: + $item['name'] = $value; + if (preg_match('/^TICKED:/', $value)) { + $item['name'] = preg_replace('/^TICKED:/', '', $value); + $item['type'] = "ticked"; + } else { + $item['type'] = "question"; + $item['subtype'] = $this->guessSubtype($col_id); + } + + } + // Stats will be computed at a later stage + $item['stats'] = null; + $this->columns[] = $item; + } + } + + protected function guessSubtype($col_id) { + $subtype = null; + //$ticked_col = $this->getColIdsByType('ticked', $this->getQuestionNameByColId($col_id)); + $min_points = 0; + $max_points = 0; + foreach($this->raw_data as $line) { + if (preg_match('/\./', $line[$col_id])) return 'open'; + if ($line[$col_id] > $max_points) $max_points = $line[$col_id]; + } + + if ($max_points == 3) return 'mc'; + if ($max_points == 1) return 'tf'; + return 'unknown'; + } + + protected function getColIdByName($name) { + foreach ($this->columns as $id => $col) if ($col['name'] == $name) return $id; + throw new Exception('Column not found: '.$name); + } + + protected function getColIdsByType($type, $name = null) { + $ids = array(); + if (is_null($name)) { + foreach ($this->columns as $id => $col) if ($col['type'] == $type) $ids[] = $id; + } else { + foreach ($this->columns as $id => $col) if ($col['type'] == $type and $col['name'] == $name) $ids[] = $id; + } + if (count($ids) == 0) { + if (is_null($name)) throw new Exception('Column type not found: '.$type); + throw new Exception('Column type not found: '.$type.'/'.$name); + } + if (count($ids) == 1) return $ids[0]; + return $ids; + } + + protected function getQuestionNameByColId($id) { + if (array_key_exists($id, $this->columns) and $this->columns[$id]['type'] == 'question') + return $this->columns[$id]['name']; + throw new Exception('Column not found, or is not a question: '.$id); + } + + protected function parseStudents() { + foreach($this->raw_data as $line => $student) { + if ($line == 0) continue; // skip header + + $data = array('teacher' => $this->teacher); + foreach(array('ID', 'SCIPER', 'NAME', 'EMAIL', 'SECTION') as $key) { + $data[$key] = $student[$this->getColIdByName($key)]; + } + + // Get points + $points = array(); + $data['items'] = array(); + foreach($this->getColIdsByType('question') as $col) { + $item = array(); + $item['name'] = $this->getQuestionNameByColId($col); + $item['points'] = (float)$student[$col]; + $points[] = $item['points']; + $item['ticked'] = $student[$this->getColIdsByType('ticked', $item['name'])]; + $item['type'] = $this->columns[$col]['type']; + $item['subtype'] = $this->columns[$col]['subtype']; + $data['items'][] = $item; + } + + $data['total'] = array_sum($points); + + $data['present'] = (int)(array_sum(array_map("square", $points))>0); + + if (preg_match('/^FAKE/', $data['SCIPER'])) { + if ($data['present']) $data['type'] = 'unregistered'; + else $data['type'] = 'unused'; + } else $data['type'] = 'student'; + + $this->students[] = $data; + } + } +} + +// Compare students on total (higher to lower) +function cmp_total($a, $b) +{ + if ($a['total'] == $b['total']) { + return 0; + } + return ($a['total'] < $b['total']) ? 1 : -1; +} + +class ExamCalcs { + protected $dataset = null; + protected $tmp_dataset = null; + + public function __construct($dataset = null) { + $this->dataset = array(); + if (!is_null($dataset)) $this->dataset = $dataset; + } + + public function addFile($teacher, $teacher_file) { + echo "Adding $teacher ($teacher_file) to the dataset.\n"; + $AR = new AmcReader($teacher_file, $teacher); + $this->addDataSet($AR->getStudents()); + } + + public function addDataSet($data) { + foreach ($data as $student) $this->dataset[] = $student; + } + + public function filterByTeachers($teachers, $update = true) { + $this->tmp_dataset = array(); + foreach ($this->dataset as $student) { + if (is_array($teachers)) { + if (in_array($student['teacher'], $teachers)) + $dataset[] = $student; + } else { + if ($student['teacher'] == $teachers) + $dataset[] = $student; + } + } + if ($update) $this->dataset = $dataset; + return $dataset; + } + + public function sortByTotalPoints($update = true) { + if ($update) { + usort($this->dataset, "cmp_total"); + return $this->dataset; + } else { + $dataset = $this->dataset; + usort($dataset, "cmp_total"); + return $dataset; + } + } + + public function getDataSet() { + return $this->dataset; + } + + public function doStats() { + $stats = array(); + $stats['presence'] = array(); + foreach($this->dataset as $student) { + if (!array_key_exists($student['type'], $stats['presence'])) { + $stats['presence'][$student['type']] = 1; + } else { + $stats['presence'][$student['type']] += 1; + } + } + print_r($stats); + } + +} + +?>