Support for parsing and printing times of day.
- §1. Conversion To Number
- §2. Digital Printing
- §3. Analogue Printing
- §4. Understanding
- §5. Relative Time Token
- §6. Scene Change Machinery Rule
- §7. During Scene Matching
- §8. Scene Questions
[ NUMBER_TY_to_TIME_TY n; return CongruenceClass(n, 1440); ];
§2. Digital Printing. For instance, "2:06 am".
[ PrintTimeOfDay t h aop; if (t<0) { print "<no time>"; return; } if (t >= TWELVE_HOURS) { aop = "pm"; t = t - TWELVE_HOURS; } else aop = "am"; h = t/ONE_HOUR; if (h==0) h=12; print h, ":"; if (t%ONE_HOUR < 10) print "0"; print t%ONE_HOUR, " ", (string) aop; ]; [ PrintDuration t h m; if (t<0) { print "minus "; t = -t; } h = t/ONE_HOUR; m = t%ONE_HOUR; if (h > 0) print h, " hour"; if (h > 1) print "s"; if (h > 0) print " "; if (m == 1) print "1 minute"; else if ((h == 0) || (m > 0)) print m, " minutes"; ];
§3. Analogue Printing. For instance, "six minutes past two".
[ PrintTimeOfDayEnglish t h m dir aop; h = (t/ONE_HOUR) % 12; m = t%ONE_HOUR; if (h==0) h=12; if (m==0) { print (number) h, " o'clock"; return; } dir = "past"; if (m > HALF_HOUR) { m = ONE_HOUR-m; h = (h+1)%12; if (h==0) h=12; dir = "to"; } switch(m) { QUARTER_HOUR: print "quarter"; HALF_HOUR: print "half"; default: print (number) m; if (m%5 ~= 0) { if (m == 1) print " minute"; else print " minutes"; } } print " ", (string) dir, " ", (number) h; ];
§4. Understanding. This I6 grammar token converts words in the player's command to a valid I7 time, and is heavily based on the one presented as a solution to an exercise in the DM4.
[ TIME_TOKEN first_word second_word at length flag illegal_char offhour hr mn i original_wn ch; original_wn = wn; i = TIME_TOKEN_INNER(); if (i ~= GPR_FAIL) return i; wn = original_wn; first_word = NextWordStopped(); switch (first_word) { 'midnight': parsed_number = 0; return GPR_NUMBER; 'midday', 'noon': parsed_number = TWELVE_HOURS; return GPR_NUMBER; } Next try the format 12:02 at = WordAddress(wn-1); length = WordLength(wn-1); for (i=0: i<length: i++) { #iftrue (CHARSIZE == 1); ch = at->i; #Ifnot; ch = at-->i; #Endif; CHARSIZE switch (ch) { ':': if (flag == false && i>0 && i<length-1) flag = true; else illegal_char = true; '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': ; default: illegal_char = true; } } if (length < 3 || length > 5 || illegal_char) flag = false; if (flag) { #iftrue (CHARSIZE == 1); for (i=0: at->i~=':': i++, hr=hr*10) hr = hr + at->i - '0'; #Ifnot; for (i=0: at-->i~=':': i++, hr=hr*10) hr = hr + at-->i - '0'; #Endif; CHARSIZE hr = hr/10; #iftrue (CHARSIZE == 1); for (i++: i<length: i++, mn=mn*10) mn = mn + at->i - '0'; #Ifnot; for (i++: i<length: i++, mn=mn*10) mn = mn + at-->i - '0'; #Endif; CHARSIZE mn = mn/10; second_word = NextWordStopped(); parsed_number = HoursMinsWordToTime(hr, mn, second_word); if (parsed_number == -1) return GPR_FAIL; if (second_word ~= 'pm' or 'am') wn--; return GPR_NUMBER; } Lastly the wordy format offhour = -1; if (first_word == 'half') offhour = HALF_HOUR; if (first_word == 'quarter') offhour = QUARTER_HOUR; if (offhour < 0) offhour = TryNumber(wn-1); if (offhour < 0 || offhour >= ONE_HOUR) return GPR_FAIL; second_word = NextWordStopped(); switch (second_word) { "six o'clock", "six" 'o^clock', 'am', 'pm', -1: hr = offhour; if (hr > 12) return GPR_FAIL; "quarter to six", "twenty past midnight" 'to', 'past': mn = offhour; hr = TryNumber(wn); if (hr <= 0) { switch (NextWordStopped()) { 'noon', 'midday': hr = 12; 'midnight': hr = 0; default: return GPR_FAIL; } } if (hr >= 13) return GPR_FAIL; if (second_word == 'to') { mn = ONE_HOUR-mn; hr--; if (hr<0) hr=23; } wn++; second_word = NextWordStopped(); "six thirty" default: hr = offhour; mn = TryNumber(--wn); if (mn < 0 || mn >= ONE_HOUR) return GPR_FAIL; wn++; second_word = NextWordStopped(); } parsed_number = HoursMinsWordToTime(hr, mn, second_word); if (parsed_number < 0) return GPR_FAIL; if (second_word ~= 'pm' or 'am' or 'o^clock') wn--; return GPR_NUMBER; ]; [ HoursMinsWordToTime hour minute word x; if (hour >= 24) return -1; if (minute >= ONE_HOUR) return -1; x = hour*ONE_HOUR + minute; if (hour >= 13) return x; x = x % TWELVE_HOURS; if (word == 'pm') x = x + TWELVE_HOURS; if (word ~= 'am' or 'pm' && hour == 12) x = x + TWELVE_HOURS; return x; ];
§5. Relative Time Token. "Time" is an interesting kind of value since it can hold two conceptually different ways of thinking about time: absolute times, such as "12:03 PM", and also relative times, like "ten minutes". For parsing purposes, these are completely different from each other, and the time token above handles only absolute times; we need the following for relative ones.
[ RELATIVE_TIME_TOKEN first_word second_word offhour mult mn original_wn; original_wn = wn; wn = original_wn; first_word = NextWordStopped(); wn--; if (first_word == 'an' or 'a//') mn=1; else mn=TryNumber(wn); if (mn == -1000) { first_word = NextWordStopped(); if (first_word == 'half') offhour = HALF_HOUR; if (first_word == 'quarter') offhour = QUARTER_HOUR; if (offhour > 0) { second_word = NextWordStopped(); if (second_word == 'of') second_word = NextWordStopped(); if (second_word == 'an') second_word = NextWordStopped(); if (second_word == 'hour') { parsed_number = offhour; return GPR_NUMBER; } } return GPR_FAIL; } wn++; first_word = NextWordStopped(); switch (first_word) { 'minutes', 'minute': mult = 1; 'hours', 'hour': mult = 60; default: return GPR_FAIL; } parsed_number = mn*mult; if (mult == 60) { mn=TryNumber(wn); if (mn ~= -1000) { wn++; first_word = NextWordStopped(); if (first_word == 'minutes' or 'minute') parsed_number = parsed_number + mn; else wn = wn - 2; } } return GPR_NUMBER; ];
§6. Scene Change Machinery Rule.
[ SCENE_CHANGE_MACHINERY_R; DetectSceneChange(); ];
[ DuringSceneMatching prop sc; for (sc=0: sc<NUMBER_SCENES_CREATED: sc++) if ((scene_status-->sc == 1) && (prop(sc+1))) rtrue; rfalse; ];
[ SceneUtility sc task; if (sc <= 0) return 0; if (task == 1 or 2) { if (scene_endings-->(sc-1) == 0) { IssueRTP("SceneHasNotStarted", "The scene has not started.", WorldModelKitRTPs); print "*** The scene in question is ", (PrintSceneName) sc, ".^"; rtrue; } } else { if (scene_endings-->(sc-1) <= 1) { IssueRTP("SceneHasNotEnded", "The scene has not ended.", WorldModelKitRTPs); print "*** The scene in question is ", (PrintSceneName) sc, ".^"; rtrue; } } switch (task) { 1: return (TWENTY_FOUR_HOURS + the_time - scene_started-->(sc-1))%(TWENTY_FOUR_HOURS); 2: return scene_started-->(sc-1); 3: return (TWENTY_FOUR_HOURS + the_time - scene_ended-->(sc-1))%(TWENTY_FOUR_HOURS); 4: return scene_ended-->(sc-1); } ];