11 Stimmen

Wie kann man diese NetHack-Funktion nach Python portieren?

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

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

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

Die Funktionen position() y phase() die ich im Netz gefunden habe, und ich verwende sie als Indikator für den Erfolg meiner Funktion. Sie sind sehr genau und liefern Ergebnisse, die ungefähr mit denen des nethack.alt.org-Servers übereinstimmen (siehe http://alt.org/nethack/moon/pom.txt ). Was ich jedoch suche, ist eine exakte Replikation der ursprünglichen NetHack-Funktion, mit intakten Eigenheiten.

Ich würde erwarten, dass meine Funktion und die "Kontroll"-Funktion zumindest dieselbe Mondphase anzeigen, aber im Moment tun sie das nicht 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()

1voto

Sean Reifschneider Punkte 1261

Hier ist meine Konvertierung davon, und ich habe dies gegen den C-Code getestet, indem Sie in Werte aus xrange(0, 1288578760, 3601), und sie beide geben die gleichen Werte. Beachten Sie, dass ich es so geändert habe, dass Sie die Sekunden seit der Epoche übergeben können, so dass ich es mit der C-Version für eine Drittelmillion verschiedener Werte testen konnte. Der Wert "Sekunden" 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

0voto

Robert L Punkte 1965

Ich glaube, dass ich mich mit Kalendern gut auskenne. Mal sehen, ob ich ein paar Dinge aufklären kann.

Die katholische Kirche legt das Osterdatum in Abhängigkeit von den Mondphasen fest (deshalb springt das Datum von Jahr zu Jahr). Deshalb muss sie in der Lage sein, die ungefähre Mondphase zu berechnen, und der Algorithmus, mit dem dies geschieht, wird erläutert aquí .

Ich habe keine sehr detaillierte Überprüfung vorgenommen, aber es scheint, dass der NetHack-Algorithmus stark auf dem Algorithmus der Kirche basiert. Der NetHack-Algorithmus scheint, wie der Algorithmus der Kirche, nur das Kalenderdatum zu berücksichtigen und Zeitzonen und die Tageszeit zu ignorieren.

Der NetHack-Algorithmus verwendet nur das Jahr und den Tag des Jahres. Bei der Prüfung des Codes kann ich feststellen, daß tm_year das Jahr minus 1900 sein muß, um Jahr-2000-kompatibel zu sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X