diff --git a/Cargo.lock b/Cargo.lock index 0a2a634a075f17f8a2fac14bbbe8d2be4a2e60f8..eb3b0b518798cf71bec8713f1aa424debb44cc9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,16 @@ name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "coco" version = "0.1.1" @@ -47,6 +57,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "games-for-redox" version = "0.1.0" dependencies = [ + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "libgo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "liner 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -83,6 +94,19 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-integer" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "num_cpus" version = "1.7.0" @@ -157,13 +181,43 @@ dependencies = [ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "time" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbee135e9245416869bf52bd6ccc9b59e2482651510784e089b874272f02a252" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" @@ -174,6 +228,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" "checksum libgo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99a64661b7d5c8b2ccb779e3fb0ced098426bb9bfbded934aa76ef227300e0cf" "checksum liner 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f9e406164c25b420480023985bdf65cef366855666ad4cb12cd3eaee82dcb399" +"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" @@ -183,4 +239,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum reversi 0.5.0 (git+https://github.com/EGhiorzi/reversi/)" = "" "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index c7f10f833434c82b8ce4a2f9ac1231894246f7d3..e4350810778c2373812807712bbbe574b8c83356 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ liner = "0.1" rand = "0.3" rayon = "0.8" termion = "1.5.1" +chrono = "0.4" [dependencies.extra] git = "https://gitlab.redox-os.org/redox-os/libextra.git" @@ -29,6 +30,10 @@ path = "src/ice/main.rs" name = "h4xx3r" path = "src/h4xx3r/main.rs" +[[bin]] +name = "pom" +path = "src/pom/main.rs" + [lib] name = "rusthello_lib" path = "src/rusthello/lib.rs" diff --git a/src/minesweeper/main.rs b/src/minesweeper/main.rs index d65c303f2cd1c4b64085a86040a7ec1782b7738e..a78665943f41fd21a45b008b93f5ab0f0fc5f69b 100644 --- a/src/minesweeper/main.rs +++ b/src/minesweeper/main.rs @@ -37,7 +37,7 @@ const FLAGGED: &'static str = "F"; /// The string printed for mines in the game over revealing. const MINE: &'static str = "*"; /// The string printed for concealed cells. -const CONCEALED: &'static str = "▒"; +const CONCEALED: &'static str = "░"; /// The game over screen. const GAME_OVER: &'static str = "╔═════════════════╗\n\r\ diff --git a/src/pom/main.rs b/src/pom/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..d1503d9139c6ff360fb7891d06121e09b61c9b3c --- /dev/null +++ b/src/pom/main.rs @@ -0,0 +1,230 @@ +// This file is a part of Redox OS games, which is distributed under terms of +// MIT license. +// +// Copyright (c) 2018 Árni Dagur +// +// vim: et:ts=4:sts=4:sw=4 +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +extern crate chrono; +use chrono::{Local, DateTime, TimeZone, Utc}; +use chrono::offset; + +use std::env; +use std::process; +use std::io::{self, Write}; +use std::f64::consts::PI; + +/// Phase of the moon. Calculates the current phase of the moon based on +/// routines from 'Practical Astronomy with Your Calculator or Spreadsheet' by +/// Duffet-Smith. The 4th edition of the book is available online for free at +/// https://archive.org/ +// Comments give the section from the book that particular piece of code was +// adapted from. + +const HELP: &'static str = r#"pom ~ Phase of the Moon + +flags: + -h | --help ~ this help message. + -dt | --datetime ~ specify datetime in "YY-MM-DD HH:MM:SS" format + -p | --percentage ~ only print the percentage + +author: + Árni Dagur +"#; + +// We define an epoch on which we shall base our calculations; here it is +// 2010 January 0.0, equivilent to the midnight between 30. and 31. december of +// 2009 (see section 3 for details). +const EPSILON_g: f64 = 279.447208f64; // The Sun's mean ecliptic long at epoch. +const RHO_g: f64 = 283.112438f64; // The longitude of the Sun at perigee. +const ECC: f64 = 0.016705f64; // Eccintricity of the Sun-Earth orbit. +const FRAC_360_TROP_YEAR: f64 = 0.9856473563866f64; // 360 divided by 365.242191 + +const L_0: f64 = 91.929335f64; // Moon's mean longitude at the epoch +const P_0: f64 = 130.143076f64; // Moon's mean longitude of the perigee at epoch + +/// Calculate the phase of the moon given a certain number of days away from the +/// epoch January 2010. +fn potm(days: f64) -> f64 { + // Section 46: Calculating the position of the sun + let n = adj360(FRAC_360_TROP_YEAR * days); + // We calulate: + // (a) The true solar anomoly in an ellipse + let M_sol = adj360(n + EPSILON_g - RHO_g); + // (b) The longitude of the sun + let Lambda_sol = adj360(n + 360.0 / PI * ECC + * M_sol.to_radians().sin() + EPSILON_g); + + // Section 65: Calculating the Moon's position + // TODO: Switch to more accurate MoonPos2 model instead of MoonPos1 + // We calculate: + // (a) the Sun's ecliptic longitude Lambda_sol, and mean anomaly M_sol, + // by the method given in section 46. (Done above) + // (b) the Moon's mean longitude, l + let l = adj360(13.1763966f64 * days + L_0); + // (c) the Moon's mean anomaly, M_m + let M_m = adj360(l - 0.1114041f64 * days - P_0); + // Next we calculate the corrections for: + // (a) Evection + let E_v = 1.2739 * (2.0 * (l - Lambda_sol) - M_m).to_radians().sin(); + // (b) The annual equation + let A_e = 0.1858 * M_sol.to_radians().sin(); + // (c) And a 'third' correction + let A_3 = 0.37 * M_sol.to_radians().sin(); + // Applying these corrections gives the Moon's corrected anomaly + let M_m_prime = M_m - E_v - A_e - A_3; + // Correction for the equation of the centre: + let E_c = 6.2886 * M_m_prime.to_radians().sin(); + // Another correction term must be calculated: + let A_4 = 0.214 * (2.0 * M_m_prime).to_radians().sin(); + // We can now find the Moon's corrected longitude, l_prime + let l_prime = l + E_v + E_c - A_e + A_4; + // The final correction to apply to the Moon's longitude is the variation + let V = 0.6583 * (2.0 * (l_prime - Lambda_sol)).to_radians().sin(); + // So the Moon's true orbital longitude is: + let l_2prime = l_prime + V; + + // Section 67: The phases of the Moon + // Calculate the 'age' of the moon. + let D = l_2prime - Lambda_sol; + // The Moon's phase, F, on the scale from 0 to 100, is given by: + 50.0 * (1.0 - D.to_radians().cos()) +} + +/// Adjusts value so 0 <= deg <= 360 +fn adj360(mut deg: f64) -> f64 { + loop { + if deg < 0.0 { + deg += 360.0; + } else if deg > 360.0 { + deg -= 360.0; + } else { + break; + } + } + deg +} + +fn main() { + let stdout = io::stdout(); + let mut stdout = stdout.lock(); + let stderr = io::stderr(); + let mut stderr = stderr.lock(); + + let epoch: DateTime = offset::Utc.ymd(2009, 12, 31).and_hms(0, 0, 0); + let mut datetime: DateTime = Local::now(); + + let mut args = env::args().skip(1); + let mut percentage_only = false; + loop { + // Read the arguments. + let arg = if let Some(x) = args.next() { + x + } else { + break; + }; + + match arg.as_str() { + "-h" | "--help" => { + stdout.write(HELP.as_bytes()).unwrap(); + stdout.flush().unwrap(); + process::exit(0); + }, + "-dt" | "--datetime" => { + datetime = offset::Local.datetime_from_str( + &args.next().unwrap_or_else(|| { + stderr.write(b"No datetime given.\n").unwrap(); + stderr.flush().unwrap(); + process::exit(1); + }), + &"%Y-%m-%d %H:%M:%S" + ).unwrap_or_else(|_| { + stderr.write(b"Invalid datetime given.\n").unwrap(); + stderr.flush().unwrap(); + process::exit(1); + }); + }, + "-p" | "--percentage" => { + percentage_only = true; + }, + _ => { + stderr.write(b"Unknown argument.\n").unwrap(); + stderr.flush().unwrap(); + process::exit(1); + } + } + } + + let seconds = datetime.signed_duration_since(epoch).num_seconds(); + let days = seconds as f64 / 86400.0; + let today = potm(days); + + if percentage_only { + println!("{:.2}", today); + process::exit(0); + } + + stdout.write(b"The Moon is").unwrap(); + if today.round() == 100.0 { + stdout.write(b"Full\n").unwrap(); + } else if today.round() == 0.0 { + stdout.write(b"New\n").unwrap(); + } else { + let tomorrow = potm(days + 1.0); + if today.round() == 50.0 { + if tomorrow > today { + stdout.write(b"at the First Quarter\n").unwrap(); + } else { + stdout.write(b"at the Last Quarter\n").unwrap(); + } + } else { + if tomorrow > today { + stdout.write(b" Waxing ").unwrap(); + } else { + stdout.write(b" Waning ").unwrap(); + } + if today > 50.0 { + println!("Gibbous ({:.2}% of Full)", today) + } else { + println!("Crescent ({:.2}% of Full)", today) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_potm_on_epoch() { + assert_eq!(potm(0.0).round(), 99.0); + } + + #[test] + fn test_potm_on_leap_day_2016_noon() { + assert_eq!(potm(2251.5).round(), 64.0); + } + + #[test] + fn test_potm_on_13_october_2004_0530am() { + assert_eq!(potm(-1904.770833333).round(), 1.0); + } + + #[test] + fn test_adj360_above_360() { + assert!((adj360(821.0) - 101.0).abs() < 1e-10); + } + + #[test] + fn test_adj360_below_0() { + assert!((adj360(-643.4) - 76.6).abs() < 1e-10); + } + + #[test] + fn test_adj360_between_0_and_360() { + assert!((adj360(168.0) - 168.0).abs() < 1e-10); + } +}