#include <iostream>
#include <vector>
#include <algorithm>

using std::cout;
using std::vector;

enum wires { invalid, white, red, black, orange, green };

struct s0; struct s1; struct s2; struct s3; struct s4; struct s5; struct sf; struct ss;

struct ctx {

    ctx(vector<wires> const & v) : defused(false), input(v) { 
        it = input.begin();
        run<s0>();
    }
    
    wires next() {
        if ( it == input.end() )
            return invalid;
        return *it++;
    }
    
    template<typename T>
    void run() {
        T().run(*this);
    }
    
    
    bool defused;
    vector<wires> input;
    vector<wires>::const_iterator it;
};

struct defuse_check {
    defuse_check(vector<vector<wires>> const & v) {
        for(auto&&a:v)
            for(auto&&w:a)
                input.emplace_back(w);
    }
  
  bool defusable() {
      std::sort(input.begin(), input.end());
      while ( std::next_permutation(input.begin(), input.end()) ) {
          if ( ctx(input).defused ) return true;
      }
      return false;
  }
  
  vector<wires> input;
};

struct s0 {
    void run(ctx& c) {
        switch(c.next()) {
            case white: c.run<s1>(); break;
            case red  : c.run<s2>(); break;
            default: c.run<sf>();
        }        
    }
};
struct s1 {
    void run(ctx& c) {
        switch(c.next()) {
            case white : c.run<s2>(); break;
            case orange: c.run<s3>(); break;
            default: c.run<sf>();
        }
    }    
};
struct s2 {
    void run(ctx& c) {
        switch(c.next()) {
            case red  : c.run<s0>(); break;
            case black: c.run<s3>(); break;
            default: c.run<sf>();
        }        
    }    
};
struct s3 {
    void run(ctx& c) {
        switch(c.next()) {
            case black : c.run<s3>(); break;
            case orange: c.run<s4>(); break;
            case green : c.run<s5>(); break;
            default: c.run<sf>();
        }
    }    
};
struct s4 {
    void run(ctx& c) {
        if ( c.next() == green ) c.run<ss>();
        else c.run<sf>();
    }    
};    
struct s5 {
    void run(ctx& c) {
        if ( c.next() == orange ) c.run<ss>();
        else c.run<sf>();
    }    
};    
struct sf { void run(ctx& c) { c.defused = false; } };
struct ss { void run(ctx& c) { c.defused = true ; } };    

template<typename T>
void print_defused(T && c) {
    cout << (c.defused ? "defused" : "boom") << "\n";
}

template<typename T>
void print_defusable(T && c) {
    cout << (c.defusable() ? "defusable" : "not defusable") << "\n";
}

int main(int argc, char* argv[]) {
    // challenges
    print_defused(ctx( {white, white, red, red, red, white, white, black, green, orange} ));
    print_defused(ctx( {white, black, black, black, black, green, orange} ));
    print_defused(ctx( {black, green, green} ));
    print_defused(ctx( {red, red, white, orange, black, green} ));
    
    // bonus 1
    print_defusable(defuse_check({{4, white}, {3, red}, {4, black}, {1, green}, {1, orange}}));
    print_defusable(defuse_check({{4, white}, {3, red}, {4, black}, {1, orange}}));

    // bonus 1 challenge
    print_defusable(defuse_check({{3, white}, {1, red}, {48, black}, {1, green}, {2, orange}}));
    print_defusable(defuse_check({{3, white}, {1, red}, {48, black}, {1, green}, {1, orange}}));
}