我试图写返回同一个月亮的相位值作为在游戏NetHack Python函数。这在发现 hacklib.c

我试图简单地从NetHack代码复制相应的功能,但我不认为我得到正确的结果。

我所写入的功能是phase_of_the_moon()

的功能和position() phase(),我在网上找到,我使用它们作为我的函数的成功的指示。他们是非常精确的,并给其大致匹配nethack.alt.org服务器(请参阅 HTTP结果:/ /alt.org/nethack/moon/pom.txt )。什么不过,我以后是原始NetHack功能的精确复制的特质完整。

我希望我的功能和“控制”功能,至少给同一个月亮阶段,但目前他们没有,我不知道为什么!

下面是NetHack代码:

/*
 * moon period = 29.53058 days ~= 30, year = 365.2422 days
 * days moon phase advances on first day of year compared to preceding year
 *  = 365.2422 - 12*29.53058 ~= 11
 * years in Metonic cycle (time until same phases fall on the same days of
 *  the month) = 18.6 ~= 19
 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
 *  (29 as initial condition)
 * current phase in days = first day phase + days elapsed in year
 * 6 moons ~= 177 days
 * 177 ~= 8 reported phases * 22
 * + 11/22 for rounding
 */
int
phase_of_the_moon()     /* 0-7, with 0: new, 4: full */
{
    register struct tm *lt = getlt();
    register int epact, diy, goldn;

    diy = lt->tm_yday;
    goldn = (lt->tm_year % 19) + 1;
    epact = (11 * goldn + 18) % 30;
    if ((epact == 25 && goldn > 11) || epact == 24)
        epact++;

    return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
}

下面是getlt()函数(也在hacklib.c):

static struct tm *
getlt()
{
    time_t date;

#if defined(BSD) && !defined(POSIX_TYPES)
    (void) time((long *)(&date));
#else
    (void) time(&date);
#endif
#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
    return(localtime((long *)(&date)));
#else
    return(localtime(&date));
#endif
}

下面是我的Python代码:

from datetime import date

def phase_of_the_moon():
   lt = date.today()

   diy = (lt - date(lt.year, 1, 1)).days
   goldn = ((lt.year - 1900) % 19) + 1
   epact = (11 * goldn + 18) % 30;
   if ((epact == 25 and goldn > 11) or epact == 24):
      epact += 1
   return ( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 )

import math, decimal, datetime
dec = decimal.Decimal

def position(now=None): 
   if now is None: 
      now = datetime.datetime.now()

   diff = now - datetime.datetime(2001, 1, 1)
   days = dec(diff.days) + (dec(diff.seconds) / dec(86400))
   lunations = dec("0.20439731") + (days * dec("0.03386319269"))

   return lunations % dec(1)

def phase(pos): 
   index = (pos * dec(8)) + dec("0.5")
   index = math.floor(index)
   return {
      0: "New Moon", 
      1: "Waxing Crescent", 
      2: "First Quarter", 
      3: "Waxing Gibbous", 
      4: "Full Moon", 
      5: "Waning Gibbous", 
      6: "Last Quarter", 
      7: "Waning Crescent"
   }[int(index) & 7]

def phase2(pos): 
   return {
      0: "New Moon", 
      1: "Waxing Crescent", 
      2: "First Quarter", 
      3: "Waxing Gibbous", 
      4: "Full Moon", 
      5: "Waning Gibbous", 
      6: "Last Quarter", 
      7: "Waning Crescent"
   }[int(pos)]

def main():
   ## Correct output
   pos = position()
   phasename = phase(pos)
   roundedpos = round(float(pos), 3)
   print "%s (%s)" % (phasename, roundedpos)

   ## My output
   print "%s (%s)" % (phase2(phase_of_the_moon()), phase_of_the_moon())

if __name__=="__main__": 
   main()
有帮助吗?

解决方案

作为编写的代码主要是不可测的 - 你需要使它测试。所以,你需要的C代码为:

int
phase_of_the_moon()     /* 0-7, with 0: new, 4: full */
{
    register struct tm *lt = getlt();
    return testable_potm(lt);
}

static int
testable_potm(const struct tm *lt)
{
    register int epact, diy, goldn;

    diy = lt->tm_yday;
    goldn = (lt->tm_year % 19) + 1;
    epact = (11 * goldn + 18) % 30;
    if ((epact == 25 && goldn > 11) || epact == 24)
        epact++;

    return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
}

现在你可以运行多个时间值的测试。替代的方法来做到这一点是假getlt()代替。

然后,您需要在您的Python代码并行变化。然后,创建可以由两个Python和C被读取,然后(在C经由time_t)转换成合适的结构localtime()值的文件。然后,你可以看到事情偏离。

其他提示

编辑:原来双方的“问题”我发现这里都是基于tm结构的误解。我会离开这个答案完好的意见讨论的缘故,但节省您的投票人谁实际上可能是正确的。 ; - )


警告:我并不十分熟悉C时间构建体;我主要打算关闭strftime供给的场文档。

我看到你的端口两个“漏洞”。首先,我相信tm_year旨在不含世纪的年份,而不是年份减去1900,所以,goldn((lt.year % 100) % 19) + 1。其次,你的计算diy是从零开始,而出现tm_yday(再次,从文档)是基于一个。不过,我不能确定是后者,作为固定只是goldn行给出正确的结果(至少截至目前),那里的固定既给出了错误的答案:

>>> def phase_of_the_moon():
    lt = date.today()

    diy = (lt - date(lt.year, 1, 1)).days
    goldn = ((lt.year % 100) % 19) + 1
    epact = (11 * goldn + 18) % 30
    if ((epact == 25 and goldn > 11) or epact == 24):
        epact += 1
    return ( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 )

>>> phase_of_the_moon():
3

再次,这是大部分猜测。请善待。 : - )

我长晚于这个线程,但FWIW,通过网络POM的alt.org服务器的显示器只在cron的更新几次,每天所以,如果你关闭的只是从它一下,这可能是原因。游戏本身运行从无论是在nethack代码本身因此不会遭受同样的缓存问题。 -DREW(alt.org所有者)

奇怪的是,当我编译和运行nethack例如我得到“2”作为回答(“第一季度”,这是与您的端口)

#include <time.h>

static struct tm *
getlt()
{
        time_t date;
        (void) time(&date);
        return(localtime(&date));
}
/*
 * moon period = 29.53058 days ~= 30, year = 365.2422 days
 * days moon phase advances on first day of year compared to preceding year
 *  = 365.2422 - 12*29.53058 ~= 11
 * years in Metonic cycle (time until same phases fall on the same days of
 *  the month) = 18.6 ~= 19
 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
 *  (29 as initial condition)
 * current phase in days = first day phase + days elapsed in year
 * 6 moons ~= 177 days
 * 177 ~= 8 reported phases * 22
 * + 11/22 for rounding
 */
int
phase_of_the_moon()     /* 0-7, with 0: new, 4: full */
{
    register struct tm *lt = getlt();
    register int epact, diy, goldn;

    diy = lt->tm_yday;
    goldn = (lt->tm_year % 19) + 1;
    epact = (11 * goldn + 18) % 30;
    if ((epact == 25 && goldn > 11) || epact == 24)
        epact++;

    return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
}

int main(int argc, char * argv[]) {
    printf ("phase of the moon %d\n\n", phase_of_the_moon());
}

输出:

> a.out
phase of the moon 2

但是,这似乎是正确的答案不,今天,weatherunderground.com和alt.org报告月亮的相位为“残月”(a.k.a 3)。

我试着删除“-1900”,但并没有导致正确的答案要么。

下面的代码是从该网站借来的,这里将其粘贴为便于参考,(并且如果其他站点关闭)。似乎你想要做什么。

# Determine the moon phase of a date given
# Python code by HAB

def moon_phase(month, day, year):
    ages = [18, 0, 11, 22, 3, 14, 25, 6, 17, 28, 9, 20, 1, 12, 23, 4, 15, 26, 7]
    offsets = [-1, 1, 0, 1, 2, 3, 4, 5, 7, 7, 9, 9]
    description = ["new (totally dark)",
      "waxing crescent (increasing to full)",
      "in its first quarter (increasing to full)",
      "waxing gibbous (increasing to full)",
      "full (full light)",
      "waning gibbous (decreasing from full)",
      "in its last quarter (decreasing from full)",
      "waning crescent (decreasing from full)"]
    months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

    if day == 31:
        day = 1
    days_into_phase = ((ages[(year + 1) % 19] + ((day + offsets[month-1]) % 30) + (year < 1900)) % 30)
    index = int((days_into_phase + 2) * 16/59.0)
    if index > 7:
        index = 7
    status = description[index]

    # light should be 100% 15 days into phase
    light = int(2 * days_into_phase * 100/29)
    if light > 100:
        light = abs(light - 200);
    date = "%d%s%d" % (day, months[month-1], year)

    return date, status, light

# put in a date you want ...
month = 5
day = 14
year = 2006  # use yyyy format

date, status, light = moon_phase(month, day, year)
print "moon phase on %s is %s, light = %d%s" % (date, status, light, '%')

您可以使用time模块获得的当前本地时间即可。下面有我做到了(粘贴如下张贴代码testrun):

import time
tm = time.localtime()
month = tm.tm_mon
day = tm.tm_mday
year = tm.tm_year
date, status, light = moon_phase(month, day, year)
print "moon phase on %s is %s, light = %d%s" % (date, status, light, '%')

输出:

moon phase on 22Dec2009 is waxing crescent (increasing to full), light = 34%

月球的东西很有趣。 :)

下面是我的它的转换,我已经通过在值使从x范围(0,1288578760,3601)测试了这对C代码,并且它们都返回相同的值。请注意,我已经改变了它,这样就可以纪元以来经过秒,这样我就可以测试它针对C版一百万不同值的三分之一。的“秒”值是可选的

def phase_of_the_moon(seconds = None):
   '0-7, with 0: new, 4: full'
   import time

   if seconds == None: seconds = time.time()
   lt = time.localtime(seconds)

   tm_year = lt.tm_year - 1900
   diy = lt.tm_yday - 1
   goldn = (tm_year % 19) + 1
   epact = (11 * goldn + 18) % 30

   if (epact == 25 and goldn > 11) or epact == 24: epact += 1

   return (((((diy + epact) * 6) + 11) % 177) / 22) & 7

我喜欢把我知道的事情或两个关于日历,让我们看看,如果我可以明确一些事情了。

在天主教复活节定义在月相方面的日期(这就是为什么日期跳转各地每年)。正因为如此,它需要能够计算出近似的月相,其这样做的算法进行了说明这里

我没有做过很详细的检查,但现在看来,在NetHack算法在很大程度上基于教会的算法。该NetHack算法似乎就像教堂一样的算法,只注意日历日期,忽略时区和一天中的时间。

在NetHack算法仅使用年和一年中的天。我可以检查代码,是Y2K兼容告诉,这tm_year必须是年份减去1900。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top