yipo
6/26/2017 - 5:53 PM

Mutant Flatworld Explorers

Mutant Flatworld Explorers

#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <tuple>
using namespace std;

class world
{
public:
    world(int width, int height) : m_width(width), m_height(height)
    {
    }

    bool contain(int x, int y) const
    {
        return (0 <= x && x < m_width) && (0 <= y && y < m_height);
    }

    bool check_scent(int x, int y) const
    {
        return m_scents.count(make_tuple(x, y)) > 0;
    }

    void leave_scent(int x, int y)
    {
        m_scents.insert(make_tuple(x, y));
    }

private:
    int m_width, m_height;
    set<tuple<int, int>> m_scents;
};

class orientation
{
public:
    enum
    {
        N, E, S, W // clockwise
    };

public:
    orientation() : m_value(N)
    {
    }

    operator int() const
    {
        return m_value;
    }

    void turn_left()
    {
        if (m_value == N) m_value = W; else m_value--;
    }

    void turn_right()
    {
        if (m_value == W) m_value = N; else m_value++;
    }

    friend istream &operator >>(istream &is, orientation &o)
    {
        while (isspace(is.peek())) is.get();

        switch (is.get())
        {
        case 'N':
            o.m_value = N;
            break;
        case 'E':
            o.m_value = E;
            break;
        case 'S':
            o.m_value = S;
            break;
        case 'W':
            o.m_value = W;
            break;
        }

        return is;
    }

    friend ostream &operator <<(ostream &os, const orientation &o)
    {
        static const string nesw("NESW");

        os << nesw.at(o.m_value);
        return os;
    }

private:
    int m_value;
};

class robot
{
public:
    robot(const shared_ptr<world> &world, int x, int y, const orientation &o) :
        m_world(world), m_x(x), m_y(y), m_o(o)
    {
    }

    void turn_left()
    {
        m_o.turn_left();
    }

    void turn_right()
    {
        m_o.turn_right();
    }

    void forward()
    {
        int bx = m_x, by = m_y; // backup

        switch (m_o)
        {
        case orientation::E:
            m_x++;
            break;
        case orientation::W:
            m_x--;
            break;
        case orientation::N:
            m_y++;
            break;
        case orientation::S:
            m_y--;
            break;
        }

        if (!m_world->contain(m_x, m_y))
        {
            m_x = bx, m_y = by;

            if (!m_world->check_scent(m_x, m_y))
            {
                m_world->leave_scent(m_x, m_y);
                throw lost();
            }
        }
    }

    friend ostream &operator <<(ostream &os, const robot &r)
    {
        os << r.m_x << " " << r.m_y << " " << r.m_o;
        return os;
    }

public:
    class lost : public exception {};

private:
    shared_ptr<world> m_world;

    int m_x, m_y;
    orientation m_o;
};

void test_case()
{
    int wx, wy;
    cin >> wx >> wy;

    shared_ptr<world> w(new world(wx + 1, wy + 1));

    int x, y;
    orientation o;
    while (cin >> x >> y >> o)
    {
        robot bot(w, x, y, o);

        string commands;
        cin >> commands;
        try
        {
            for (auto command : commands)
            {
                switch (command)
                {
                case 'L':
                    bot.turn_left();
                    break;
                case 'R':
                    bot.turn_right();
                    break;
                case 'F':
                    bot.forward();
                    break;
                default:
                    throw;
                }
            }

            cout << bot << endl;
        }
        catch (robot::lost &e)
        {
            cout << bot << " LOST" << endl;
        }
    }
}

int main()
{
    test_case();
    return 0;
}