Code Golf:计算东正教复活节日期

时间:2010-08-27 12:53:53

标签: language-agnostic code-golf rosetta-stone

挑战

使用最少量的字符计算特定年份(1900-2100)的希腊东正教复活节日期(http://www.timeanddate.com/holidays/us/orthodox-easter-day)。

输入只是“2010”形式的一年。它与你得到它(Input,CommandLineArgs等)无关,但它必须是动态的!

输出应采用日 - 月 - 年(例如dd/mm/yyyyd/m/yyyy

的形式

限制必须使用自动返回(不适用格里高利)日期的标准函数,例如Mathematica的EasterSundayGreekOrthodox或PHP的easter_date()

实施例

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

代码计数包括输入/​​输出(即完整程序)。

修改 我指的是东部复活节日期。

参考: http://en.wikipedia.org/wiki/Computus

14 个答案:

答案 0 :(得分:9)

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

这个使用Meeus Julian algorithm,但由于这个只能在1900年到2099年间使用,因此使用Anonymous Gregorian algorithm的实现正在进行中。

编辑:现在正确处理2005年。感谢Mark指出它。

编辑2:更好地处理好几年,感谢所有的投入!

编辑3:应该适用于范围内的所有年份。 (抱歉劫持胡安。)

答案 1 :(得分:4)

Mathematica

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

调用
a[2010]

输出

4/4/2010

我也是:我没有看到不使用built-in functions的重点。

答案 2 :(得分:4)

PHP CLI,没有easter_date(),125个字符

适用于1900年3月13日至2100年3月13日的日期,现适用于5月份的Easters

代码:

<?=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));

调用:

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

输出:

04/04/2010
01/05/2005

使用空格:

<?=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));

由于PHP处理分配,此迭代不再可读。它几乎是一种功能语言!


为了完整性,这里是之前的127字符解决方案,不依赖于短标记:

代码:

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));

调用:

$ 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

答案 3 :(得分:4)

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个字符

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)

这也使用Meeus Julian算法(并且应该适用于5月的日期)。

  • 不再需要检查现代年份和输出零填充
  • 不要再期待三月份的Easters了,因为1800-2100之间没有。
  • 包含Python 2.3版本(目前为止最短)

答案 4 :(得分:3)

Java - 252 196 190 chars


  • 更新1:第一个算法是西格里高利复活节。现在固定到东朱利安复活节。保存了56个字符:)

  • 更新2:似乎不需要零填充。保存了4个字符。


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);}}

使用换行符

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);
 }
}

答案 5 :(得分:2)

德尔福 377 335 317个字符

单行:

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.

格式化:

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.

答案 6 :(得分:2)

JavaScript(196个字符)

使用Meeus Julian algorithm。该实现假设给出了有效的四位数年份。

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)

答案 7 :(得分:2)

的Tcl

东部复活节

(116个字符)

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

使用Meeus算法。将年份作为命令行参数,生成 Eastern 复活节。可能是一个单行,但分裂后它的可读性稍高......

西方复活节

(拆分线前220个字符)

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

使用匿名算法。

答案 8 :(得分:1)

COBOL,1262个字符

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.

注意:不是我的,但我喜欢它

编辑:我添加了带空格的字符数,但我不知道COBOL中的间距是如何工作的所以我没有改变任何原始字符。 〜vlad003

更新:我发现OP获得此代码的位置:http://www.tek-tips.com/viewthread.cfm?qid=31746&page=112。我只是把它放在这里,因为作者应得的。 〜vlad003

答案 9 :(得分:1)

C, 128 121 98个字符

回到Meeus的算法。计算朱利安的一天,但调整格里高利(这对我来说似乎仍然天真,但我找不到更短的选择)。

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);}

我没有找到实际需要floor(d/31)的情况。另外,考虑到5月份的日期,Meeus算法中的m必须至少为5,因此DoM大于154,因此划分。

年份以程序调用参数的数量加1提供,即。 1996年你必须提供1995年的论据。现代系统上的ARG_MAX范围足以满足这一要求。

PS。我看到Gabe已经在Python 2.3中实现了相同的实现,超过了我一个字符。噢。 :( PPS。有人看着1800-2099的表格方法吗?

编辑 - 缩短了Gabe对88个字符的回答:

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)

答案 10 :(得分:0)

BASIC,973个字符

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

信用:Astronomical Society of South Australia

编辑:我添加了一个字数,但我认为可以删除许多空格;我不知道BASIC所以我没有对代码进行任何更改。 〜vlad003

答案 11 :(得分:0)

'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)

答案 12 :(得分:0)

我不打算实现它,但是我希望看到一个代码通过电子邮件发送给教皇,扫描任何回复日期的答案,然后返回。

不可否认,呼叫过程可能会被阻止一段时间。

答案 13 :(得分:0)

Javascript 125个字符

这将处理1900年至2199年。其他一些实施无法正确处理年份2100

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);

修复截止日期为2399的日期。
我确信有一种方法可以通过算法计算超出此范围的日期,但我不想弄明白。

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)