215 lines
3.6 KiB
C++
215 lines
3.6 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
#include <list>
|
|
#include <string>
|
|
#include <functional>
|
|
|
|
//
|
|
// Describes one single puzzle.
|
|
//
|
|
class puzzle
|
|
{
|
|
protected:
|
|
int width;
|
|
int height;
|
|
typedef std::vector<char> content_type;
|
|
content_type content;
|
|
enum symbols {
|
|
empty = 0,
|
|
wall,
|
|
box,
|
|
goal,
|
|
box_in_goal,
|
|
worker
|
|
};
|
|
|
|
public:
|
|
puzzle()
|
|
: width(0)
|
|
, height(0)
|
|
{}
|
|
|
|
void load( const std::string& name )
|
|
{
|
|
std::cout << "Loading " << name << "..." << std::flush;
|
|
std::ifstream is( name );
|
|
std::stringstream ss;
|
|
//
|
|
// Read line by line and calculate width and hight.
|
|
//
|
|
std::string line;
|
|
while ( std::getline( is, line ) )
|
|
{
|
|
ss << line << std::endl;
|
|
width = std::max( width, (int)line.length() );
|
|
++height;
|
|
}
|
|
//
|
|
// Encode puzzle.
|
|
//
|
|
std::cout << "encoding..." << std::flush;
|
|
content.resize(width*height);
|
|
content_type::iterator it = content.begin();
|
|
while ( std::getline( ss, 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;
|
|
}
|
|
|
|
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<puzzle*> puzzles_type;
|
|
puzzles_type puzzles;
|
|
|
|
typedef int i32;
|
|
typedef i32 offset_type;
|
|
typedef i32 count_type;
|
|
|
|
public:
|
|
|
|
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 <class I>
|
|
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;
|
|
|
|
for ( int i = 1; i <= 90; ++i )
|
|
{
|
|
std::stringstream ss;
|
|
ss << "screen_" << i << ".sokoban";
|
|
puzzle * p = new puzzle;
|
|
p->load( ss.str());
|
|
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;
|
|
}
|
|
|
|
|