// pong.cpp:
//  VariableHack
//  Most creative abuse of the C++ language wins.

// Let's get some boring stuff out of the way...
#include <allegro.h>

int main(int argc, char* argv[])
{ return 0; } END_OF_MAIN()

// Configuration
enum { paddle_w = 5, paddle_h = 30 };
enum { ball_r = 2 };
enum { p1_up = KEY_Q, p1_dn = KEY_A };
enum { p2_up = KEY_P, p2_dn = KEY_L };


// Now to set up allegro
int _allegro_init_ = allegro_init();
int _install_keyboard_ = install_keyboard();
// When a void function comes along, you must WHIP IT!
template <void (*func)(int)> int whip_it(int parm)
{ func(parm); return 0; }
int _set_color_depth_ = whip_it<set_color_depth>(16);
int _set_gfx_mode_ = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 320, 240, 0, 0);
BITMAP* buffer = create_bitmap(SCREEN_W, SCREEN_H);

// Get a timer running
volatile int ticks = 0;
void thing() { ticks++; }
int _install_int_ex_ = install_int_ex(thing, BPS_TO_TIMER(25));

// Here is the stuff we use to run code

// This executes a statement
template <class what> int _tick() { delete new what; return 0; }

// Statements contain constructors
template <class what> class draw {
	public: draw()
	{ what::draw(); }
};
class dec_timer { // ticks is volatile, so this needs to be specialized/
	public: dec_timer()
	{ --ticks; }
};
template <class condition, class loop> class _while {
	public: _while()
	{ while(condition::go()) _tick<loop>(); }
};
template <class left, class right> class _compound {
	public: _compound()
	{ _tick<left>(); _tick<right>(); }
};
class _nil { };
template <class cond, class t, class f> class _if {
	public: _if()
	{ if(cond::go()) _tick<t>(); else _tick<f>(); }
};
template <int& var, class amt> class _addeq {
	public: _addeq()
	{ var += amt::go(); }
};
template <int& var, class amt> class _set {
	public: _set()
	{ var = amt::go(); }
};

// Expressions contain the go method
class timer { // ticks is volatile, so I think we can't get a reference to it.
	public: static int go()
	{ return ticks; }
};
template <int which> class keys {
	public: static int go()
	{ return key[which]; }
};
template <int& var> class _get {
	public: static int go()
	{ return var; }
};
template <int which> class _const {
	public: static int go()
	{ return which; }
};
template <class op> class _not {
	public: static int go()
	{ return !op::go(); }
};
template <class op> class _neg {
	public: static int go()
	{ return -op::go(); }
};
template <class left, class right> class _add {
	public: static int go()
	{ return left::go() + right::go(); }
};
template <class left, class right> class _and {
	public: static int go()
	{ return left::go() && right::go(); }
};
template <class left, class right> class _gt {
	public: static int go()
	{ return left::go() > right::go(); }
};
template <class left, class right> class _lt {
	public: static int go()
	{ return left::go() < right::go(); }
};

// Primitive drawing
class flip {
	public: static inline void draw()
	{ blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); clear_to_color(buffer, 0); }
};
template <class x, class y> class paddle {
	public: static inline void draw()
	{ rectfill(buffer, x::go(), y::go(), x::go() + paddle_w, y::go() + paddle_h, -1); }
};
template <class x, class y> class ball {
	public: static inline void draw()
	{ circlefill(buffer, x::go(), y::go(), ball_r, -1); }
};
template <class x, class y> class score {
	public: static inline void draw()
	{ textprintf(buffer, font, 0, 0, -1, "%d", x::go());
	textprintf_right(buffer, font, SCREEN_W, 0, -1, "%d", y::go()); }
};

// The engine
int top = text_height(font), bottom = SCREEN_H, left = 0, right = SCREEN_W;
int dbx = SCREEN_W / 2, dby = SCREEN_H / 2;
int bx = dbx, by = dby, bxv = 1, byv = -1;
int p1 = dby - (paddle_w / 2), p2 = dby - (paddle_w / 2);
int s1 = 0, s2 = 0;

// The game
int _main_loop_ = _tick<_while<
	_not<keys<KEY_ESC> >,
	_compound<
		_while<_gt<timer, _const<0> >,
			_compound<
				dec_timer,
				_compound<
					_compound<
						_compound<
							_if<
								_and<keys<p1_up>, _gt<_get<p1>, _get<top> > >,
								_addeq<p1, _neg<_const<1> > >,
								_if<
									_and<keys<p1_dn>, _lt<_add<_get<p1>, _const<paddle_h> >, _get<bottom> > >,
									_addeq<p1, _const<1> >,
									_nil
								>
							>,
							_if<
								_and<keys<p2_up>, _gt<_get<p2>, _get<top> > >,
								_addeq<p2, _neg<_const<1> > >,
								_if<
									_and<keys<p2_dn>, _lt<_add<_get<p2>, _const<paddle_h> >, _get<bottom> > >,
									_addeq<p2, _const<1> >,
									_nil
								>
							>
						>,
						_compound<
							_compound<
								_addeq<bx, _get<bxv> >,
								_addeq<by, _get<byv> >
							>,
							_if<_lt<_get<by>, _get<top> >,
								_compound<_set<by, _get<top> >, _set<byv, _const<1> > >,
								_if<_gt<_get<by>, _get<bottom> >,
									_compound<
										_set<by, _add<_get<bottom>, _const<-1> > >,
										_set<byv, _const<-1> >
									>,
									_nil
								>
							>	
						>
					>,
					_compound<
						_if<_and<_lt<_get<bx>, _add<_add<_get<left>, _const<paddle_w> >, _const<ball_r> > >,
							_and<_not<_lt<_get<by>, _get<p1> > >,
							_not<_gt<_get<by>, _add<_get<p1>, _const<paddle_h> > > > > >,
							_set<bxv, _const<1> >,
							_if<_and<_gt<_get<bx>, _add<_add<_get<right>, _const<-paddle_w> >, _const<-ball_r> > >,
								_and<_not<_lt<_get<by>, _get<p2> > >,
								_not<_gt<_get<by>, _add<_get<p2>, _const<paddle_h> > > > > >,
								_set<bxv, _const<-1> >,
								_nil
							>
						>,
						_if<_lt<_get<bx>, _get<left> >,
							_compound<
								_compound<_set<bx,  _const<paddle_w> >,
								_set<by, _add<_get<p1>, _const<paddle_h / 2> > > >,
								_compound<_set<bxv, _const<1> >, _addeq<s2, _const<1> > >
							>,
							_if<_gt<_get<bx>, _get<right> >,
								_compound<
								_compound<_set<bx, _add<_get<right>, _const<-paddle_w> > >,
								_set<by, _add<_get<p2>, _const<paddle_h / 2> > > >,
									_compound<_set<bxv, _const<-1> >, _addeq<s1, _const<1> > >
								>,
								_nil
							>
						>
					>
				>
			>
		>,
		_compound<
			_compound<
				draw<score<_get<s1>, _get<s2> > >,
				draw<ball<_get<bx>, _get<by> > >
			>,
			_compound<
				_compound<
					draw<paddle<_get<left>, _get<p1> > >,
					draw<paddle<_add<_get<right>, _neg<_const<paddle_w> > >, _get<p2> > >
				>,
				draw<flip>
			>
		>
	>
> >();
