views:

1154

answers:

14

The Challenge

Calculate the Date of the Greek Orthodox Easter (http://www.timeanddate.com/holidays/us/orthodox-easter-day) Sunday in a given Year (1900-2100) using the least amount of characters.

Input is just a year in the form '2010'. It's not relevant where you get it (Input, CommandLineArgs etc.) but it must be dynamic!

Output should be in the form day-month-year (say dd/mm/yyyy or d/m/yyyy)

Restrictions No standard functions, such as Mathematica's EasterSundayGreekOrthodox or PHP's easter_date(), which return the (not applicable gregorian) date automatic must be used!

Examples

2005 returns 1/5/2005
2006 returns 23/4/2006
2007 returns 8/4/2007
2008 returns 27/4/2008
2009 returns 19/4/2009
2010 returns 4/4/2010
2011 returns 24/4/2011
2012 returns 15/4/2012
2013 returns 5/5/2013
2014 returns 20/4/2014
2015 returns 12/4/2015

Code count includes input/output (i.e full program).

Edit: I mean the Eastern Easter Date.

Reference: http://en.wikipedia.org/wiki/Computus

+1  A: 

COBOL, 1262 chars

WORKING-STORAGE SECTION.

01 V-YEAR       PIC S9(04) VALUE 2010.
01 V-DAY        PIC S9(02) VALUE ZERO.
01 V-EASTERDAY  PIC S9(04) VALUE ZERO.
01 V-CENTURY    PIC S9(02) VALUE ZERO.
01 V-GOLDEN     PIC S9(04) VALUE ZERO.
01 V-GREGORIAN  PIC S9(04) VALUE ZERO.
01 V-CLAVIAN    PIC S9(04) VALUE ZERO.
01 V-FACTOR     PIC S9(06) VALUE ZERO.
01 V-EPACT      PIC S9(06) VALUE ZERO.

PROCEDURE DIVISION

XX-CALCULATE EASTERDAY.

   COMPUTE V-CENTURY = (V-YEAR / 100) + 1
   COMPUTE V-GOLDEN= FUNCTION MOD(V-YEAR, 19) + 1
   COMPUTE V-GREGORIAN = (V-CENTURY * 3) / 4 - 12
   COMPUTE V-CLAVIAN
        = (V-CENTURY * 8 + 5) / 25 - 5 - V-GREGORIAN
   COMPUTE V-FACTOR
        = (V-YEAR * 5) / 4 - V-GREGORIAN - 10
   COMPUTE V-EPACT
   = FUNCTION MOD((V-GOLDEN * 11 + 20 + V-CLAVIAN), 30)

   IF V-EPACT = 24
      ADD 1 TO V-EPACT
   ELSE
      IF V-EPACT = 25
         IF V-GOLDEN > 11
            ADD 1 TO V-EPACT
         END-IF
      END-IF
   END-IF

  COMPUTE V-DAY = 44 - V-EPACT

  IF V-DAY < 21
     ADD 30 TO V-DAY
  END-IF

  COMPUTE V-DAY
  = V-DAY + 7 - (FUNCTION MOD((V-DAY + V-FACTOR), 7))

  IF V-DAY <= 31
     ADD 300 TO V-DAY GIVING V-EASTERDAY
  ELSE
     SUBTRACT 31 FROM V-DAY
     ADD 400 TO V-DAY GIVING V-EASTERDAY
  END-IF
  .
XX-EXIT.
   EXIT.

Note: Not mine, but I like it

EDIT: I added a char count with spaces but I don't know how spacing works in COBOL so I didn't change anything from original. ~vlad003

UPDATE: I've found where the OP got this code: http://www.tek-tips.com/viewthread.cfm?qid=31746&amp;page=112. I'm just putting this here because the author deserves it. ~vlad003

fredley
You should note what language/platform this is.
A. Levy
I don't think it will compile without headers. What compiler are you using?
belisarius
If it is not yours, you should tell whose it is. It might even be a copyright violation.
Andreas Rejbrand
Please cite your source. (+1 @Andreas Rejbrand)
David Thomas
A: 

BASIC, 973 chars

Sub EasterDate (d, m, y)

   Dim FirstDig, Remain19, temp    'intermediate results
   Dim tA, tB, tC, tD, tE          'table A to E results

   FirstDig = y \ 100              'first 2 digits of year
   Remain19 = y Mod 19             'remainder of year / 19

' calculate PFM date
   temp = (FirstDig - 15) \ 2 + 202 - 11 * Remain19

   Select Case FirstDig
      Case 21, 24, 25, 27 To 32, 34, 35, 38
         temp = temp - 1
      Case 33, 36, 37, 39, 40
         temp = temp - 2
   End Select
   temp = temp Mod 30

   tA = temp + 21
   If temp = 29 Then tA = tA - 1
   If (temp = 28 And Remain19 > 10) Then tA = tA - 1

'find the next Sunday
   tB = (tA - 19) Mod 7

   tC = (40 - FirstDig) Mod 4
   If tC = 3 Then tC = tC + 1
   If tC > 1 Then tC = tC + 1

   temp = y Mod 100
   tD = (temp + temp \ 4) Mod 7

   tE = ((20 - tB - tC - tD) Mod 7) + 1
   d = tA + tE

'return the date
   If d > 31 Then
      d = d - 31
      m = 4
   Else
      m = 3
   End If

End Sub

Credit: Astronomical Society of South Australia

EDIT: I added a char count but I think many spaces could be removed; I don't know BASIC so I didn't make any changes to the code. ~vlad003

fredley
Character count?
vlad003
I added it myself, but you may want to remove spaces to lower the count.
vlad003
BASIC is a hilarious programming language I have to say. What does (temp + temp \ 4) do? What is the \ operator?
tenfour
@tenfour: According to Wikipedia: "In some dialects of the BASIC programming language, the backslash is used as an operator symbol to indicate integer division."
vlad003
But this answer's kinda long with all the spaces and comments...
vlad003
+2  A: 

Delphi 377 335 317 characters

Single line:

var y,c,n,i,j,m:integer;begin Val(ParamStr(1),y,n);c:=y div 100;n:=y-19*(y div 19);i:=c-c div 4-(c-((c-17)div 25))div 3+19*n+15;i:=i-30*(i div 30);i:=i-(i div 28 )*(1-(i div 28)*(29 div(i+1))*((21 -n)div 11));j:=y+y div 4 +i+2-c+c div 4;j:=j-7*(j div 7);m:=3+(i-j+40 )div 44;Write(i-j+28-31*(m div 4),'/',m,'/',y)end.

Formatted:

var
  y,c,n,i,j,m:integer;
begin
  Val(ParamStr(1),y,n);
  c:=y div 100;
  n:=y-19*(y div 19);
  i:=c-c div 4-(c-((c-17)div 25))div 3+19*n+15;
  i:=i-30*(i div 30);
  i:=i-(i div 28 )*(1-(i div 28)*(29 div(i+1))*((21 -n)div 11));
  j:=y+y div 4 +i+2-c+c div 4;j:=j-7*(j div 7);
  m:=3+(i-j+40 )div 44; 
  Write(i-j+28-31*(m div 4),'/',m,'/',y)
end.
RRUZ
A: 

Mathematica

<<Calendar`;a=Print[#[[3]],"/",#[[2]],"/",#[[1]]]&[EasterSundayGreekOrthodox@#]&

Invoke with

a[2010]

Output

4/4/2010

Me too: I don't see the point in not using built-in functions.

belisarius
Because the point is to show how you can do it in as few keystrokes as possible not to show that your languages library has every imaginable function.
vlad003
If your language's library has every imaginable function, then you can do it in very few keystrokes.
Pie21
So, lets print without "Print", add without "+" and program without variables, just to pose other artificial restrictions that affect languages unevenly. The only way to restrict language features fairly is to propose a code-golf in only one language.
belisarius
BTW, forbid using a stack in obviously recursive problems seems to be very creative too!
belisarius
Stop crying and do it right.
M28
What does it print for 2005?
Gabe
@Gabe a[2005] printed 27/3/2005 ... now fixed .. prints 1/5/2005
belisarius
how could you complain about imposing artificial restrictions on a code golf?? it's for fun; if you're not having fun, go elsewhere.
tenfour
Perhaps this function should be added to the GolfScript standard library, since it's getting so much demand?
Novelocrat
+3  A: 

Java - 252 196 190 chars


  • Update 1: The first algo was for Western Gregorian Easter. Fixed to Eastern Julian Easter now. Saved 56 chars :)

  • Update 2: Zero padding seem to not be required. Saved 4 chars.


class E{public static void main(String[]a){long y=new Long(a[0]),b=(y%19*19+15)%30,c=b+(y%4*2+y%7*4-b+34)%7+(y>1899&y<2100?128:115),m=c/31;System.out.printf("%d/%d/%d",c%31+(m<5?0:1),m,y);}}

With newlines

class E{
 public static void main(String[]a){
  long y=new Long(a[0]),
  b=(y%19*19+15)%30,
  c=b+(y%4*2+y%7*4-b+34)%7+(y>1899&y<2100?128:115),
  m=c/31;
  System.out.printf("%d/%d/%d",c%31+(m<5?0:1),m,y);
 }
}
BalusC
*Please* tell me you didn't include the spaces in `y = new` in your golf stroke count!
Gabe
@Gabe: that was an oversight :)
BalusC
+2  A: 

JavaScript (196 characters)

Using the Meeus Julian algorithm. This implementation assumes that a valid four-digit year was given.

y=~~prompt();d=(19*(y%19)+15)%30;x=d+(2*(y%4)+4*(y%7)-d+34)%7+114;m=~~(x/31);d=x%31+1;if(y>1899&&y<2100){d+=13;if(m==3&&d>31){d-=31;m++}if(m==4&&d>30){d-=30;m++}}alert((d<10?"0"+d:d)+"/0"+m+"/"+y)
Josh Leitzel
What does your program print for 2005?
Gabe
You don't need the `window.onload` bit.
Casey Hope
@Gabe Fixed. (Nonexistent date of `31/04/2005` was output before.)
Josh Leitzel
@Casey I kept it because OP asked for a 'full program,' not a function.
Josh Leitzel
Fails for years outside 1900 and 2100: 1875 should be 25/04/1875, program outputs 13/04/1875; 2200 should be 18/04/2123, program outputs 04/04/2123. This is because Julian conversion to Gregorian uses an algorithm to determine how many days to add. Your program adds the correct amount for 1900-2100, but adds nothing for other dates. I don't think it's a requirement that it should work for dates outside 1900-2100, but you mentioned it as a possible requirement.
Mark Trapp
You can still have a full program by omitting `window.onload=function(){` -- execution will simply start immediately instead of on load.
Casey Hope
Improved the script using ~~ and removing it from the window.onload
M28
fails for year 2100, right?
David Murdoch
+4  A: 

PHP CLI, no easter_date(), 125 characters

Valid for dates from 13 March 1900 to 13 March 2100, now works for Easters that fall in May

Code:

<?=date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));

Invocation:

$ php codegolf.php 2010
$ php codegolf.php 2005

Output:

04/04/2010
01/05/2005

With whitespace:

<?=date("d/m/Y", mktime(0, 0, 0, floor(($b = ($a = (19 * (($y = $argv[1]) % 19) + 15) % 30) + (2 * ($y % 4) + 4 * $y % 7 - $a + 34) % 7 + 114) / 31), ($b % 31) + 14, $y));

This iteration is no longer readable thanks to PHP's handling of assignments. It's almost a functional language!


For completeness, here's the previous, 127 character solution that does not rely on short tags:

Code:

echo date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));

Invocation:

$ php -r 'echo date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));' 2010
$ php -r 'echo date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));' 2005
Mark Trapp
The question is for the Eastern (Julian) date, so we're not interested in the Gregorian date. As you mention the calendars are different so you have to adjust the dates for certain years. Your Julian output does not satisfy the required output in the question. See my JS solution, which accounts for the date difference.
Josh Leitzel
@Josh Leitzel, fixed.
Mark Trapp
What does your program print for 2005?
Gabe
@Gabe, previously the awesome day of April 31st. I've fixed this at the expense of more characters, so now it's May 1st.
Mark Trapp
I don't mean to be annoying, but how can this be considered a solution when it only works for a range of 200 years?
Josh Leitzel
@Josh Leitzel, all of the Meeus algorithm answers, including your own, fail when the year is outside the bounds of 1900 and 2100. You even put a check in yours for this condition.
Mark Trapp
Just as a clarification, this is because of the Julian to Gregorian calendar conversion. Adding 13 days only works for dates between 1900 and 2100: see [Wikipedia](http://en.wikipedia.org/wiki/Gregorian_calendar#Difference_between_Gregorian_and_Julian_calendar_dates) for the table.
Mark Trapp
what does this print for 2100?
David Murdoch
@David Murdoch: nothing correct, as the Julian conversion fails for dates after the stated March 13, 2100 (which the Eastern Easter certainly is after).
Mark Trapp
+5  A: 

C#, 155 157 182 209 212 characters

class P{static void Main(string[]i){int y=int.Parse(i[0]),c=(y%19*19+15)%30,d=c+(y%4*2+y%7*4-c+34)%7+128;System.Console.Write(d%31+d/155+"/"+d/31+"/"+y);}}

Python 2.3, 97 characters

y=int(input())
c=(y%19*19+15)%30
d=c+(y%4*2+y%7*4-c+34)%7+128
print"%d/%d/%d"%(d%31+d/155,d/31,y)

This also uses the Meeus Julian algorithm (and should work for dates in May).

  • removed no longer necessary check for modern years and zero-padding in output
  • don't expect Easters in March anymore because there are none between 1800-2100
  • included Python 2.3 version (shortest so far)
Gabe
what does this print for 2100?
David Murdoch
The result for 2100 should be `2 / 5 / 2100`. Not `1 / 5 / 2100`
David Murdoch
The actual range of the algorithm is between 1900 and 2099 inclusive, which presumably is what the rule means when it says "(1900-2100)".
Gabe
Oh, I read 1900-2100 as 1900 THROUGH 2100...which would include the year 2100. Even if you read it as 1900 TO 2100 you should still count 2100, right? I someone told you to count from 1 TO 10 would you stop at 9?
David Murdoch
David: I just meant that it was a bug in the spec. The algorithm works for dates from 13 March 1900 to 13 March 2100. It just turns out that Easter for 2100 is after that last date.
Gabe
A: 
    'VB .Net implementation of:
    'http://aa.usno.navy.mil/faq/docs/easter.php
    Dim y As Integer = 2010
    Dim c, d, i, j, k, l, m, n As Integer
    c = y \ 100
    n = y - 19 * (y \ 19)
    k = (c - 17) \ 25
    i = c - c \ 4 - (c - k) \ 3 + 19 * n + 15
    i = i - 30 * (i \ 30)
    i = i - (i \ 28) * (1 - (i \ 28) * (29 \ (i + 1)) * ((21 - n) \ 11))
    j = y + y \ 4 + i + 2 - c + c \ 4
    j = j - 7 * (j \ 7)
    l = i - j
    m = 3 + (l + 40) \ 44
    d = l + 28 - 31 * (m \ 4)
    Easter = DateSerial(y, m, d)
dbasnett
+9  A: 

Python (101 140 132 115 chars)

y=input()
d=(y%19*19+15)%30
e=(y%4*2+y%7*4-d+34)%7+d+127
m=e/31
a=e%31+1+(m>4)
if a>30:a,m=1,5
print a,'/',m,'/',y

This one uses the Meeus Julian algorithm but since this one only works between 1900 and 2099, an implementation using Anonymous Gregorian algorithm is coming right up.

Edit: Now 2005 is properly handled. Thanks to Mark for pointing it out.

Edit 2: Better handling of some years, thanks for all the input!

Edit 3: Should work for all years in range. (Sorry for hijacking it Juan.)

Juan
You can shorten that by using operator precedence cleverly.
Donal Fellows
@Donal: I actually tried playing around with precedence, but I couldnt find anything to shorten.
Juan
Fails for 1907: should be 05/05/1907, output is 04/05/1907. Looks like it's because the check you added for May assumes the latest Easter can be is May 1st.
Mark Trapp
Also, the Anonymous Gregorian algorithm won't calculate the Eastern Orthodox (Julian) Easter. If you wanted to take into account dates outside the 1900-2100 range, you'd need to check the year and add the appropriate number of days.
Mark Trapp
Fails for 2013: gives May 4th, should be May 5th: http://www.timeanddate.com/holidays/us/orthodox-easter-day
Nas Banov
And I just messed things up even further. Cleary I dont remember what I learned in algebra..
Juan
@Nas Banov: I think I fixed it for that year.
mjschultz
@Juan: You got the thing I spotted: `a*(b%c)` can go to `b%c*a` (provided there's no side effects in the way) for a saving of 2 chars.
Donal Fellows
The result for 2100 should be 2 / 5/ 2100, not 1 / 5/ 2100
David Murdoch
+2  A: 

Tcl

Eastern Easter

(116 chars)

puts [expr 1+[incr d [expr ([set y $argv]%4*2+$y%7*4-[
set d [expr ($y%19*19+15)%30]]+34)%7+123]]%30]/[expr $d/30]/$y

Uses the Meeus algorithm. Takes the year as a command line argument, produces Eastern easter. Could be a one-liner, but it's slightly more readable when split...

Western Easter

(220 chars before splitting over lines)

interp alias {} tcl::mathfunc::s {} set;puts [expr [incr 3 [expr {
s(2,(s(4,$argv)%100/4*2-s(3,(19*s(0,$4%19)+s(1,$4/100)-$1/4-($1-($1+8)/25+46)
/3)%30)+$1%4*2-$4%4+4)%7)-($0+11*$3+22*$2)/451*7+114}]]%31+1]/[expr $3/31]/$4

Uses the Anonymous algorithm.

Donal Fellows
It's also a shameless ripoff of this other answer: http://stackoverflow.com/questions/3584307/code-challenge-easter-date/3591079#3591079
Donal Fellows
what does this output for year 2100?
David Murdoch
@David: First snippet, `1/5/2100`, second snippet, `28/3/2100`. Don't know if they're correct; the algorithms are known to have limited domains.
Donal Fellows
A: 

I'm not going to implement it, but I'd like to see one where the code e-mails the Pope, scans any answer that comes back for a date, and returns that.

Admittedly, the calling process may be blocked for a while.

mjfgates
So far it's been blocked since the 5th century. It asks for the orthodox easter date - the guy with the big hat in Rome works for the other lot
Martin Beckett
+1  A: 

C, 128 121 98 characters

Back to Meeus' algorithm. Computing the day in Julian, but adjusting for Gregorian (this still seems naive to me, but I cannot find a shorter alternative).

main(y,v){int d=(y%19*19+15)%30;d+=(y%4*2+y%7*4-d+34)%7+128;printf("%d/%d/%d",d%31+d/155,d/31,y);}

I have not found a case where floor(d/31) would actually be needed. Also, to account for dates in May, the m in Meeus' algorithm must be at least 5, therefore the DoM is greater than 154, hence the division.

The year is supplied as the number of program invocation arguments plus one, ie. for 1996 you must provide 1995 arguments. The range of ARG_MAX on modern systems is more than enough for this.

PS. I see Gabe has come to the same implementation in Python 2.3, surpassing me by one character. Aw. :( PPS. Anybody looking at a tabular method for 1800-2099?

Edit - Shortened Gabe's answer to 88 characters:

y=input()
d=(y%19*19+15)%30
d+=(y%4*2+y%7*4-d+34)%7+128
print"%d/%d/%d"%(d%31+d/155,d/31,y)
Michael Foukarakis
what does this output for year 2100?
David Murdoch
For 2100, the year when the Julian-Gregorian calendars' difference increases by 1 day, it outputs 1/5/2100.
Michael Foukarakis
A: 

Javascript 125 characters

This will handle years 1900 - 2199. Some of the other implementations cannot handle the year 2100 correctly.

y=prompt();k=(y%19*19+15)%30;e=(y%4*2+y%7*4-k+34)%7+k+127;m=~~(e/31);d=e%31+m-4+(y>2099);alert((d+=d<30||++m-34)+"/"+m+"/"+y)

Ungolfed..ish

// get the year to check.
y=prompt();

// do something crazy.
k=(y%19*19+15)%30;

// do some more crazy...
e=(y%4*2+y%7*4-k+34)%7+k+127;

// estimate the month. p.s. The "~~" is like Math.floor
m=~~(e/31);

// e % 31 => get the day
d=e%31;
if(m>4){
    d += 1;
}
if(y > 2099){
   d += 1;
}

// if d is less than 30 days add 1
if(d<30){
   d += 1;
}
// otherwise, change month to May
// and adjusts the days to match up with May.
// e.g., 32nd of April is 2nd of May
else{
    m += 1;
    d = m - 34 + d;
}

// alert the result!
alert(d + "/" + m + "/" + y);

A fix for dates up to 2399.
I'm sure there is a way to algorithmically calculate dates beyond this but I don't want to figure it out.

y=prompt();k=(y%19*19+15)%30;e=(y%4*2+y%7*4-k+34)%7+k+127;m=~~(e/31);d=e%31+m-4+(y<2200?0:~~((y-2000)/100));alert((d+=d<30||++m-34)+"/"+m+"/"+y)
David Murdoch