Skip to content

Instantly share code, notes, and snippets.

@jsimmons
Created April 21, 2017 01:28
Show Gist options
  • Save jsimmons/da9071232bec2ce8f921e698c1ccf9a4 to your computer and use it in GitHub Desktop.
Save jsimmons/da9071232bec2ce8f921e698c1ccf9a4 to your computer and use it in GitHub Desktop.
Another ridiculously over-engineered interview question answered in Rust. This time from https://medium.com/@rodbegbie/find-open-restaurants-an-engineering-take-home-test-dissected-1ada20282ceb
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
#![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