class TreeGenerator {
	protected:
		static size_t MAX_DEPTH;
		static size_t MAX_LENGTH;
		std::string m_Str;

		int randint ( int lo, int hi ) const {
			return rand ( ) % ( hi - lo + 1 ) + lo;
		}

	public:
		std::string generate ( ) {
			m_Str.clear ( );
			m_Str += "RANKED_TREE ";
			S ( );
			return m_Str;
		}

		virtual ~TreeGenerator ( ) {
		}

	private:
		virtual void S ( size_t depth = 1 ) = 0;
};

size_t TreeGenerator::MAX_DEPTH = 200;
size_t TreeGenerator::MAX_LENGTH = 1000;

/** Generator for rte1.xml */
class TreeGenerator1 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			S2 ( depth + 1 );
			m_Str += ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) ? "b 0 " : "c 0 ";
		}

		void S2 ( size_t depth ) {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 )
				return;

			m_Str += "d 1 ";
			m_Str += "a 2 ";
			S2 ( depth + 1 );
			m_Str += randint ( 0, 1 ) == 0 ? "b 0 " : "c 0 ";
		}
};

/** Generator for rte2.xml */
class TreeGenerator2 : public TreeGenerator {
	private:
		void S ( size_t /* depth = 1 */ ) override {
			m_Str += "a 2 b 0 b 0 ";
		}
};

/** Generator for rte3.xml */
class TreeGenerator3 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += "b 0 ";
				return;
			}

			m_Str += "a 2 ";
			S ( depth + 1 );
			S ( depth + 1 );
		}
};

/** Generator for rte4.xml */
class TreeGenerator4 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += "a 2 b 0 b 0 ";
				return;
			}

			m_Str += "a 2 ";
			S ( depth + 1 );
			S ( depth + 1 );
		}
};

/** Generator for rte5.xml */
class TreeGenerator5 : public TreeGenerator {
	private:
		void S ( size_t /* depth = 1 */ ) override {
			m_Str += "a 0 ";
		}
};

/** Generator for rte6.xml */
class TreeGenerator6 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			m_Str += "a 2 ";
			SL ( depth + 1 );
			SR ( depth + 1 );
		}

		void SL ( size_t depth ) {
			int r = randint ( 0, 1 );
			if ( r == 0 || depth > MAX_DEPTH )
				m_Str += "b 0 ";
			else if ( r == 1 )
				S ( depth + 1 );
		}

		void SR ( size_t depth ) {
			int r = randint ( 0, 1 );
			if ( r == 0 || depth > MAX_DEPTH )
				m_Str += "c 0 ";
			else if ( r == 1 )
				S ( depth + 1 );
		}
};

/** Generator for rte7.xml */
class TreeGenerator7 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			S2 ( depth + 1 );
			m_Str += "a 2 c 0 b 0 ";
		}

		void S2 ( size_t depth ) {
			if ( depth > MAX_DEPTH || randint ( 0, 2 ) == 0 )
				return;

			m_Str += "d 1 ";
			S2 ( depth + 1 );
		}
};

/** Generator for rte8.xml */
class TreeGenerator8 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += std::string ( 1, 'b' + randint ( 0, 3 ) ) + " 0 ";
				return;
			}

			m_Str += "a 2 ";
			S ( depth + 1 );
			S ( depth + 1 );
		}
};

/** Generator for rte9.xml */
class TreeGenerator9 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += "b 0 ";
			} else {
				m_Str += "a 2 ";
				S ( depth + 1 );
				S ( depth + 1 );
			}
		}
};

/** Generator for rte0.xml */
class TreeGenerator0 : public TreeGenerator {
	private:
		void S ( size_t depth = 1 ) override {
			a1 ( depth );
		}

		void a1 ( size_t depth ) {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += "d 0 ";
			} else {
				m_Str += "a 1 ";
				if ( randint ( 0, 1 ) == 0 ) {
					b1 ( depth + 1 );
				} else {
					c1 ( depth + 1 );
				}
			}
		}

		void b1 ( size_t depth ) {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += "d 0 ";
			} else {
				m_Str += "b 1 ";
				if ( randint ( 0, 1 ) == 0 ) {
					b1 ( depth + 1 );
				} else {
					a1 ( depth + 1 );
				}
			}
		}

		void c1 ( size_t depth ) {
			if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) {
				m_Str += "d 0 ";
			} else {
				m_Str += "c 1 ";
				if ( randint ( 0, 1 ) == 0 ) {
					c1 ( depth + 1 );
				} else {
					a1 ( depth + 1 );
				}
			}
		}
};
