#!/usr/bin/wish wm title . "Sums: level 1" # sums # # Written by and copyright Neil Smith ( neil@wimp.freeuk.com ) # Version 1.0, 8 August 2005 # # A GUI script that generates sums, with different difficulty levels. # # # # To use this program, ensure Tcl/Tk is installed, and make this file # executable. Then run this program. # # # This program 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 2 of the License, or # (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA or the Free Software Foundation Europe e.V., # Villa Vogelsang, Antonienallee 1, 45279 Essen, Germany # # For more details, see http://www.gnu.org/ # For the text of the GPL, see http://www.gnu.org/licenses/gpl.txt global answer score maxscore minscore currentLevel effectiveLevel maxlevel set answer "" set score 0 # Score needed to progress to the next level set maxscore 5 set minscore 0 # The level that's displayed set currentLevel 1 # The level of difficulty that being used set effectiveLevel 1 # The maximum value for effectiveLevel set maxlevel 3 array set operators {0 "+" 1 "-" 2 "*" 3 "/"} # Description of each level. Modify the contents of this array to change how # the program generates new problems at each level # operatorRange: operator is in the first n # sumOperandRange: operands in range [1, n] inclusive for addition and subtraction # productOperandsRange: operands in range [1, n] inclusive for multiplication and division # negativeAnswers: whether subtraction questions can have negative answers # zeroOperands: whether the operands can be zero set level(1,operatorRange) 2 set level(1,sumOperandRange) 10 set level(1,productOperandRange) 10 set level(1,negativeAnswers) False set level(1,zeroOperands) False set level(2,operatorRange) 2 set level(2,sumOperandRange) 10 set level(2,productOperandRange) 10 set level(2,negativeAnswers) False set level(2,zeroOperands) True set level(3,operatorRange) 2 set level(3,sumOperandRange) 20 set level(3,productOperandRange) 10 set level(3,negativeAnswers) False set level(3,zeroOperands) True set level(4,operatorRange) 2 set level(4,sumOperandRange) 50 set level(4,productOperandRange) 10 set level(4,negativeAnswers) True set level(4,zeroOperands) True set level(5,operatorRange) 3 set level(5,sumOperandRange) 100 set level(5,productOperandRange) 10 set level(5,negativeAnswers) True set level(5,zeroOperands) True set level(6,operatorRange) 4 set level(6,sumOperandRange) 100 set level(6,productOperandRange) 20 set level(6,negativeAnswers) True set level(6,zeroOperands) True # Create the GUI frame .toppadding frame .bottompadding frame .sumf frame .sumf.leftpadding frame .sumf.rightpadding label .sumf.operand1 -text "" -font {verdana 16} -width 4 -justify right label .sumf.operator -text "" -font {verdana 16} -width 1 label .sumf.operand2 -text "" -font {verdana 16} -width 2 label .sumf.eq -text "=" -font {verdana 16} entry .sumf.answer -textvariable answer -width 6 -font {verdana 16} frame .scoref frame .scoref.leftpadding frame .scoref.rightpadding # Create a disabled check button for each possible score value for {set i 1} {$i <= $maxscore} {incr i} { checkbutton ".scoref.score$i" -variable "score$i" -state disabled } frame .buttonframe frame .buttonframe.leftpadding # button .buttonframe.newbutton -text "New" -command new -font {verdana 16} button .buttonframe.checkbutton -text "Check" -command check -font {verdana 16} button .buttonframe.closebutton -text "Close" -command "destroy ." -font {verdana 16} frame .buttonframe.rightpadding pack .toppadding -side top -expand true -fill both pack .sumf -side top pack .sumf.leftpadding -side left -expand true -fill both pack .sumf.operand1 .sumf.operator .sumf.operand2 .sumf.eq .sumf.answer -side left pack .sumf.rightpadding -side left -expand true -fill both pack .scoref -side top pack .scoref.leftpadding -side left -expand true -fill both for {set i 1} {$i <= $maxscore} {incr i} { pack ".scoref.score$i" -side left } pack .scoref.rightpadding -side left -expand true -fill both pack .buttonframe -side top pack .buttonframe.leftpadding -side left -expand true -fill both # pack .buttonframe.newbutton pack .buttonframe.checkbutton .buttonframe.closebutton -side left pack .buttonframe.rightpadding -side left -expand true -fill both pack .bottompadding -side top -expand true -fill both # Bind return key to check the answer bind .sumf.answer {check} bind .sumf.answer {check} # Check the answer given in ::answer proc check {} { # Calculate the real answer set realAnswer [expr [.sumf.operand1 cget -text] [.sumf.operator cget -text] [.sumf.operand2 cget -text] ] # Compare the given answer to the real answer and adjust the score if {$::answer == $realAnswer} { set ::score [expr {$::score + 1}] } else { set ::score [expr $::score - 1] } # Reset the score indicator for {set i 1} {$i <= $::maxscore} {incr i} { if {$::score >= $i} {set "::score$i" 1} else {set "::score$i" 0} } # If they exceed the maxscore, they go up a level if {$::score >= $::maxscore} { set ::score $::minscore if {$::effectiveLevel < $::maxlevel} { set ::effectiveLevel [expr $::effectiveLevel + 1] } set ::currentLevel [expr $::currentLevel + 1] tk_messageBox -message "Well done!\nNow try level $::currentLevel" -title "Sums" -type ok wm title . "Sums level $::currentLevel" } elseif {$::score < $::minscore} { # if they drop below the minimum score, they go down a level set ::score $::minscore if {$::effectiveLevel == 1} { tk_messageBox -message "Perhaps you ought\nto ask for some help" -title "Sums" -type ok } else { set ::currentLevel [expr $::currentLevel - 1] if {$::currentLevel > $::maxlevel} { set ::effectiveLevel $::maxlevel } else { set ::effectiveLevel $::currentLevel } tk_messageBox -message "Too hard.\nWould level $::currentLevel be easier?" -title "Sums" -type ok wm title . "Sums level $::currentLevel" new } } # Reset the score indicator again, to reflect a possible change in level (and hence score) for {set i 1} {$i <= $::maxscore} {incr i} { if {$::score >= $i} {set "::score$i" 1} else {set "::score$i" 0} } # If the answer was correct, set a new question if {$::answer == $realAnswer} { new } else { set ::answer "" } } # Set a new question proc new {} { # Choose a random operator set operator $::operators([expr int(rand()*$::level($::effectiveLevel,operatorRange))]) if {[string equal $operator "+"] || [string equal $operator "-"]} { if {$::level($::effectiveLevel,zeroOperands)} { set operand1 [expr int(rand()*($::level($::effectiveLevel,sumOperandRange)+1))] set operand2 [expr int(rand()*($::level($::effectiveLevel,sumOperandRange)+1))] } else { set operand1 [expr int(rand()*$::level($::effectiveLevel,sumOperandRange)) + 1] set operand2 [expr int(rand()*$::level($::effectiveLevel,sumOperandRange)) + 1] } if {[string equal $operator "-"] && [expr $operand1 < $operand2] && (!$::level($::effectiveLevel,negativeAnswers))} { set temp $operand1 set operand1 $operand2 set operand2 $temp } } elseif {[string equal $operator "*"]} { if {$::level($::effectiveLevel,zeroOperands)} { set operand1 [expr int(rand()*($::level($::effectiveLevel,productOperandRange)+1))] set operand2 [expr int(rand()*($::level($::effectiveLevel,productOperandRange)+1))] } else { set operand1 [expr int(rand()*$::level($::effectiveLevel,productOperandRange)) + 1] set operand2 [expr int(rand()*$::level($::effectiveLevel,productOperandRange)) + 1] } } else { set operand2 [expr int(rand()*$::level($::effectiveLevel,productOperandRange)) + 1] if {$::level($::effectiveLevel,zeroOperands)} { set answer [expr int(rand()*($::level($::effectiveLevel,productOperandRange)+1))] } else { set answer [expr int(rand()*$::level($::effectiveLevel,productOperandRange)) + 1] } set operand1 [expr $operand2 * $answer] } .sumf.operator configure -text $operator .sumf.operand1 configure -text $operand1 .sumf.operand2 configure -text $operand2 set ::answer "" } # Start by setting a new question new focus .sumf.answer