When I started out programming one bit of advice I received that stayed with me was this:
After writing your first draft and getting a working program running, delete all the files and begin again. You will most likely get a much better program the second time around.
Unfortunatly we usually do not have the luxury of time when writing programs.
However programming is writing and how many of us would want our first drafts distributed? Revision is a key component to writing good programs. I hope to return to this code in the comming weeks and posting the revisions. I have always found it an interesting exercise to compare the revisions of a program.
;; Called when the project is first loaded. ;; Sets up the global variables we need. to startup make "maxHr 12 am.pmClicked end ;; ;; Called each time the start button is pressed. ;; Checks the text boxes to make sure there is ;; something in them. to start dolist [n [hr min sec]] [ talkto :n let [ t parse get :n "text] ifelse empty? :t [ insert "00 ] [ if (count get :n "text) > 2 [ sol ct insert first :t ] if not (count first :t) = 2 [ sol ct insert word "0 first :t ] ] ] ifelse checkDigits = "ok [runClock] [stop] end ;; ;; The main loop. MicroWorlds wait instruction takes one argument ;; which is the number of tenths of a second to wait. We wait for one ;; second and then update the digits. Then we start again. to runClock wait 10 doSec runClock end ;; ;; Check the seconds digits. If the next second is 60 we rollover ;; the seconds and check the minutes. The extra check for less than 10 ;; is to correctly format the display. to doSec let [t sec + 1] sec, sol ct ifelse :t < 60 [ ifelse :t < 10 [ insert word "0 :t ][ insert :t ] ][ insert "00 doMin ] end ;; ;; If the seconds rolled over increase the minute digit. ;; If the minutes rollover check the hour. to doMin let [t min + 1] min, sol ct ifelse :t < 60 [ ifelse :t < 10 [ insert word "0 :t ][ insert :t ] ][ insert "00 doHr ] end ;; ;; If the minutes rolled over we increase and check the hour digits. A lot of the complexity ;; here is because of the dual format, AM/PM or 24 hour, display. MaxHr holds the ;; maximum value for the hour digit depending on the mode. FirstHr holds the starting ;; hour digit depending on the mode. to doHr let [t hr + 1] hr, sol ct ifelse :t < (:maxHr + 1) [ ifelse :t < 10 [ insert word "0 :t ][ insert :t ] if and (not (:maxHr = 23)) (:t = 12) ;; If in am/pm mode and the time is 12 ;; change the am/pm indicator. [ ifelse :isAm = "true [ ;; it's now morning make it pm am, setsh "ampmOff pm, setsh "amPmOn make "isAM "false ][ ;; it's now night make it am am, setsh "ampmOn pm, setsh "ampmOff make "isAm "true ] ] ][ insert word "0 :firstHr ] end ;; ;; We check all boxes before reporting any errors. ;; This way the user can correct them all at once. ;; Lot's more possile in the way of error checking here. to checkDigits let [bh " bm " bs "] if or (hr < 0) (hr > :maxHr) [make "bh "hour,] if or (min < 0) (min > 59) [make "bm "minute,] if or (sec < 0) (sec > 59) [make "bs "second,] if (or (:bh = "hour,) (:bm = "minute,) (:bs = "second,)) [errMsg :bh :bm :bs op "false] op "ok end to errMsg :bh :bm :bs announce (se [The time format you entered is not correct. Check the format of the ] :bh :bm :bs [then correct and restart.] end ;; ;; The 24 hour mode checkbox was clicked. ;; Set the hour depending on if it's am or pm. to 24clicked make "maxHr 23 make "firstHr 0 ifelse (hr = 12) [ if :isAM = "true [ hr, sol ct insert "00 ] ] [ if (:isAm = "false) ;; it's pm, add 12 to the hour. ;; ie: 11:00 pm is 23:00 hours. [ let [t (hr + 12)] hr, sol ct insert :t ] ] setshape "chkboxchked am.pm, setshape "chkbox am, setsh "ampmOff pm, setsh "ampmOff end ;; ;; The AM/PM checkbox was clicked. ;; Set the am/pm indicator depending on the hour. to am.pmClicked make "isAm "true if (hr = 12) [ make "isAm "false ] if (hr = "00) [ hr, sol ct insert "12 make "isAm "true ] if (hr > 12) [ let [t (hr - 12)] if (:t < 10) [make "t word "0 :t] hr, sol ct insert :t make "isAm "false ] am.pmSet end ;; ;; Set the radio buttons and checkboxes to the right shapes. to am.pmSet make "maxHr 12 make "firstHr 1 am.pm, setshape "chkboxchked 24hr, setshape "chkbox ifelse (:isAm = "true) [ am, setsh "ampmOn pm, setsh "ampmOff ][ pm, setsh "ampmOn am, setsh "ampmOff ] end ;; ;; The am radio button was clicked. ;; If we're in 24 hour mode (maxHr = 23) ignore it. to amClicked if (:maxHr = 23) [stop] make "isAm "true am.pmSet end ;; ;; The pm radio button was clicked. ;; If we're in 24 hour mode (maxHr = 23) ignore it. to pmClicked if (:maxHr = 23) [stop] make "isAm "false am.pmSet end ;; ;; Only used to layout the clock first time. ;; to makeClock newtext "hr [-368 206] [50 45] set "hr "showname? "false newtext "min [-305 206] [50 45] set "min "showname? "false newtext "sec [-244 206] [50 45] set "sec "showname? "false end
waitwait number Causes a pause in the execution of a program or instruction. The time is measured in 10ths of a second. Example: repeat 5 [ht wait 10 st wait 10]
timerReports a number representing the time elapsed since the program started, or since the last resett command was run. The number is in tenths of a second. Example: resett Wait a little. show timer 22 The next procedure displays a question just after resetting the timer. If you got the right answer, it tells you how fast you were at typing it. The value of the timer is divided by ten in order to get the value in seconds. to reflex resett question [What is 12 times 12?] ifelse answer = 144 [announce se timer / 10 "sec] [announce [Wrong answer]] end
resettStands for reset timer. Resets the timer to 0. The timer starts when you start up MicroWorlds. See timer. Example: resett show timer 0 The next procedure displays a question just after resetting the timer. If you got the right answer, it tells you how fast you were at typing it. The time is in tenths of a second. to reflex resett let [num1 1 + random 10 num2 1 + random 10] question (se [What is] :num1 [times] :num2 [?]) ifelse answer = :num1 * :num2 [announce se timer / 10 "sec] [announce [Wrong answer]] end