#include #include #include #include #include #include #include #include // // Describes one single puzzle. // class puzzle { protected: int width; int height; typedef std::vector content_type; content_type content; enum symbols { empty = 0, wall, box, goal, box_in_goal, worker }; public: puzzle() : width(0) , height(0) {} bool load( const std::string& name ) { // // Open file. // std::cout << "Loading " << name << "..." << std::flush; std::ifstream is( name ); if ( !is ) { std::cout << "file not found." << std::endl; return false; } // // Read line by line and calculate width and hight. // std::string line; while ( std::getline( is, line ) ) { width = std::max( width, (int)line.length() ); ++height; } // // Encode puzzle. // is.clear(); is.seekg(0); std::cout << "encoding..." << std::flush; content.resize(width*height); content_type::iterator it = content.begin(); while ( std::getline( is, line ) ) { for ( char c : line ) { switch ( c ) { case ' ': *it++ = empty; break; case '#': *it++ = wall; break; case '$': *it++ = box; break; case '.': *it++ = goal; break; case '*': *it++ = box_in_goal; break; case '@': *it++ = worker; break; default: throw std::runtime_error( std::string("Unexpected symbol '" )+c+"' found." ); } } for ( int i=0; i < width - line.length(); ++i) *it++ = empty; } std::cout << "done" << std::endl; return true; } int size() { return 2+width*height; } void encode( std::ostream& os ) { if ( width > height ) encode_as_is(os); else encode_rotated(os); } private: void encode_as_is( std::ostream& os ) { os << (char)width; os << (char)height; for ( char c : content ) os << c; } void encode_rotated( std::ostream& os ) { std::cout << "rotating." << std::endl; os << (char)height; os << (char)width; for ( int i = 0; i < width; ++i ) for ( int j = 0; j < height; ++j ) os << content[ j*width+i ]; } }; // // Describes catalog of puzzles. // class catalog { protected: typedef std::list puzzles_type; puzzles_type puzzles; typedef int i32; typedef i32 offset_type; typedef i32 count_type; public: ~catalog() { for ( auto p : puzzles ) delete p; } void push( puzzle * p ) { puzzles.push_back( p ); } void compile( std::ostream& os ) { std::cout << "Compiling." << std::endl; encode( os,(count_type)puzzles.size()); offset_type bgn = sizeof(count_type)+puzzles.size()*sizeof(offset_type); std::cout << "Table ... "; for ( puzzle * p : puzzles ) { encode(os,bgn); bgn += p->size(); } std::cout << "done." << std::endl; std::cout << "Puzzles..."; for ( puzzle * p : puzzles ) { p->encode(os); } std::cout << "done." << std::endl; } protected: template void encode( std::ostream& os, I i) { if ( sizeof(i) == 1 ) os << (char)i; else if ( sizeof(i) == 2 ) { os << (char)(i&0xff); os << (char)(i>>8&0xff); } else if ( sizeof(i) == 4 ) { os << (char)(i&0xff); os << (char)(i>>8&0xff); os << (char)(i>>16&0xff); os << (char)(i>>24&0xff); } } }; int main( void ) try { catalog c; // // Compile all screen_xxx.sokoban files where xxx is the level. // for ( int i = 1; true; ++i ) { std::ostringstream ss; ss << "screen_" << i << ".sokoban"; puzzle * p = new puzzle; if ( !p->load( ss.str()) ) { delete p; break; } c.push( p ); } std::ofstream os( "puzzles.bin", std::ios::binary ); c.compile( os ); return 0; } catch ( const std::exception& e ) { std::cout << "std::exception: " << e.what() << std::endl; } catch ( ... ) { std::cout << "unknown exception." << std::endl; }