aboutsummaryrefslogtreecommitdiff
path: root/rust/bob/src/lib.rs
blob: ae18a3d8cf60e7336ef46f24620bcf95ac4ee68b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/* The solution consists of an implementation of a simple Finite State Automaton whose states and
 * transition messages are represented by the `State` and `Message` enums.
 *
 * `process(State, Message) -> State` represents the main transition function for the FSA. This
 * allows us to compute the answer with a single visit of the input string.
 *
 * Note: some duplicate states (`QuestLow`, `ElseLow`) are needed in order to remember whether we
 * have seen a lowercase character already or not. This is probably not the minimal number of
 * states required to solve the problem.
 */
enum State { Nothing, QuestLow, Quest, Yell, YellQ, ElseLow, Else }
enum Message { Whitespace, Upper, Lower, Symbol, Question }

fn to_message(c: char) -> Message {
    match c as u8 {
        0..=32   => Message::Whitespace,    // All controll characters are considered whitespace
        63       => Message::Question,
        65..=90  => Message::Upper,
        97..=122 => Message::Lower,
        _        => Message::Symbol         // Anything else (numbers incl.) is a symbol
    }
}

fn process(s: State, m: Message) -> State {
    match s {
        State::Nothing => match m {
            Message::Whitespace => s,
            Message::Upper => State::Yell,
            Message::Lower => State::ElseLow,
            Message::Question => State::Quest,
            Message::Symbol => State::Else
        },
        State::QuestLow => match m {
            Message::Whitespace | Message::Question => s,
            _ => State::ElseLow
        },
        State::Quest => match m {
            Message::Upper => State::Yell,
            Message::Lower => State::ElseLow,
            Message::Symbol => State::Else,
            _ => s
        },
        State::Yell => match m {
            Message::Lower => State::ElseLow,
            Message::Question => State::YellQ,
            _ => s
        },
        State::YellQ => match m {
            Message::Symbol | Message::Upper => State::Yell,
            Message::Lower => State::ElseLow,
            _ => s
        },
        State::ElseLow => match m {
            Message::Question => State::QuestLow,
            _ => s
        },
        State::Else => match m {
            Message::Upper => State::Yell,
            Message::Lower => State::ElseLow,
            Message::Question => State::Quest,
            _ => s
        }
    }
}

pub fn reply(message: &str) -> &str {
    let state = message.chars().fold(State::Nothing, |s, c| process(s,to_message(c)));
    match state {
        State::Nothing => "Fine. Be that way!",
        State::QuestLow | State::Quest => "Sure.",
        State::Yell => "Whoa, chill out!",
        State::YellQ => "Calm down, I know what I'm doing!",
        _ => "Whatever."
    }
}