You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					
					
						
							559 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							559 lines
						
					
					
						
							17 KiB
						
					
					
				| <?php | |
| // This file is part of Moodle - http://moodle.org/ | |
| // | |
| // Moodle is free software: you can redistribute it and/or modify | |
| // it under the terms of the GNU General Public License as published by | |
| // the Free Software Foundation, either version 3 of the License, or | |
| // (at your option) any later version. | |
| // | |
| // Moodle is distributed in the hope that it will be useful, | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| // GNU General Public License for more details. | |
| // | |
| // You should have received a copy of the GNU General Public License | |
| // along with Moodle.  If not, see <http://www.gnu.org/licenses/>. | |
|  | |
| /** | |
|  * This files plays the game "Snakes and Ladders". | |
|  * | |
|  * @package    mod_game | |
|  * @copyright  2007 Vasilis Daloukas | |
|  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
|  */ | |
| defined('MOODLE_INTERNAL') || die(); | |
| 
 | |
| /** | |
|  * Plays the game "Snakes and Ladders". | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $game | |
|  * @param stdClass $attempt | |
|  * @param stdClass $snakes | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_continue( $id, $game, $attempt, $snakes, $context) { | |
|     if ($attempt != false and $snakes != false) { | |
|         return game_snakes_play( $id, $game, $attempt, $snakes, $context); | |
|     } | |
| 
 | |
|     if ($attempt === false) { | |
|         $attempt = game_addattempt( $game); | |
|     } | |
| 
 | |
|     $newrec = new stdClass(); | |
|     $newrec->id = $attempt->id; | |
|     $newrec->snakesdatabaseid = $game->param3; | |
|     if ($newrec->snakesdatabaseid == 0) { | |
|         $newrec->snakesdatabaseid = 1; | |
|     } | |
|     $newrec->position = 1; | |
|     $newrec->queryid = 0; | |
|     $newrec->dice = rand( 1, 6); | |
|     if (!game_insert_record(  'game_snakes', $newrec)) { | |
|         print_error( 'game_snakes_continue: error inserting in game_snakes'); | |
|     } | |
| 
 | |
|     game_updateattempts( $game, $attempt, 0, 0); | |
| 
 | |
|     return game_snakes_play( $id, $game, $attempt, $newrec, $context); | |
| } | |
| 
 | |
| /** | |
|  * Plays the game "Snakes and Ladders". | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $game | |
|  * @param stdClass $attempt | |
|  * @param stdClass $snakes | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_play( $id, $game, $attempt, $snakes, $context) { | |
|     global $CFG, $DB, $OUTPUT; | |
| 
 | |
|     $board = game_snakes_get_board( $game); | |
|     $showboard = false; | |
| 
 | |
|     if ($snakes->position > $board->usedcols * $board->usedrows && $snakes->queryid <> 0) { | |
|         $finish = true; | |
| 
 | |
|         if (! $cm = $DB->get_record('course_modules', array( 'id' => $id))) { | |
|             print_error("Course Module ID was incorrect id=$id"); | |
|         } | |
| 
 | |
|         echo '<B>'.get_string( 'win', 'game').'</B><BR>'; | |
|         echo '<br>'; | |
|         echo "<a href=\"$CFG->wwwroot/mod/game/attempt.php?id=$id\">". | |
|             get_string( 'nextgame', 'game').'</a>         '; | |
|         echo "<a href=\"$CFG->wwwroot/course/view.php?id=$cm->course\">".get_string( 'finish', 'game').'</a> '; | |
|  | |
|         $gradeattempt = 1; | |
|         $finish = 1; | |
|         game_updateattempts( $game, $attempt, $gradeattempt, $finish); | |
|     } else { | |
|         $finish = false; | |
|         if ($snakes->queryid == 0) { | |
|             game_snakes_computenextquestion( $game, $snakes, $query); | |
|         } else { | |
|             $query = $DB->get_record( 'game_queries', array( 'id' => $snakes->queryid)); | |
|         } | |
|         if ($game->toptext != '') { | |
|             echo $game->toptext.'<br>'; | |
|         } | |
|         $showboard = true; | |
|     } | |
|  | |
|     if ($showboard and $game->param8 == 0) { | |
|         game_snakes_showquestion( $id, $game, $snakes, $query, $context); | |
|     } | |
| ?> | |
|     <script language="javascript" event="onload" for="window"> | |
|     <!--     | |
|     var retVal = new Array(); | |
|     var elements = document.getElementsByTagName("*"); | |
|     for(var i = 0;i < elements.length;i++){ | |
|         if( elements[ i].type == 'text'){ | |
|             elements[ i].focus(); | |
|             break; | |
|         } | |
|     } | |
|     --> | |
|     </script> | |
|  | |
|     <table> | |
|     <tr> | |
|         <td> | |
|  | |
| <div id="board" STYLE="position:relative; left:0px;top:0px;  | |
|     width:<?php p($board->width); ?>px; height:<?php p($board->height); ?>px;"> | |
| <img src="<?php echo $board->imagesrc; ?>"></img> | |
| </div> | |
|  | |
|     <?php | |
|     if ($finish == false) { | |
|         game_snakes_showdice( $snakes, $board); | |
|     } | |
|     ?> | |
|  | |
|     </td> | |
|     </tr> | |
|     </table> | |
|  | |
|     <?php | |
|     if ($game->bottomtext != '') { | |
|         echo '<br>'.$game->bottomtext; | |
|     } | |
|  | |
|     if ($showboard and $game->param8 != 0) { | |
|         game_snakes_showquestion( $id, $game, $snakes, $query, $context); | |
|     } | |
| } | |
|  | |
| /** | |
|  * Show dice | |
|  * | |
|  * @param stdClass $snakes | |
|  * @param boolean $board | |
|  */ | |
| function game_snakes_showdice( $snakes, $board) { | |
|     $pos = game_snakes_computeplayerposition( $snakes, $board); | |
| ?> | |
| <div ID="player1" STYLE="position:relative; left:<?php p( $pos->x);?>px; top:<?php p( $pos->y);?>px;" > | |
| <img src="snakes/1/player1.png"  | |
| alt="<?php print_string('snakes_player', 'game', ($snakes->position + 1)); /*Accessibility. */ ?>"  | |
| width="<?php echo $pos->width; ?>"  | |
| height="<?php echo $pos->height; ?>"/> | |
| </div> | |
|  | |
| <div ID="dice" STYLE="position:relative;  | |
| left:<?php p( $board->width + round($board->width / 3)); ?>px; | |
| top:<?php p( -2 * round($board->height / 3));?>px; "> | |
|     <img src="snakes/1/dice<?php p($snakes->dice);?>.png" alt="<?php print_string('snakes_dice', 'game', $snakes->dice) ?>" /> | |
|     </div> | |
| <?php | |
| } | |
|  | |
| /** | |
|  * Computes player's position. | |
|  * | |
|  * @param stdClass $snakes | |
|  * @param stdClass $board | |
|  */ | |
| function game_snakes_computeplayerposition( $snakes, $board) { | |
|     $x = ($snakes->position - 1) % $board->usedcols; | |
|     $y = floor( ($snakes->position - 1) / $board->usedcols); | |
|  | |
|     $cellwidth = ($board->width - $board->headerx - $board->footerx) / $board->usedcols; | |
|     $cellheight = ($board->height - $board->headery - $board->footery) / $board->usedrows; | |
|  | |
|     $pos = new stdClass(); | |
|     $pos->width = 22; | |
|     $pos->height = 22; | |
|  | |
|     $pos->ofsx = 0; | |
|     $pos->ofsy = $pos->height; | |
|  | |
|     switch( $board->direction) { | |
|         case 1: | |
|             if (($y % 2) == 1) { | |
|                 $x = $board->usedcols - $x - 1; | |
|             } | |
|             $pos->x = $board->headerx + $x * $cellwidth + ($cellwidth - $pos->width) / 2 + $pos->ofsx; | |
|             $pos->y = $board->footery + $y * $cellheight + ($cellheight - $pos->height) / 2 + $pos->ofsy; | |
|             $pos->x = round( $pos->x); | |
|             $pos->y = round( -$pos->y); | |
|             break; | |
|     } | |
|  | |
|     return $pos; | |
| } | |
|  | |
| /** | |
|  * Computes next question. | |
|  * | |
|  * @param stdClass $game | |
|  * @param stdClass $snakes | |
|  * @param stdClass $query | |
|  */ | |
| function game_snakes_computenextquestion( $game, &$snakes, &$query) { | |
|     global $DB, $USER; | |
|  | |
|     // Retrieves CONST_GAME_TRIES_REPETITION words and select the one which is used fewer times. | |
|     if (($recs = game_questions_selectrandom( $game, 1, CONST_GAME_TRIES_REPETITION)) == false) { | |
|         return false; | |
|     } | |
|  | |
|     $glossaryid = 0; | |
|     $questionid = 0; | |
|     $minnum = 0; | |
|     $query = new stdClass(); | |
|     foreach ($recs as $rec) { | |
|         $a = array( 'gameid' => $game->id, 'userid' => $USER->id, | |
|                 'questionid' => $rec->questionid, 'glossaryentryid' => $rec->glossaryentryid); | |
|         if (($rec2 = $DB->get_record('game_repetitions', $a, 'id,repetitions AS r')) != false) { | |
|             if (($rec2->r < $minnum) or ($minnum == 0)) { | |
|                 $minnum = $rec2->r; | |
|                 $query->glossaryentryid = $rec->glossaryentryid; | |
|                 $query->questionid = $rec->questionid; | |
|             } | |
|         } else { | |
|             $query->glossaryentryid = $rec->glossaryentryid; | |
|             $query->questionid = $rec->questionid; | |
|             break; | |
|         } | |
|     } | |
|  | |
|     if (($query->glossaryentryid == 0) and ($query->questionid == 0)) { | |
|         return false; | |
|     } | |
|     $query->gamekind = $game->gamekind; | |
|     $query->attemptid = $snakes->id; | |
|     $query->gameid = $game->id; | |
|     $query->userid = $USER->id; | |
|     $query->sourcemodule = $game->sourcemodule; | |
|     $query->score = 0; | |
|     $query->timelastattempt = time(); | |
|     if (!($query->id = $DB->insert_record( 'game_queries', $query))) { | |
|         print_error( "Can't insert to table game_queries"); | |
|     } | |
|  | |
|     $snakes->queryid = $query->id; | |
|  | |
|     $updrec = new stdClass(); | |
|     $updrec->id = $snakes->id; | |
|     $updrec->queryid = $query->id; | |
|     $updrec->dice = $snakes->dice = rand( 1, 6); | |
|  | |
|     if (!$DB->update_record( 'game_snakes', $updrec)) { | |
|         print_error( 'game_questions_selectrandom: error updating in game_snakes'); | |
|     } | |
|  | |
|     game_update_repetitions($game->id, $USER->id, $query->questionid, $query->glossaryentryid); | |
|  | |
|     return true; | |
| } | |
|  | |
| /** | |
|  * Shows the question. | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $game | |
|  * @param stdClass $snakes | |
|  * @param stdClass $query | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_showquestion( $id, $game, $snakes, $query, $context) { | |
|     if ($game->sourcemodule == 'glossary') { | |
|         game_snakes_showquestion_glossary( $id, $snakes, $query, $game); | |
|     } else { | |
|         game_snakes_showquestion_question( $game, $id, $snakes, $query, $context); | |
|     } | |
| } | |
|  | |
| /** | |
|  * Shows the question. | |
|  * | |
|  * @param stdClass $game | |
|  * @param int $id | |
|  * @param stdClass $snakes | |
|  * @param stdClass $query | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_showquestion_question( $game, $id, $snakes, $query, $context) { | |
|     global $CFG; | |
|  | |
|     $questionlist = $query->questionid; | |
|     $questions = game_sudoku_getquestions( $questionlist); | |
|  | |
|     // Start the form. | |
|     echo "<form id=\"responseform\" method=\"post\" ". | |
|         "action=\"{$CFG->wwwroot}/mod/game/attempt.php\" onclick=\"this.autocomplete='off'\">\n"; | |
|     echo "<center><input type=\"submit\" name=\"finishattempt\" value=\"".get_string('sudoku_submit', 'game')."\"></center>\n"; | |
|  | |
|     // Add a hidden field with the quiz id. | |
|     echo '<input type="hidden" name="id" value="' . s($id) . "\" />\n"; | |
|     echo '<input type="hidden" name="action" value="snakescheck" />'; | |
|     echo '<input type="hidden" name="queryid" value="' . $query->id . "\" />\n"; | |
|  | |
|     // Print all the questions. | |
|     foreach ($questions as $question) { | |
|         game_print_question( $game, $question, $context); | |
|     } | |
|     // Add a hidden field with questionids. | |
|     echo '<input type="hidden" name="questionids" value="'.$questionlist."\" />\n"; | |
|  | |
|     echo "</form>\n"; | |
| } | |
|  | |
| /** | |
|  * Show a glossary question. | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $snakes | |
|  * @param stdClass $query | |
|  * @param stdClass $game | |
|  */ | |
| function game_snakes_showquestion_glossary( $id, $snakes, $query, $game) { | |
|     global $CFG, $DB; | |
|  | |
|     $entry = $DB->get_record( 'glossary_entries', array('id' => $query->glossaryentryid)); | |
|  | |
|     // Start the form. | |
|     echo "<form id=\"responseform\" method=\"post\" ". | |
|         "action=\"{$CFG->wwwroot}/mod/game/attempt.php\" onclick=\"this.autocomplete='off'\">\n"; | |
|     echo "<center><input type=\"submit\" name=\"finishattempt\" value=\"".get_string('sudoku_submit', 'game')."\"></center>\n"; | |
|  | |
|     // Add a hidden field with the queryid. | |
|     echo '<input type="hidden" name="id" value="' . s($id) . "\" />\n"; | |
|     echo '<input type="hidden" name="action" value="snakescheckg" />'; | |
|     echo '<input type="hidden" name="queryid" value="' . $query->id . "\" />\n"; | |
|  | |
|     // Print all the questions. | |
|  | |
|     // Add a hidden field with glossaryentryid. | |
|     echo '<input type="hidden" name="glossaryentryid" value="'.$query->glossaryentryid."\" />\n"; | |
|  | |
|     $cmglossary = get_coursemodule_from_instance('glossary', $game->glossaryid, $game->course); | |
|     $contextglossary = game_get_context_module_instance( $cmglossary->id); | |
|     $s = game_filterglossary(str_replace( '\"', '"', $entry->definition), $query->glossaryentryid, | |
|         $contextglossary->id, $game->course); | |
|     echo $s.'<br>'; | |
|  | |
|     echo get_string( 'answer').': '; | |
|     echo "<input type=\"text\" name=\"answer\" size=30 /><br>"; | |
|  | |
|     echo "</form>\n"; | |
| } | |
|  | |
| /** | |
|  * Checks if answer is correct. | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $game | |
|  * @param stdClass $attempt | |
|  * @param stdClass $snakes | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_check_questions( $id, $game, $attempt, $snakes, $context) { | |
|     global $CFG, $DB; | |
|  | |
|     $responses = data_submitted(); | |
|  | |
|     if ($responses->queryid != $snakes->queryid) { | |
|         game_snakes_play( $id, $game, $attempt, $snakes, $context); | |
|         return; | |
|     } | |
|  | |
|     $questionlist = $DB->get_field( 'game_queries', 'questionid', array( 'id' => $responses->queryid)); | |
|  | |
|     $questions = game_sudoku_getquestions( $questionlist); | |
|     $correct = false; | |
|     $query = ''; | |
|     foreach ($questions as $question) { | |
|         $query = new stdClass(); | |
|         $query->id = $snakes->queryid; | |
|  | |
|         $grade = game_grade_responses( $question, $responses, 100, $answertext, $answered); | |
|         if ($grade < 99) { | |
|             // Wrong answer. | |
|             game_update_queries( $game, $attempt, $query, 0, $answertext); | |
|             continue; | |
|         } | |
|  | |
|         // Correct answer. | |
|         $correct = true; | |
|  | |
|         game_update_queries( $game, $attempt, $query, 1, ''); | |
|     } | |
|  | |
|     // Set the grade of the whole game. | |
|     game_snakes_position( $id, $game, $attempt, $snakes, $correct, $query, $context); | |
| } | |
|  | |
| /** | |
|  * Checks if the glossary answer is correct. | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $game | |
|  * @param stdClass $attempt | |
|  * @param stdClass $snakes | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_check_glossary( $id, $game, $attempt, $snakes, $context) { | |
|     global $CFG, $DB; | |
|  | |
|     $responses = data_submitted(); | |
|  | |
|     if ($responses->queryid != $snakes->queryid) { | |
|         game_snakes_play( $id, $game, $attempt, $snakes, $context); | |
|         return; | |
|     } | |
|  | |
|     $query = $DB->get_record( 'game_queries', array( 'id' => $responses->queryid)); | |
|  | |
|     $glossaryentry = $DB->get_record( 'glossary_entries', array( 'id' => $query->glossaryentryid)); | |
|  | |
|     $name = 'resp'.$query->glossaryentryid; | |
|     $useranswer = $responses->answer; | |
|  | |
|     if (game_upper( $useranswer) != game_upper( $glossaryentry->concept)) { | |
|         // Wrong answer. | |
|         $correct = false; | |
|         game_update_queries( $game, $attempt, $query, 0, $useranswer); // Last param is grade. | |
|     } else { | |
|         // Correct answer. | |
|         $correct = true; | |
|  | |
|         game_update_queries( $game, $attempt, $query, 1, $useranswer); // Last param is grade. | |
|     } | |
|  | |
|     // Set the grade of the whole game. | |
|     game_snakes_position( $id, $game, $attempt, $snakes, $correct, $query, $context); | |
| } | |
|  | |
| /** | |
|  * Computes the position. | |
|  * | |
|  * @param int $id | |
|  * @param stdClass $game | |
|  * @param stdClass $attempt | |
|  * @param stdClass $snakes | |
|  * @param boolean $correct | |
|  * @param stdClasss $query | |
|  * @param stdClass $context | |
|  */ | |
| function game_snakes_position( $id, $game, $attempt, $snakes, $correct, $query, $context) { | |
|     global $DB; | |
|  | |
|     $data = $DB->get_field( 'game_snakes_database', 'data', array( 'id' => $snakes->snakesdatabaseid)); | |
|  | |
|     if ($correct) { | |
|         if (($next = game_snakes_foundlander( $snakes->position + $snakes->dice, $data))) { | |
|             $snakes->position  = $next; | |
|         } else { | |
|             $snakes->position  = $snakes->position + $snakes->dice; | |
|         } | |
|     } else { | |
|         if (($next = game_snakes_foundsnake( $snakes->position, $data))) { | |
|             $snakes->position  = $next; | |
|         } | |
|     } | |
|  | |
|     $updrec = new stdClass(); | |
|     $updrec->id = $snakes->id; | |
|     $updrec->position = $snakes->position; | |
|     $updrec->queryid = 0; | |
|  | |
|     if (!$DB->update_record( 'game_snakes', $updrec)) { | |
|         print_error( "game_snakes_position: Can't update game_snakes"); | |
|     } | |
|  | |
|     $board = $DB->get_record_select( 'game_snakes_database', "id=$snakes->snakesdatabaseid"); | |
|     $gradeattempt = $snakes->position / ($board->usedcols * $board->usedrows); | |
|     $finished = ( $snakes->position > $board->usedcols * $board->usedrows ? 1 : 0); | |
|  | |
|     game_updateattempts( $game, $attempt, $gradeattempt, $finished); | |
|  | |
|     game_snakes_computenextquestion( $game, $snakes, $query); | |
|  | |
|     game_snakes_play( $id, $game, $attempt, $snakes, $context); | |
| } | |
|  | |
| /** | |
|  * In lander go forward. | |
|  * | |
|  * @param int $position | |
|  * @param string $data | |
|  */ | |
| function game_snakes_foundlander( $position, $data) { | |
|     preg_match( "/L$position-([0-9]*)/", $data, $matches); | |
|  | |
|     if (count( $matches)) { | |
|         return $matches[ 1]; | |
|     } | |
|  | |
|     return 0; | |
| } | |
|  | |
| /** | |
|  * In snake go backward. | |
|  * | |
|  * @param int $position | |
|  * @param string $data | |
|  */ | |
| function game_snakes_foundsnake( $position, $data) { | |
|     preg_match( "/S([0-9]*)-$position,/", $data.',', $matches); | |
|  | |
|     if (count( $matches)) { | |
|         return $matches[ 1]; | |
|     } | |
|  | |
|     return 0; | |
| } | |
|  | |
| /** | |
|  * Removes attempt data. | |
|  * | |
|  * @param int $questionusageid | |
|  * @param int $questionid | |
|  */ | |
| function game_snakes_remove_attemptdata ($questionusageid, $questionid) { | |
|     global $DB; | |
|  | |
|     $sql = "SELECT qas.id | |
|               FROM mdl_question_attempts qa | |
|          LEFT JOIN mdl_question_attempt_steps qas | |
|                 ON qa.id=qas.questionattemptid | |
|              WHERE questionusageid = $questionusageid | |
|                AND questionid = $questionid | |
|                AND state != 'todo'"; | |
|  | |
|     if ($stepdata = $DB->get_records_sql($sql)) { | |
|         foreach ($stepdata as $step) { | |
|             if ($step->id > 0) { | |
|                 $DB->delete_records('question_attempt_step_data', array('attemptstepid' => $step->id)); | |
|                 $DB->get_records_sql("update {question_attempt_steps} set state='todo' where id = {$step->id}"); | |
|             } | |
|         } | |
|     } | |
| }
 | |
| 
 |