import util;
import game;
import output;
import driver;
import solver;

class CUI(Solver) : GameObserver
{
	this(in Game g) { solver = new Solver(g); }
	Solver solver;
	bool fin;
	override void on_game_changed(char c, in Game g, bool finished) { fin = finished; }
}

class ForSafety : GameObserver
{
	this(in Game g)
	{
		if(g.map.W*g.map.H <= 1000)
		{
			try {
				score_log ~= g.score;
				auto fast_solver = new FastSolver(g);
				foreach(_; 0..g.map.W*g.map.H) {
					char c = fast_solver.single_step();
					if(c=='A') break;
					const(Game) gg = fast_solver.current_game;
					log ~= c;
					score_log ~= gg.score;
					if(gg.cleared || gg.dead) break;
				}
			} catch {
				log = null;
				score_log = null;
			}
		}
	}
	override void on_game_changed(char c, in Game g, bool finished) {}
	string log;
	long[] score_log;
}

void main()
{
	auto d = new Driver(stdin);
	auto o = d.addObserver!(GuardedOutput)();
	auto c = d.addObserver!(CUI!MainSolver)();
	auto f = d.addObserver!(ForSafety)();
	o.safety_data(f.log, f.score_log);
	while(!c.fin)
		d.command(c.solver.single_step());
}
