hot_ranking_algorithm/
lib.rs1extern crate chrono;
2
3pub use chrono::offset::Utc;
4pub use chrono::DateTime;
5use std::cmp;
6
7const HALF_LIFE: i32 = 45_000;
8
9pub fn rank(
13 upvotes: &i32,
14 downvotes: &i32,
15 timestamp: DateTime<Utc>,
16 epoch: DateTime<Utc>,
17) -> i32 {
18 let duration = timestamp.signed_duration_since(epoch);
19 let seconds = duration.num_seconds() as i32;
20
21 let score = upvotes - downvotes;
22 let upper = cmp::max(score, 1) as f32;
23 let order = upper.log(10.0) as i32;
24
25 let sign = match score {
26 n if n > 0 => 1,
27 n if n < 0 => -1,
28 _ => 0,
29 };
30
31 sign * order + seconds / HALF_LIFE
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use chrono::prelude::*;
38
39 #[test]
40 fn one_upvote_one_downvote() {
41 let upvotes: i32 = 1;
42 let downvotes: i32 = 1;
43 let epoch = Utc.ymd(2014, 1, 1).and_hms(21, 15, 33);
44 let timestamp = Utc.ymd(2014, 1, 1).and_hms(21, 15, 33);
45
46 let ranking = rank(&upvotes, &downvotes, timestamp, epoch);
47 assert!(ranking == 0);
48 }
49
50 #[test]
51 fn twenty_upvotes_zero_downvotes() {
52 let upvotes: i32 = 50;
53 let downvotes: i32 = 0;
54 let epoch = Utc.ymd(2014, 1, 1).and_hms(21, 15, 33);
55 let timestamp = Utc.ymd(2014, 1, 1).and_hms(21, 15, 33);
56
57 let ranking = rank(&upvotes, &downvotes, timestamp, epoch);
58 assert!(ranking > 0);
59 }
60
61 #[test]
62 fn one_upvote_twenty_downvotes() {
63 let upvotes: i32 = 1;
64 let downvotes: i32 = 1000;
65 let epoch = Utc.ymd(2014, 1, 1).and_hms(21, 15, 33);
66 let timestamp = Utc.ymd(2014, 1, 1).and_hms(21, 15, 33);
67
68 let ranking = rank(&upvotes, &downvotes, timestamp, epoch);
69 println!("{}", ranking);
70 assert!(ranking == 0);
71 }
72}