# # find Easter for a given year # # a Limbo version of a program in the Informal Introduction to Algol68 implement Easter; include "sys.m"; sys: Sys; include "draw.m"; include "daytime.m"; daytime: Daytime; include "string.m"; str: String; Easter: module { init: fn(nil: ref Draw->Context, nil: list of string); }; stderr: ref Sys->FD; init(nil: ref Draw->Context, args: list of string) { year: int; sys = load Sys Sys->PATH; daytime = load Daytime Daytime->PATH; str = load String String->PATH; sys->pctl(Sys->NEWPGRP|Sys->FORKFD, nil); stderr = sys->fildes(2); if(len args <= 1) { lp := daytime->local(daytime->now()); year = 1900 + lp.year; if(lp.mon > 3) year++; # after April? next year } else { (s, t) := str->splitr(hd tl args, "0-9"); if(s == "" || t != ""){ sys->fprint(stderr, "Usage: easter [year]\n"); exit; } year = int s; } findeaster(year); } # See: # Christophorus Clavius. Kalendarium Gregorianum Perpetuum. # Cum Privilegio Summi Pontificis Et Aliorum Principum. # Romae, Ex Officina Dominicae Basae. MDLXXXII. # Cum Licentia Superiorum. (with attached Papal Bull). # GREGORY: con 1752; # date Gregorian calendar started in Great Britain and Colonies, after Easter findeaster(year: int) { if(year <= GREGORY){ sys->fprint(stderr, "easter: year %d predates adoption of Gregorian calendar in Great Britain\n", year); exit; } century := year/100; leap := year%4==0 && year%100 != 0 || year%400 == 0; if(leap) sys->print("%d leap year\n", year); else sys->print("%d\n", year); dominic := 7 - day(year+year/4 - century+century/4-1-leap); sys->print("The Dominical Letter is %c%s\n", "ABCDEFG"[dominic-1], (array[] of {"", "/A", "/B", "/C", "/D", "/E", "/F", "/G"})[leap*(day(dominic-2)+1)]); golden := year%19 + 1; sys->print("The golden number is %d\n", golden); lilius := mod(century-century/4-(century-(century-17)/25)/3-8, 30); epact := mod(11*(golden-1)-lilius, 30); sys->print("The epact is %d\n", epact); moon := 31 - epact + 59 + leap; Paschal := moon+13; march21st := 31+28+leap+21; if(Paschal < march21st) { clavius := 25; if(golden > 11) clavius = 26; if(epact >= clavius) moon += 30; else moon += 29; Paschal = moon+13; } sys->print("The Paschal full moon falls upon %s %s\n", weekday(day(Paschal - dominic)), day2date(Paschal, leap)); easter := Paschal+7-day(Paschal-dominic); sys->print("Easter day being the next Sunday after the Paschal full moon,\n"); sys->print("therefore falls upon %s\n", day2date(easter, leap)); } weekday(n: int): string { return (array [] of {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"})[n]; } day(n: int): int { return mod(n, 7); } mod(a, b: int): int { c := a%b; if(c < 0) return c+b; return c; } day2date(dayno, leapyr: int): string { feb := 28; if(leapyr) feb = 29; map := array[] of { ("January", 31), ("February", feb), ("March", 31), ("April", 30), ("May", 31), ("June", 30), ("July", 31), ("August", 31), ("September", 30), ("October", 31), ("November", 30), ("December", 31), }; for(i := 0; i < len map; i++) { (name, days) := map[i]; if(dayno <= days) return sys->sprint("%s %d", name, dayno); else dayno -= days; } return nil; }