Понимание фаз луны: алгоритм и его реализация на Python
Введение
Луна играет важную роль в жизни на Земле, от приливов и отливов до сельскохозяйственных циклов. Понимание фаз Луны может быть полезным для астрономов, садоводов и всех, кто интересуется натуральными циклами. В этой статье мы разберем код, который определяет текущую фазу луны, и узнаем, как он работает.
Структура программы
Код можно разделить на несколько ключевых функций:
1. julian(year, month, day): вычисляет юлианскую дату для заданной даты.
2. phase(year=None, month=None, day=None): определяет фазу луны на основании юлианской даты.
1. Функция `julian`
def julian(year, month, day):
a = (14 - month) / 12.0
y = year + 4800 - a
m = (12 * a) - 3 + month
return (
day + (153 * m + 2) / 5.0 + (365 * y) + y / 4.0 - y / 100.0 + y / 400.0 - 32045
)
Эта функция предназначена для вычисления юлианской даты, которая представляет собой последовательное число дней, начиная с определенной точки в прошлом (32045 дней до нашей эры).
- Она принимает три параметра: год, месяц и день.
- Переменная a вычисляет, нужно ли «перескочить» год при вычислении из-за разницы в календарях.
- Переменные y и m помогают трансформировать входную дату в юлианскую дату.
2. Функция `phase`
def phase(year=None, month=None, day=None):
if year is None and month is None and day is None:
today = dt.datetime.now()
today -= dt.timedelta(days=1) # 2020 leap day correction
year, month, day = today.year, today.month, today.day
p = (julian(year, month, day) - julian(2000, 1, 6)) % 29.530588853
Эта функция определяет текущую лунную фазу. Если не указаны параметры даты, она использует текущую дату.
- julian(year, month, day) вызывается для получения юлианской даты.
- Разница между юлианской датой и фиксированной датой (2000-01-06, когда в последний раз наблюдали полнолуние) позволяет получить значение p, которое представляет собой количество дней с момента последнего новолуния.
Определение фаз луны
if p < 1.84566:
return "🌑" # новолуние
elif p < 5.53699:
return "🌒" # растущий серп
elif p < 9.22831:
return "🌓" # первая четверть
elif p < 12.91963:
return "🌔" # растущая луна
elif p < 16.61096:
return "🌕" # полнолуние
elif p < 20.30228:
return "🌖" # убывающая луна
elif p < 23.99361:
return "🌗" # последняя четверть
elif p < 27.68493:
return "🌘" # убывающая луна
else:
return "🌑" # новолуние
Здесь основан на значении p определяется фаза Луны:
- Для каждого диапазона возвращается соответствующий символ лунной фазы.
Расширение функциональности
Исходный код можно улучшить, добавив несколько функциональных возможностей:
1. Обработка ошибок: Добавить обработку случаев, когда неверные значения передаются в функцию.
2. Поддержка разных языков: Вернуть фазы луны не только в виде эмодзи, но и в текстовом варианте.
3. Интерфейс командной строки: Позволить пользователю вводить дату через аргументы командной строки.
4. Логирование: Добавить логирование для отслеживания вызовов функций.
Пример улучшенного кода
import datetime as dt
import argparse
def julian(year, month, day):
if month < 3:
month += 12
year -= 1
A = year // 100
B = 2 - A + A // 4
return int((365.25 * (year + 4716))) + int((30.6001 * (month + 1))) + day + B - 1524.5
def phase(year=None, month=None, day=None):
if year is None and month is None and day is None:
today = dt.datetime.now()
today -= dt.timedelta(days=1) # 2020 leap day correction
year, month, day = today.year, today.month, today.day
p = (julian(year, month, day) - julian(2000, 1, 6)) % 29.530588853
phases = {
"🌑": "новолуние",
"🌒": "растущий серп",
"🌓": "первая четверть",
"🌔": "растущая луна",
"🌕": "полнолуние",
"🌖": "убывающая выпуклая луна",
"🌗": "последняя четверть",
"🌘": "убывающая луна"
}
for phase_symbol, phase_name in phases.items():
if (phase_symbol == "🌑" and p < 1.84566) or \
(phase_symbol == "🌒" and p < 5.53699) or \
(phase_symbol == "🌓" and p < 9.22831) or \
(phase_symbol == "🌔" and p < 12.91963) or \
(phase_symbol == "🌕" and p < 16.61096) or \
(phase_symbol == "🌖" and p < 20.30228) or \
(phase_symbol == "🌗" and p < 23.99361) or \
(phase_symbol == "🌘" and p < 27.68493):
return phase_symbol, phase_name
return "🌑", "новолуние"
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Определение фазы луны.")
parser.add_argument("-y", "--year", type=int, help="Год")
parser.add_argument("-m", "--month", type=int, help="Месяц")
parser.add_argument("-d", "--day", type=int, help="День")
args = parser.parse_args()
result_symbol, result_name = phase(args.year, args.month, args.day)
print(f"Текущая фаза луны: {result_symbol} - {result_name}")
Полный пример использования кода
После сохранения кода в файл (например, moon_phase.py), вы можете использовать его через командную строку:
python moon_phase.py --year 2023 --month 10 --day 29
Это выведет текущую фазу луны для указанной даты.
Возможная ошибка.
Ошибка, которую вы можете получать, возникает из-за того, что ваша консоль (или терминал) не поддерживает некоторые символы Unicode, такие как эмодзи. В этом конкретном случае символ 🌑 (новолуние) не может быть отображён из-за ограничения кодировки, используемой в вашей среде.
Вот несколько способов, как вы можете решить эту проблему:
1. Изменение кодировки консоли
Если вы работаете в Windows, вы можете попробовать изменить кодировку консоли на UTF-8, что может помочь в отображении эмодзи:
chcp 65001
После выполнения этой команды, запустите ваш скрипт снова.
2. Использование текстовых символов вместо эмодзи
Если вы не хотите менять кодировку консоли, и вам нужны только текстовые символы, вы можете изменить ваш код, чтобы возвращать текстовые representaciónes вместо эмодзи.
Пример: изначальный код
phases = {
"🌑": "новолуние",
"🌒": "растущий серп",
"🌓": "первая четверть",
"🌔": "растущая луна",
"🌕": "полнолуние",
"🌖": "убывающая выпуклая луна",
"🌗": "последняя четверть",
"🌘": "убывающая луна"
}
Замените на:
phases = {
"new moon": "новолуние",
"waxing crescent": "растущий серп",
"first quarter": "первая четверть",
"waxing gibbous": "растущая луна",
"full moon": "полнолуние",
"waning gibbous": "убывающая выпуклая луна",
"last quarter": "последняя четверть",
"waning crescent": "убывающая луна"
}
Затем измените логику возврата, чтобы она возвращала текстовые значения вместо эмодзи.
3. Запуск текста в IDE или текстовом редакторе
Если вы запустите код в IDE (например, PyCharm) или в текстовом редакторе, таком как VSCode, они обычно поддерживают Unicode и могут отображать эмодзи без проблем.
4. Обработка ошибок при выводе
Кроме того, вы можете добавить обработку ошибок, чтобы избежать краха программы, если символ не может быть отображен:
try:
print(f"Текущая фаза луны: {result_symbol} - {result_name}")
except UnicodeEncodeError:
print(f"Текущая фаза луны: 'Symbol not displayed' - {result_name}")
Попробуйте одно из этих решений, и это должно помочь вам избежать ошибки `UnicodeEncodeError`.