Frage

Ich versuche, eine Python-Funktion zu schreiben, die den gleichen Mondphasenwert wie im Spiel NetHack zurückzugibt. Dies wird gefunden in hacklib.c .

Ich habe versucht, die entsprechende Funktion aus dem NetHack Code einfach zu kopieren, aber ich glaube nicht, dass ich die richtigen Ergebnisse bin immer.

Die Funktion, die ich geschrieben habe, ist phase_of_the_moon().

Die Funktionen position() und phase(), die ich im Internet gefunden, und ich bin mit ihnen als Indiz für den Erfolg meiner Funktion. Sie sind sehr präzise und Ergebnisse liefern, die etwa den nethack.alt.org Server übereinstimmen (siehe http: / /alt.org/nethack/moon/pom.txt ). Was ich nach ist jedoch eine exakte Nachbildung der ursprünglichen NetHack Funktion, Idiosynkrasien intakt.

Ich würde meine Funktion und die ‚Kontrolle‘ Funktion erwartet die gleiche Mondphase zumindest zu geben, aber noch nicht, dass sie tun, und ich bin mir nicht sicher, warum!

Hier ist der NetHack Code:

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

Hier ist die getlt() Funktion (auch in 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
}

Hier ist mein Python-Code:

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()
War es hilfreich?

Lösung

Der Code geschrieben ist weitgehend nicht überprüfbar - und Sie müssen es testbar machen. So müssen Sie den C-Code sein:

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

Jetzt können Sie Tests mit mehreren Werten von Zeit. Die alternative Möglichkeit, dies stattdessen zu fälschen getlt() zu tun.

Sie müssen dann parallel Änderungen in Ihrem Python-Code. Dann Sie eine Datei von time_t Werten schaffen, die sowohl von Python und C gelesen werden kann, und dann in eine geeignete Struktur (via localtime() in C). Dann können Sie sehen, wo die Dinge sind abweichend.

Andere Tipps

Edit: Stellt sich beide der „Probleme“ out ich hier gesehen wurden, basierend auf einem falschen Verständnis der tm Struktur. Ich werde die Antwort intakt aus Gründen der Diskussion in den Kommentaren hinterlassen, aber Ihre Stimmen für jemanden retten, die tatsächlich richtig sein könnte. ; -)


Vorab: Ich bin nicht schrecklich mit C Zeit Konstrukte vertraut; Ich werde aus meist der Felddokumentation für strftime geliefert.

Ich sehe zwei "Bugs" in Ihrem Hafen. Erstens glaube ich tm_year sollte das Jahr ohne Jahrhundert sein, nicht das Jahr minus 1900, so sollte goldn ((lt.year % 100) % 19) + 1 werden. Zweitens Ihre Berechnung für diy nullbasiert ist, während tm_yday erscheint (wieder aus der Dokumentation) ein basiert zu sein. Aber ich bin nicht sicher über die letztere, als Fixierung nur die goldn Linie ein richtiges Ergebnis gibt (zumindest für heute), wobei als Befestigungs beide gibt die falsche Antwort:

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

Auch dies ist meistens Vermutungen. Bitte sei nett. : -)

Ich bin lange spät auf diesen Thread aber FWIW, die Anzeige von pom des alt.org Server über das Internet nur Updates auf cron ein paar Mal pro Tag, so dass, wenn Sie von ihm durch nur ein bisschen sind weg, das könnte der Grund. Das Spiel selbst läuft von was auch immer in dem nethack Code selbst so nicht das gleiche Cache-Problem leidet. -drew (alt.org Inhaber)

Seltsamerweise, wenn ich kompilieren und ausführen, um die nethack Beispiel I „2“ als Antwort ( „First Quarter“, die die gleiche wie Ihre Port) erhalten

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

Ausgabe:

> a.out
phase of the moon 2

Aber das scheint nicht, wie die richtige Antwort, wie heute, weatherunderground.com und alt.org berichtet die Phase des Mondes als „Zunehmender Mond“ (a.k.a 3).

Ich habe versucht, entfernen die „-1900“, aber das auch nicht in der richtigen Antwort geführt hat.

Im Anschluss an Code ist entlehnt von dieser Seite , Einfügen es hier für eine einfache Referenz ( und im Falle der anderen Seite geht nach unten). Scheint zu tun, was Sie wollen.

# 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, '%')

Sie können die time Modul verwenden, um die aktuelle Ortszeit zu erhalten. Heres, wie ich es tat (unten geschrieben Code einfügen, um 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, '%')

Ausgabe:

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

Mond Sachen macht Spaß. :)

Hier ist meine Umwandlung davon, und ich habe dies gegen den C-Code getestet, indem sie in Werte von xrange (0, 1288578760, 3601) vorbei, und sie beide die gleichen Werte zurückgeben. Beachten Sie, dass es es geändert haben, so dass Sie die Sekunden seit Epoche passieren können, so dass ich es gegen die C-Version für ein Drittel der eine Million verschiedenen Werte testen konnte. Der "Sekunden" Wert ist optional

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

Ich mag zu denken, ich ein oder zwei Dinge über Kalender wissen, also mal sehen, ob ich auf ein paar Dinge klären kann.

Die katholische Kirche definiert das Datum von Ostern in Bezug auf den Mondphasen (aus diesem Grunde springt das Datum um von Jahr zu Jahr). Aus diesem Grund muss es in der Lage sein die ungefähre Mondphase zu berechnen und seinen Algorithmus zu tun, so wird erklärt hier .

Ich habe nicht sehr gründliche Überprüfung durchgeführt, aber es scheint, dass der NetHack Algorithmus stark auf den Algorithmus der Kirche beruht. Der NetHack Algorithmus scheint, wie die Algorithmus-Kirche, achtet nur auf das Kalenderdatum, Zeitzonen und die Tageszeit, zu ignorieren.

Der NetHack Algorithmus verwendet nur das Jahr und den Tag des Jahres. Ich kann sagen Sie den Code aus der Prüfung, die Y2K kompatibel zu sein, dass tm_year hat das Jahr minus 1900 sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top