Created
September 27, 2018 14:26
-
-
Save zgracem/545d8922fe47d730835c419aa9a43621 to your computer and use it in GitHub Desktop.
Calculating the phase of the moon in Ruby, based on NetHack's source code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Based on NetHack's phase_of_the_moon() | |
# > http://nethack.wikia.com/wiki/Hacklib.c#phase_of_the_moon | |
### See also: | |
# > https://en.wikipedia.org/wiki/Epact | |
# > https://en.wikipedia.org/wiki/Golden_number_(time) | |
# > https://en.wikipedia.org/wiki/Metonic_cycle | |
# > https://en.wikipedia.org/wiki/Computus | |
def phase(lt = Time.now) | |
# The solar year is about 365¼ days, while the lunar month is slightly longer | |
# than 29½ days, on average; both are non-integers. | |
solar_year = 365.242190 | |
lunar_month = 29.530588 # ≈ 30 | |
lunar_year = lunar_month * 12 # ≈ 354.367056 | |
# The Metonic cycle is the period which corresponds to a common multiple of | |
# solar years (~19) and lunar months (235). Two calendar years at the same | |
# point in the cycle will have the same phases of the moon on the same dates. | |
metonic_cycle = (235 * lunar_month) / solar_year # ≈ 19 | |
# The sequence number of the current year in the Metonic cycle is called the | |
# golden number. The golden number of any Julian or Gregorian calendar year | |
# can be calculated by dividing the year by 19, taking the remainder, and | |
# adding 1. | |
golden = (lt.year % metonic_cycle.round) + 1 | |
# If a solar and lunar year start on the same day, then after one year, the | |
# start of the solar year is 11 days after the start of the lunar year; after | |
# two years, it is 22 days after. These excess days are epacts, and are added | |
# to the day of the solar year to determine the day of the lunar year. | |
advance = (solar_year - lunar_year).round # ≈ 11 | |
epact = (golden * advance + 18) % lunar_month.round | |
# Within a Metonic cycle, years that are 11 years apart have epacts that | |
# differ by one day. Because lunar months are either 29 or 30 days, if epacts | |
# 24 and 25 both occur within one Metonic cycle, the new moon in some months | |
# will fall on the same dates in both years. To ensure dates repeat only | |
# after 19 years, in years with an epact of 25 and a golden number > 11, the | |
# reckoned new moon in short months will fall one day earlier. | |
if (epact == 25 && golden > 11) || epact == 24 | |
epact += 1 | |
end | |
# current phase in days = phase on January 1 + days elapsed in year | |
current_phase = epact + lt.yday | |
moon_phases = %i{new_moon waxing_crescent first_quarter waxing_gibbous | |
full_moon waning_gibbous last_quarter waning_crescent} | |
six = 6 | |
moons = lunar_month * six # ≈ 177 | |
phases = moons / moon_phases.size | |
# 0-7, with 0: new, 4: full | |
(((((lt.yday + epact) * 6) + 11) % 177) / 22).round & 7 | |
# (((((lt.yday + epact) * six) + advance) % moons) / phases).round & (moon_phases.index(moon_phases.last)) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment