Created
April 21, 2017 01:28
-
-
Save jsimmons/0b0510912f407a8c90bc3e00e543171a to your computer and use it in GitHub Desktop.
Another ridiculously over-engineered interview question answered in Rust.
This file contains hidden or 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
Kushi Tsuru | Mon-Sun 11:30 am - 9 pm | |
---|---|---|
Osakaya Restaurant | Mon-Thu, Sun 11:30 am - 9 pm / Fri-Sat 11:30 am - 9:30 pm | |
The Stinking Rose | Mon-Thu, Sun 11:30 am - 10 pm / Fri-Sat 11:30 am - 11 pm | |
McCormick & Kuleto's | Mon-Thu, Sun 11:30 am - 10 pm / Fri-Sat 11:30 am - 11 pm | |
Mifune Restaurant | Mon-Sun 11 am - 10 pm | |
The Cheesecake Factory | Mon-Thu 11 am - 11 pm / Fri-Sat 11 am - 12:30 am / Sun 10 am - 11 pm | |
New Delhi Indian Restaurant | Mon-Sat 11:30 am - 10 pm / Sun 5:30 pm - 10 pm | |
Iroha Restaurant | Mon-Thu, Sun 11:30 am - 9:30 pm / Fri-Sat 11:30 am - 10 pm | |
Rose Pistola | Mon-Thu 11:30 am - 10 pm / Fri-Sun 11:30 am - 11 pm | |
Alioto's Restaurant | Mon-Sun 11 am - 11 pm | |
Canton Seafood & Dim Sum Restaurant | Mon-Fri 10:30 am - 9:30 pm / Sat-Sun 10 am - 9:30 pm | |
All Season Restaurant | Mon-Fri 10 am - 9:30 pm / Sat-Sun 9:30 am - 9:30 pm | |
Bombay Indian Restaurant | Mon-Sun 11:30 am - 10:30 pm | |
Sam's Grill & Seafood Restaurant | Mon-Fri 11 am - 9 pm / Sat 5 pm - 9 pm | |
2G Japanese Brasserie | Mon-Thu, Sun 11 am - 10 pm / Fri-Sat 11 am - 11 pm | |
Restaurant Lulu | Mon-Thu, Sun 11:30 am - 9 pm / Fri-Sat 11:30 am - 10 pm | |
Sudachi | Mon-Wed 5 pm - 12:30 am / Thu-Fri 5 pm - 1:30 am / Sat 3 pm - 1:30 am / Sun 3 pm - 11:30 pm | |
Hanuri | Mon-Sun 11 am - 12 am | |
Herbivore | Mon-Thu, Sun 9 am - 10 pm / Fri-Sat 9 am - 11 pm | |
Penang Garden | Mon-Thu 11 am - 10 pm / Fri-Sat 10 am - 10:30 pm / Sun 11 am - 11 pm | |
John's Grill | Mon-Sat 11 am - 10 pm / Sun 12 pm - 10 pm | |
Quan Bac | Mon-Sun 11 am - 10 pm | |
Bamboo Restaurant | Mon-Sat 11 am - 12 am / Sun 12 pm - 12 am | |
Burger Bar | Mon-Thu, Sun 11 am - 10 pm / Fri-Sat 11 am - 12 am | |
Blu Restaurant | Mon-Fri 11:30 am - 10 pm / Sat-Sun 7 am - 3 pm | |
Naan 'N' Curry | Mon-Sun 11 am - 4 am | |
Shanghai China Restaurant | Mon-Sun 11 am - 9:30 pm | |
Tres | Mon-Thu, Sun 11:30 am - 10 pm / Fri-Sat 11:30 am - 11 pm | |
Isobune Sushi | Mon-Sun 11:30 am - 9:30 pm | |
Viva Pizza Restaurant | Mon-Sun 11 am - 12 am | |
Far East Cafe | Mon-Sun 11:30 am - 10 pm | |
Parallel 37 | Mon-Sun 11:30 am - 10 pm | |
Bai Thong Thai Cuisine | Mon-Sat 11 am - 11 pm / Sun 11 am - 10 pm | |
Alhamra | Mon-Sun 11 am - 11 pm | |
A-1 Cafe Restaurant | Mon, Wed-Sun 11 am - 10 pm | |
Nick's Lighthouse | Mon-Sun 11 am - 10:30 pm | |
Paragon Restaurant & Bar | Mon-Fri 11:30 am - 10 pm / Sat 5:30 pm - 10 pm | |
Chili Lemon Garlic | Mon-Fri 11 am - 10 pm / Sat-Sun 5 pm - 10 pm | |
Bow Hon Restaurant | Mon-Sun 11 am - 10:30 pm | |
San Dong House | Mon-Sun 11 am - 11 pm | |
Thai Stick Restaurant | Mon-Sun 11 am - 1 am | |
Cesario's | Mon-Thu, Sun 11:30 am - 10 pm / Fri-Sat 11:30 am - 10:30 pm | |
Colombini Italian Cafe Bistro | Mon-Fri 12 pm - 10 pm / Sat-Sun 5 pm - 10 pm | |
Sabella & La Torre | Mon-Thu, Sun 10 am - 10:30 pm / Fri-Sat 10 am - 12:30 am | |
Soluna Cafe and Lounge | Mon-Fri 11:30 am - 10 pm / Sat 5 pm - 10 pm | |
Tong Palace | Mon-Fri 9 am - 9:30 pm / Sat-Sun 9 am - 10 pm | |
India Garden Restaurant | Mon-Sun 10 am - 11 pm | |
Sapporo-Ya Japanese Restaurant | Mon-Sat 11 am - 11 pm / Sun 11 am - 10:30 pm | |
Santorini's Mediterranean Cuisine | Mon-Sun 8 am - 10:30 pm | |
Kyoto Sushi | Mon-Thu 11 am - 10:30 pm / Fri 11 am - 11 pm / Sat 11:30 am - 11 pm / Sun 4:30 pm - 10:30 pm | |
Marrakech Moroccan Restaurant | Mon-Sun 5:30 pm - 2 am |
This file contains hidden or 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
#![feature(inclusive_range_syntax)] | |
extern crate csv; | |
use std::mem::transmute; | |
use std::fs::File; | |
use std::io::Read; | |
#[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
#[allow(dead_code)] | |
enum Day { | |
Mon, | |
Tue, | |
Wed, | |
Thu, | |
Fri, | |
Sat, | |
Sun, | |
} | |
#[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
enum Period { | |
Am, | |
Pm, | |
} | |
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | |
#[allow(dead_code)] | |
enum Time { | |
T0000, | |
T0030, | |
T0100, | |
T0130, | |
T0200, | |
T0230, | |
T0300, | |
T0330, | |
T0400, | |
T0430, | |
T0500, | |
T0530, | |
T0600, | |
T0630, | |
T0700, | |
T0730, | |
T0800, | |
T0830, | |
T0900, | |
T0930, | |
T1000, | |
T1030, | |
T1100, | |
T1130, | |
T1200, | |
T1230, | |
T1300, | |
T1330, | |
T1400, | |
T1430, | |
T1500, | |
T1530, | |
T1600, | |
T1630, | |
T1700, | |
T1730, | |
T1800, | |
T1830, | |
T1900, | |
T1930, | |
T2000, | |
T2030, | |
T2100, | |
T2130, | |
T2200, | |
T2230, | |
T2300, | |
T2330, | |
Last, | |
} | |
impl Time { | |
fn from_u32(i: u32) -> Time { | |
let x = i % Time::Last as u32; | |
unsafe { transmute(x as u8) } | |
} | |
} | |
#[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
enum Token { | |
Day(Day), | |
Time(Time), | |
Period(Period), | |
Sep, // / | |
DaySep, // , | |
ToSep, // - | |
} | |
struct Scanner<'a> { | |
position: usize, | |
bytes: &'a [u8], | |
} | |
impl<'a> Scanner<'a> { | |
fn new(bytes: &[u8]) -> Scanner { | |
Scanner { | |
position: 0, | |
bytes: bytes, | |
} | |
} | |
} | |
// am | |
// 00:00 0 | |
// 00:30 1 | |
// 01:00 2 | |
// 01:30 3 | |
// 02:00 4 | |
// 02:30 5 | |
// 03:00 6 | |
// 03:30 7 | |
// 04:00 8 | |
// 04:30 9 | |
// 05:00 10 | |
// 05:30 11 | |
// 06:00 12 | |
// 06:30 13 | |
// 07:00 14 | |
// 07:30 15 | |
// 08:00 16 | |
// 08:30 17 | |
// 09:00 18 | |
// 09:30 19 | |
// 10:00 20 | |
// 10:30 21 | |
// 11:00 22 | |
// 11:30 23 | |
// | |
// pm | |
// 12:00 24 | |
// 12:30 25 | |
// 13:00 26 | |
// 13:30 27 | |
// 14:00 28 | |
// 14:30 29 | |
// 15:00 30 | |
// 15:30 31 | |
// 16:00 32 | |
// 16:30 33 | |
// 17:00 34 | |
// 17:30 35 | |
// 18:00 36 | |
// 18:30 37 | |
// 19:00 38 | |
// 19:30 39 | |
// 20:00 40 | |
// 20:30 41 | |
// 21:00 42 | |
// 21:30 43 | |
// 22:00 44 | |
// 22:30 45 | |
// 23:00 46 | |
// 23:30 47 | |
impl<'a> Iterator for Scanner<'a> { | |
type Item = Token; | |
fn next(&mut self) -> Option<Token> { | |
if self.position >= self.bytes.len() { | |
return None; | |
} | |
let b = self.bytes[self.position]; | |
match b { | |
b'-' => { | |
self.position += 1; | |
return Some(Token::ToSep); | |
} | |
b',' => { | |
self.position += 1; | |
return Some(Token::DaySep); | |
} | |
b'/' => { | |
self.position += 1; | |
return Some(Token::Sep); | |
} | |
b'M' => { | |
self.position += 3; | |
return Some(Token::Day(Day::Mon)); | |
} | |
b'T' => { | |
if let Some(peek) = self.bytes.get(self.position + 1) { | |
self.position += 3; | |
if *peek == b'u' { | |
return Some(Token::Day(Day::Tue)); | |
} else if *peek == b'h' { | |
return Some(Token::Day(Day::Thu)); | |
} | |
} | |
return None; | |
} | |
b'W' => { | |
self.position += 3; | |
return Some(Token::Day(Day::Wed)); | |
} | |
b'F' => { | |
self.position += 3; | |
return Some(Token::Day(Day::Fri)); | |
} | |
b'S' => { | |
if let Some(peek) = self.bytes.get(self.position + 1) { | |
self.position += 3; | |
if *peek == b'a' { | |
return Some(Token::Day(Day::Sat)); | |
} else if *peek == b'u' { | |
return Some(Token::Day(Day::Sun)); | |
} | |
} | |
return None; | |
} | |
b'a' => { | |
self.position += 2; | |
return Some(Token::Period(Period::Am)); | |
} | |
b'p' => { | |
self.position += 2; | |
return Some(Token::Period(Period::Pm)); | |
} | |
b'1' => { | |
// 1 | |
// 1:30 | |
// 10 | |
// 10:30 | |
// 11 | |
// 11:30 | |
// 12 // actually the start? treat as 0? | |
// 12:30 | |
if let Some(peek) = self.bytes.get(self.position + 1) { | |
match *peek { | |
b' ' => { | |
self.position += 1; | |
return Some(Token::Time(Time::T0100)); | |
} | |
b':' => { | |
self.position += 4; | |
return Some(Token::Time(Time::T0130)); | |
} | |
c @ b'0'...b'2' => { | |
let t = match c { | |
b'0' => Time::T1000 as u32, | |
b'1' => Time::T1100 as u32, | |
b'2' => Time::T0000 as u32, | |
_ => 0, | |
}; | |
match self.bytes.get(self.position + 2) { | |
Some(&b' ') => { | |
self.position += 2; | |
return Some(Token::Time(Time::from_u32(t))); | |
} | |
Some(&b':') => { | |
self.position += 5; | |
return Some(Token::Time(Time::from_u32(t + 1))); | |
} | |
_ => {} | |
} | |
} | |
_ => {} | |
} | |
} | |
return None; | |
} | |
c @ b'2'...b'9' => { | |
let t = ((c - b'0') as u32) * 2; | |
if let Some(peek) = self.bytes.get(self.position + 1) { | |
match *peek { | |
b' ' => { | |
self.position += 1; | |
return Some(Token::Time(Time::from_u32(t))); | |
} | |
b':' => { | |
self.position += 4; | |
return Some(Token::Time(Time::from_u32(t + 1))); | |
} | |
_ => {} | |
} | |
} | |
return None; | |
} | |
_ => { | |
self.position += 1; | |
return self.next(); | |
} | |
} | |
} | |
} | |
#[derive(Copy, Clone, Debug)] | |
struct DayRange { | |
open: Day, | |
close: Day, | |
} | |
#[derive(Copy, Clone, Debug)] | |
struct TimeRange { | |
open: Time, | |
close: Time, | |
} | |
#[derive(Debug)] | |
struct OpenHours { | |
// 7 days, | |
// 48 time segments | |
segments: [u64; 6], | |
name: String, | |
} | |
struct Parser<'a> { | |
scanner: Scanner<'a>, | |
token: Option<Token>, | |
} | |
impl<'a> Parser<'a> { | |
fn new(mut scanner: Scanner) -> Parser { | |
let token = scanner.next(); | |
Parser { | |
token: token, | |
scanner: scanner, | |
} | |
} | |
fn next(&mut self) { | |
self.token = self.scanner.next(); | |
} | |
fn parse_day(&mut self) -> Option<DayRange> { | |
if let Some(Token::Day(d1)) = self.token { | |
self.next(); | |
match self.token { | |
Some(Token::ToSep) => { | |
self.next(); | |
if let Some(Token::Day(d2)) = self.token { | |
self.next(); | |
return Some(DayRange { | |
open: d1, | |
close: d2, | |
}); | |
} | |
}, | |
Some(_) => { | |
return Some(DayRange { | |
open: d1, | |
close: d1, | |
}); | |
}, | |
None => { | |
return None; | |
}, | |
} | |
} | |
None | |
} | |
fn parse_time(&mut self) -> Option<Time> { | |
if let Some(Token::Time(t)) = self.token { | |
self.next(); | |
if let Some(Token::Period(p)) = self.token { | |
self.next(); | |
return match p { | |
Period::Am => Some(t), | |
Period::Pm => Some(Time::from_u32(t as u32 + Time::T1200 as u32)), | |
}; | |
} | |
} | |
None | |
} | |
fn parse_time_range(&mut self) -> Option<TimeRange> { | |
let t1 = match self.parse_time() { | |
Some(t) => t, | |
None => { | |
return None; | |
} | |
}; | |
match self.token { | |
Some(Token::ToSep) => { | |
self.next(); | |
} | |
_ => { | |
return None; | |
} | |
} | |
let t2 = match self.parse_time() { | |
Some(t) => t, | |
None => { | |
return None; | |
} | |
}; | |
Some(TimeRange { | |
open: t1, | |
close: t2, | |
}) | |
} | |
fn parse(&mut self, restaurant: &str) -> OpenHours { | |
let mut open_hours = OpenHours { | |
name: restaurant.to_owned(), | |
segments: [0; 6], | |
}; | |
println!("{}", restaurant); | |
loop { | |
let mut days = Vec::new(); | |
loop { | |
if let Some(day_range) = self.parse_day() { | |
days.push(day_range); | |
} | |
match self.token { | |
Some(Token::DaySep) => { | |
self.next(); | |
} | |
_ => { | |
break; | |
} | |
} | |
} | |
if let Some(time_range) = self.parse_time_range() { | |
for day in days { | |
for d in day.open as usize...day.close as usize { | |
if time_range.open > time_range.close { | |
for t in time_range.open as usize...Time::T2330 as usize { | |
let abs_time = d * Time::Last as usize + t; | |
let idx = abs_time / 64; | |
let off = abs_time % 64; | |
open_hours.segments[idx] |= 1u64 << off; | |
} | |
for t in Time::T0000 as usize..time_range.close as usize as usize { | |
let abs_time = ((d + 1) % 7) * Time::Last as usize + t; | |
let idx = abs_time / 64; | |
let off = abs_time % 64; | |
open_hours.segments[idx] |= 1u64 << off; | |
} | |
continue; | |
} else { | |
for t in time_range.open as usize..time_range.close as usize { | |
let abs_time = d * Time::Last as usize + t; | |
let idx = abs_time / 64; | |
let off = abs_time % 64; | |
open_hours.segments[idx] |= 1u64 << off; | |
} | |
} | |
} | |
} | |
} | |
match self.token { | |
Some(Token::Sep) => { | |
self.next(); | |
} | |
_ => { | |
break; | |
} | |
} | |
} | |
for s in &open_hours.segments { | |
print!("{:b}", s); | |
} | |
println!(""); | |
println!(""); | |
open_hours | |
} | |
} | |
fn main() { | |
let mut file = File::open("data.csv").unwrap(); | |
let mut text = String::new(); | |
file.read_to_string(&mut text).unwrap(); | |
let mut reader = csv::Reader::from_string(text).has_headers(false); | |
let mut open_list = Vec::new(); | |
for record in reader.decode() { | |
let (restaurant, opening): (String, String) = record.unwrap(); | |
let bytes = opening.as_bytes(); | |
let scanner = Scanner::new(bytes); | |
let mut parser = Parser::new(scanner); | |
let open_hours = parser.parse(restaurant.as_str()); | |
open_list.push(open_hours); | |
} | |
let day = Day::Mon; | |
let time = Time::T0200; | |
let abs_time = day as usize * Time::Last as usize + time as usize; | |
let bit_index = abs_time / 64; | |
let bit_mask = 1 << (abs_time % 64); | |
for hours in open_list { | |
if hours.segments[bit_index] & bit_mask != 0 { | |
println!("{} IS OPEN!", hours.name); | |
} else { | |
println!("{} IS CLOSED!", hours.name); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment