diff options
| -rw-r--r-- | dbox.c | 1081 | ||||
| -rw-r--r-- | depend.mak | 1 | ||||
| -rw-r--r-- | level0 | 5 | ||||
| -rw-r--r-- | level1 | 10 | ||||
| -rw-r--r-- | level14 | 9 | ||||
| -rw-r--r-- | level15 | 9 | ||||
| -rw-r--r-- | level4 | 10 | ||||
| -rw-r--r-- | level5 | 10 | ||||
| -rw-r--r-- | level73 | 14 | ||||
| -rw-r--r-- | levelA | 6 | ||||
| -rw-r--r-- | levelB | 5 | ||||
| -rw-r--r-- | levelC | 7 | ||||
| -rw-r--r-- | levelD | 9 | ||||
| -rw-r--r-- | levelE | 12 | ||||
| -rw-r--r-- | makefile | 57 | ||||
| -rw-r--r-- | mktar | 11 | 
16 files changed, 1256 insertions, 0 deletions
| @@ -0,0 +1,1081 @@ +/* + +    dbox - Sokoban level solver + +    Copyright (C) 2001  Ian Cowburn (ianc@noddybox.demon.co.uk) + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +    ------------------------------------------------------------------------- + +*/ +static const char cvs_id[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> + +#if (USECURSES == ncurses) +#  include <ncurses.h> +#else +#  include <curses.h> +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +static const int DEBUG=TRUE; +static char *name; + +/* Stop the program once this much memory is allocated. +   Set to -1 to disable the check +*/ +#define MAXMB		-1 + +#define MEGABYTE	(1024*1024) + +/* ---------------------------------------- TYPES +*/ +typedef signed char	PosInt; +typedef unsigned char	Byte; +typedef Byte		Bool; + +typedef char		Route[1024]; + +typedef enum {SPACE_GL=' ', +	      WALL_GL='#', +	      PLAYER_GL='@', +	      BOX_GL='B', +	      TARGET_GL='.', +	      BOX_TARGET_GL='X'} Glyph; + +typedef enum {SPACE, WALL} MapChar; + +typedef enum {QUIET,CSV,VERBOSE} LogMode; + +#define DIR_NONE	-1 +#define DIR_LEFT	0 +#define DIR_UP		1 +#define DIR_RIGHT	2 +#define DIR_DOWN	3 + +typedef struct +	{ +	PosInt		x; +	PosInt		y; +	} Pos; + +static const Pos move_dir[4]={{-1,0},{0,-1},{1,0},{0,1}}; + +typedef struct State +	{ +	Pos		player; +	Pos		*box; +	Bool		path; +	Byte		dir; +	Bool		pushed; +	int		hash; +	struct State	*left; +	struct State	*right; +	struct State	*up; +	struct State	*down; +	struct State	*parent; +	struct State	*next; +	} State; + +typedef struct +	{ +	char		*name; +	int		width,height; +	int		no; +	Pos		*target; +	MapChar		*map; +	State		*state; +	} Level; + +#define STATE_HASH	0x10000 + +typedef struct StateMap +	{ +	State		*s; +	struct StateMap	*next; +	} StateMap; + +static StateMap		*state_map[STATE_HASH]={NULL}; +static int		state_map_no=0; + +#define AT(l,x,y)	((l)->map[(l)->width*(y)+(x)]) + + +/* ---------------------------------------- PROTOS +*/ +static void	*Grab(size_t l); + +static void	Interactive(Level *l, int play); + +static Level	*Load(const char *path); +static void	FreeLevel(Level *l); +static void	Display(Level *level, State *state); +static char	GetGlyph(Level *level, State *state, int x, int y); +static State	*CreateState(Byte dir, Bool must_push, Level *l, State *s, +			     Bool check_possible); +static void	Solve(Level *level, Route route, int max_depth, LogMode log); + + +/* ---------------------------------------- MAIN +*/ +int main(int argc, char *argv[]) +{ +    int interact=FALSE; +    int play=FALSE; +    int base; +    int f; +    LogMode mode=VERBOSE; + +    name=argv[0]; + +    if (argc<2) +    	{ +	fprintf(stderr,"%s: usage %s [-i|-p] file [file2 ...]\n",name,name); +	return EXIT_FAILURE; +	} + +    if (strcmp(argv[1],"-i")==0) +	{ +	interact=TRUE; +	base=2; +	} +    else if (strcmp(argv[1],"-p")==0) +	{ +	interact=TRUE; +	play=TRUE; +	base=2; +	} +    else if (strcmp(argv[1],"-c")==0) +	{ +	interact=FALSE; +	mode=CSV; +	base=2; +	} +    else +    	base=1; + +    if (argc<=base) +	{ +	fprintf(stderr,"%s: usage %s [-c|-i|-p] file [file2 ...]\n",name,name); +	return EXIT_FAILURE; +	} + +    for(f=base;f<argc;f++) +	{ +	Route route; +	Level *level; + +	if (!(level=Load(argv[f]))) +	    { +	    fprintf(stderr,"%s: %s could not be read\n",name,argv[f]); +	    } +	else +	    { +	    if (interact) +	    	Interactive(level,play); +	    else +	    	{ +		printf("Solving %s\n\n",level->name); + +		Display(level,level->state); + +		Solve(level,route,999,mode); + +		printf("\nRoute = '%s'\n",route); +		} + +	    FreeLevel(level); +	    } +	} + +    return EXIT_SUCCESS; +} + + +/* ---------------------------------------- UTIL +*/ +static size_t grab_tot=0; +static int grab_last_mb=0; +static int grab_mb=0; + +static void *Grab(size_t l) +{ +    size_t *p; + +    p=malloc(l+sizeof(size_t)); + +    if (!p) +    	{ +	fprintf(stderr,"%s: malloc(%d) failed\n",name,l); +	exit(EXIT_FAILURE); +	} + +    *p=l; + +    grab_tot+=l; + +    grab_mb=grab_tot/MEGABYTE; + +    if (grab_last_mb!=grab_mb) +    	{ +	grab_last_mb=grab_mb; + +	if (grab_mb==MAXMB) +	    { +	    fprintf(stderr,"Quitting: Allocated %d Mb\n",grab_mb); +	    exit(EXIT_FAILURE); +	    } +	} + +    return p+1; +} + + +static void Release(void *p) +{ +    size_t *pp; + +    pp=p; + +    pp--; + +    grab_tot-=*pp; + +    free(pp); +} + + +static int GrabSize(void) +{ +    return grab_mb; +} + + +static Pos *FindPos(Pos *p, int no, int x, int y) +{ +    int f; + +    for (f=0;f<no;f++) +	if (p[f].x==x && p[f].y==y) +	    return p+f; + +    return NULL; +} + + +/* ---------------------------------------- LEVEL LOADING +*/ +static char *GetLine(FILE *fp) +{ +    static char s[1024]; + +    fgets(s,sizeof s,fp); + +    if (feof(fp)) +	return NULL; + +    if (s[strlen(s)-1]=='\n') +	s[strlen(s)-1]=0; + +    return s; +} + +static Level *Load(const char *path) +{ +    FILE *fp; +    char *line; +    Level *new; +    int x,y; +    int tno,bno; +    int pno; + +    if (!(fp=fopen(path,"r"))) +    	return NULL; + +    new=Grab(sizeof *new); + +    line=GetLine(fp); +    new->name=Grab(strlen(line)+1); +    strcpy(new->name,line); + +    new->no=atoi(GetLine(fp)); + +    /* Calc sizes +    */ +    new->width=strlen(GetLine(fp)); +    new->height=1; + +    while((line=GetLine(fp))) +    	{ +	new->height++; + +	if (strlen(line)!=new->width) +	    { +	    fprintf(stderr,"%s: '%s' (line %d) too short " +			    "(should be %d wide)\n", +			    	name,line,new->height,new->width); +	    exit(EXIT_FAILURE); +	    } +	} + +    /* Rewind file and skip first two lines +    */ +    rewind(fp); +    GetLine(fp); +    GetLine(fp); + +    new->target=Grab(sizeof(Pos)*new->no); +    new->map=Grab(sizeof(MapChar)*(new->width*new->height)); + +    new->state=Grab(sizeof(State)); +    new->state->parent=NULL; +    new->state->next=NULL; +    new->state->box=Grab(sizeof(Pos)*new->no); +    new->state->left=new->state->right=new->state->up=new->state->down=NULL; +    new->state->dir=DIR_NONE; + +    tno=0; +    bno=0; +    pno=0; + +    for(y=0;y<new->height;y++) +	{ +	line=GetLine(fp); + +	if (strlen(line)<new->width) +	    { +	    fprintf(stderr,"%s: line '%s' too short " +			    "(should be %d wide)\n",name,line,new->width); +	    exit(EXIT_FAILURE); +	    } + +	for(x=0;x<new->width;x++) +	    switch(line[x]) +	    	{ +		case WALL_GL: +		    AT(new,x,y)=WALL; +		    break; + +		case SPACE_GL: +		    AT(new,x,y)=SPACE; +		    break; + +		case BOX_TARGET_GL: +		case TARGET_GL: +		    if (tno==new->no) +		    	{ +			fprintf(stderr,"%s: too many " +					"targets in %s\n",name,path); + +			exit(EXIT_FAILURE); +			} + +		    AT(new,x,y)=SPACE; +		    new->target[tno].x=x; +		    new->target[tno].y=y; +		    tno++; + +		    /* NOTE: Runs into following case +		    */ +		    if (line[x]==TARGET_GL) +			break; + +		case BOX_GL: +		    if (bno==new->no) +		    	{ +			fprintf(stderr,"%s: too many " +					"boxes in %s\n",name,path); + +			exit(EXIT_FAILURE); +			} + +		    AT(new,x,y)=SPACE; +		    new->state->box[bno].x=x; +		    new->state->box[bno].y=y; +		    bno++; +		    break; + +		case PLAYER_GL: +		    if (pno++==1) +		    	{ +			fprintf(stderr,"%s: too many " +					"players in %s\n",name,path); + +			exit(EXIT_FAILURE); +			} + +		    AT(new,x,y)=SPACE; +		    new->state->player.x=x; +		    new->state->player.y=y; +		    break; +		} +	} + +    fclose(fp); + +    if (pno==0) +	{ +	fprintf(stderr,"%s: no player definied in %s\n",name,path); + +	exit(EXIT_FAILURE); +	} + +    return new; +} + + +static void FreeLevel(Level *l) +{ +} + + +static void Display(Level *level, State *state) +{ +    int x,y; + +    for(y=0;y<level->height;y++) +	{ +	for(x=0;x<level->width;x++) +	    putchar(GetGlyph(level,state,x,y)); + +	putchar('\n'); +	} +} + + +static char GetGlyph(Level *level, State *state, int x, int y) +{ +    if (AT(level,x,y)==WALL) +	return WALL_GL; +    else if (FindPos(&state->player,1,x,y)) +	return PLAYER_GL; +    else if (FindPos(state->box,level->no,x,y) && +		FindPos(level->target,level->no,x,y)) +	return BOX_TARGET_GL; +    else if (FindPos(state->box,level->no,x,y)) +	return BOX_GL; +    else if (FindPos(level->target,level->no,x,y)) +	return TARGET_GL; +    else +	return SPACE_GL; + +} + + +/* ---------------------------------------- SOLVER +*/ +static void FreeState(State *s) +{ +    Release(s->box); +    Release(s); +} + + +static void ClearStates(void) +{ +    int f; + +    state_map_no=0; + +    for(f=0;f<STATE_HASH;f++) +	while(state_map[f]) +	    { +	    StateMap *p; +	    p=state_map[f]->next; +	    Release(state_map[f]); +	    state_map[f]=p; +	    } +} + + +static Bool AddNewState(Level *l, State *s) +{ +    StateMap *p; +    int hash; + +    hash=s->hash%STATE_HASH; + +    p=state_map[hash]; + +    while(p) +    	{ +	if (s->player.x==p->s->player.x && s->player.y==p->s->player.y) +	    { +	    int f; +	    int ok; + +	    ok=FALSE; + +	    for(f=0;f<l->no && !ok;f++) +	    	if (s->box[f].x!=p->s->box[f].x || s->box[f].y!=p->s->box[f].y) +		    ok=TRUE; + +	    if (!ok) +	    	return FALSE; +	    } + +	p=p->next; +	} + +    p=Grab(sizeof *p); + +    p->s=s; +    p->next=state_map[hash]; +    state_map[hash]=p; + +    state_map_no++; + +    return TRUE; +} + + +static int GetStateNum(void) +{ +    return state_map_no; +} + + +static const char *NoMoveReason(char *fmt,...) +{ +    static char r[512]; +    va_list va; + +    va_start(va,fmt); + +    if (fmt) +	vsprintf(r,fmt,va); + +    va_end(va); + +    return r; +} + + +static Bool CheckImpossible(Level *l, State *s) +{ +    int f; + +    for(f=0;f<l->no;f++) +    	{ +	int x,y; + +	x=s->box[f].x; +	y=s->box[f].y; + +	if (!FindPos(l->target,l->no,x,y)) +	    { +	    int d; +	    int any_move; + +	    /* Check that the box can be pushed at all for the next go +	       (Simple wall based check) +	    */ +	    any_move=FALSE; + +	    for(d=0;d<4 && !any_move;d++) +	    	{ +		int nx,ny; + +		nx=x+move_dir[d].x; +		ny=y+move_dir[d].y; + +		if (AT(l,nx,ny)!=WALL) +		    { +		    int ox,oy; + +		    ox=x+move_dir[(d+2)%4].x; +		    oy=y+move_dir[(d+2)%4].y; + +		    if (AT(l,ox,oy)!=WALL) +		    	any_move=TRUE; +		    } +		} + +	    if (!any_move) +	    	{ +		NoMoveReason("Couldn't push block at %d,%d",x,y); +		return TRUE; +		} + +	    /* Four blocks together is impossible +	    */ +	    if (FindPos(s->box,l->no,x+1,y) && FindPos(s->box,l->no,x,y+1) && +	    					FindPos(s->box,l->no,x+1,y+1)) +		{ +		NoMoveReason("Group of 4 boxes at %d,%d",x,y); +	    	return TRUE; +		} +	    } +	} + +    return FALSE; +} + + +static State *CreateState(Byte dir, Bool must_push, +			  Level *l, State *s, Bool check_possible) +{ +    State *new; +    Pos *p; +    int x,y; +    int push; +    int dx,dy; +    int f; + +    dx=move_dir[dir].x; +    dy=move_dir[dir].y; + +    push=FALSE; + +    x=s->player.x+dx; +    y=s->player.y+dy; + +    /* Check for walls +    */ +    if (AT(l,x,y)==WALL) +    	return NULL; + +    /* Check for boxes +    */ +    if ((p=FindPos(s->box,l->no,x,y))) +    	{ +	int bx,by; + +	/* Can the box be pushed? +	*/ +	bx=p->x+dx; +	by=p->y+dy; + +	if (AT(l,bx,by)==WALL) +	    return NULL; + +	if (FindPos(s->box,l->no,bx,by)) +	    return NULL; + +	push=TRUE; +	} + +    if (!push && must_push) +    	return NULL; + +    new=Grab(sizeof *new); +    new->box=Grab(sizeof(Pos)*l->no); +    memcpy(new->box,s->box,sizeof(Pos)*l->no); + +    new->player.x=x; +    new->player.y=y; + +    if (push) +    	{ +	p=FindPos(new->box,l->no,x,y); + +	p->x+=dx; +	p->y+=dy; + +	/* (Very) basic checks to see if the move has made the level impossible +	*/ +	if (check_possible && CheckImpossible(l,new)) +	    { +	    FreeState(new); +	    return NULL; +	    } +	} + + +    new->left=NULL; +    new->right=NULL; +    new->up=NULL; +    new->down=NULL; + +    new->parent=s; +    new->next=NULL; + +    new->path=FALSE; +    new->pushed=push; +    new->dir=dir; + +    /* Calculate a hash based on box and player positions  +    */ +    new->hash=0; + +    for(f=0;f<l->no;f++) +	new->hash+=new->box[f].x+new->box[f].y*l->height; + +    new->hash+=(STATE_HASH>>2)+new->box[f].x+new->box[f].y*l->height; + +    if (!AddNewState(l,new)) +    	{ +	NoMoveReason("State matches previous"); +	FreeState(new); +	return NULL; +	} + +    return new; +} + + +static void SetChain(State **first, State **curr, State *new) +{ +    if (new) +	{ +	if (!*first) +	    { +	    *first=new; +	    *curr=*first; +	    } +	else +	    { +	    (*curr)->next=new; +	    (*curr)=new; +	    } +	} +} + + +static void SubSolve(Level *level, State *state,int depth, +		     int max_depth, LogMode log) +{ +    static time_t last=0; +    State *first; +    State *curr; +    State *new; +    State *s; +    int ok; +    int f; + +    if (depth>=max_depth) +    	return; + +    if (depth==1) +    	last=time(NULL); + +    switch(log) +    	{ +	case QUIET: +	    break; +	case VERBOSE: +	    printf("Searching %d moves deep " +			"(%ld secs, used %dMb - %d unique states)\n", +			    depth,time(NULL)-last,GrabSize(),GetStateNum()); +	    break; +	case CSV: +	    printf("%d,%ld,%d,%d\n", +			    depth,time(NULL)-last,GrabSize(),GetStateNum()); +	    break; +	} + +    last=time(NULL); + +    /* Loop across all states at this depth +    */ +    s=state; +    first=NULL; +    curr=NULL; + +    while(s) +    	{ +	/* Check to see whether the level is solved +	*/ +	ok=TRUE; + +	for(f=0;(f<level->no) && ok;f++) +	    if (!FindPos(s->box,level->no, +	    		 level->target[f].x,level->target[f].y)) +		ok=FALSE; + +	if (ok) +	    { +	    s->path=TRUE; +	    s=s->parent; + +	    while(s) +		{ +	    	s->path=TRUE; +		s=s->parent; +		} +	    return; +	    } + +	/* Check moves +	*/ +	if (s->dir==DIR_RIGHT) +	    s->left=new=CreateState(DIR_LEFT,!s->pushed,level,s,TRUE); +	else +	    s->left=new=CreateState(DIR_LEFT,FALSE,level,s,TRUE); + +	SetChain(&first,&curr,new); + +	if (s->dir==DIR_LEFT) +	    s->right=new=CreateState(DIR_RIGHT,!s->pushed,level,s,TRUE); +	else +	    s->right=new=CreateState(DIR_RIGHT,FALSE,level,s,TRUE); + +	SetChain(&first,&curr,new); + +	if (s->dir==DIR_DOWN) +	    s->up=new=CreateState(DIR_UP,!s->pushed,level,s,TRUE); +	else +	    s->up=new=CreateState(DIR_UP,FALSE,level,s,TRUE); + +	SetChain(&first,&curr,new); + +	if (s->dir==DIR_UP) +	    s->down=new=CreateState(DIR_DOWN,!s->pushed,level,s,TRUE); +	else +	    s->down=new=CreateState(DIR_DOWN,FALSE,level,s,TRUE); + +	SetChain(&first,&curr,new); + +	s=s->next; +	} + +    if (first) +	SubSolve(level,first,++depth,max_depth,log); +} + + +static void Solve(Level *level, Route route, int max_depth, LogMode log) +{ +    State *s; + +    route[0]=0; +    ClearStates(); + +    SubSolve(level,level->state,1,max_depth,log); + +    s=level->state; + +    while(s) +    	{ +	if (s->left && s->left->path) +	    { +	    strcat(route,"L"); +	    s=s->left; +	    } +	else if (s->right && s->right->path) +	    { +	    strcat(route,"R"); +	    s=s->right; +	    } +	else if (s->up && s->up->path) +	    { +	    strcat(route,"U"); +	    s=s->up; +	    } +	else if (s->down && s->down->path) +	    { +	    strcat(route,"D"); +	    s=s->down; +	    } +	else +	    s=NULL; +	} +} + + +/* ---------------------------------------- INTERACTIVE MODE +*/ +static void CursesDisplay(Level *l, State *s, int play) +{ +    int x,y,f; +    char allow[80]; + +    for(x=0;x<l->width;x++) +	{ +	char num[20]; + +	sprintf(num,"%d",x); + +	f=0; +	while(num[f]) +	    mvaddch(3+f,3+x,num[f++]); + +	for(y=0;y<l->height;y++) +	    { +	    if (x==0) +	    	mvprintw(6+y,0,"%d",y); + +	    mvaddch(6+y,3+x,GetGlyph(l,s,x,y)); +	    } +	} + +    strcpy(allow,"Moves: "); + +    if (s->left) +    	strcat(allow,"left "); + +    if (s->right) +    	strcat(allow,"right "); + +    if (s->up) +    	strcat(allow,"up "); + +    if (s->down) +    	strcat(allow,"down "); + +    if (s->parent) +    	strcat(allow,"back"); + +    while(strlen(allow)<70) +    	strcat(allow,"     "); + +    mvaddstr(l->height+11,0,allow); + +    if (!play) +    	{ +	if (s->path) +	    mvaddstr(l->height+10,0,"On solved path: YES"); +	else +	    mvaddstr(l->height+10,0,"On solved path: NO "); +	} +    else +    	{ +	int depth=0; + +	while(s) +	    { +	    depth++; +	    s=s->parent; +	    } + +	mvprintw(l->height+10,0,"Depth: %d ",depth); +	} + +    mvprintw(LINES-3,0,"Last reason: %-40.40s",NoMoveReason(NULL)); + +    refresh(); +} + + +static void Interactive(Level *l, int play) +{ +    int quit; +    Route route; +    State *s; + +    if (!play) +	Solve(l,route,999,VERBOSE); + +    initscr(); +    cbreak(); +    noecho(); +    nonl(); +    intrflush(stdscr,FALSE); +    keypad(stdscr,TRUE); + +    quit=FALSE; +    s=l->state; + +    clear(); +    mvaddstr(0,0,l->name); + +    mvaddstr(LINES-1,0,"Cursors to move, P to follow path, " +    			"Q to quit, Backspace/B to step back"); + +    if (!play) +	mvprintw(l->height+9,0,"Route:%s",route); + +    while(!quit) +    	{ +	int key; + +	CursesDisplay(l,s,play); + +	key=getch(); + +	if (key=='p' || key=='P') +	    { +	    if (s->left && s->left->path) +	    	key=KEY_LEFT; + +	    if (s->right && s->right->path) +	    	key=KEY_RIGHT; + +	    if (s->up && s->up->path) +	    	key=KEY_UP; + +	    if (s->down && s->down->path) +	    	key=KEY_DOWN; +	    } + +	switch(key) +	    { +	    case KEY_BACKSPACE: +	    case 'b': +	    case 'B': +		if (s->parent) +		    s=s->parent; +	    	break; + +	    case KEY_LEFT: +		if (play && !s->left) +		    s->left=CreateState(DIR_LEFT,FALSE,l,s,TRUE); + +		if (s->left) +		    s=s->left; +	    	break; + +	    case KEY_RIGHT: +		if (play && !s->right) +		    s->right=CreateState(DIR_RIGHT,FALSE,l,s,TRUE); + +		if (s->right) +		    s=s->right; +	    	break; + +	    case KEY_DOWN: +		if (play && !s->down) +		    s->down=CreateState(DIR_DOWN,FALSE,l,s,TRUE); + +		if (s->down) +		    s=s->down; +	    	break; + +	    case KEY_UP: +		if (play && !s->up) +		    s->up=CreateState(DIR_UP,FALSE,l,s,TRUE); + +		if (s->up) +		    s=s->up; +	    	break; + +	    case 'q': +	    case 'Q': +	    	quit=TRUE; +		break; + +	    default: +	    	break; +	    } +	} + +    endwin(); +} + + +/* END OF FILE */ diff --git a/depend.mak b/depend.mak new file mode 100644 index 0000000..65af7b3 --- /dev/null +++ b/depend.mak @@ -0,0 +1 @@ +dbox.o: dbox.c @@ -0,0 +1,5 @@ +Test Level +2 +####### +#.B@B.# +####### @@ -0,0 +1,10 @@ +Level 1 +4 +  ###    +  #.#    +  # #### +###B B.# +#. B@### +####B#   +   #.#   +   ###   @@ -0,0 +1,9 @@ +Level 14 +6 +######## +#  #   # +# B..B # +#@B.X ## +# B..B # +#  #   # +######## @@ -0,0 +1,9 @@ +Level 15 +6 + ####### +##    #  +# B BB # +#......# +# BB B # +### @### +  ####   @@ -0,0 +1,10 @@ +Level 4 +5 + ####  +##  #  +#@B #  +##B ## +## B # +#.B  # +#..X.# +###### @@ -0,0 +1,10 @@ +Level 5 +3 + #####   + #@ ###  + # B  #  +### # ## +#.# #  # +#.B  # # +#.   B # +######## @@ -0,0 +1,14 @@ +Level 73 +12 +       ######## +       #  #   # + ####### BB...# + #        #...# + # ######B#...# +## #      #...# +#  # #B B ##### +# # B B B #     +# @  B #  #     +#####B BB #     +    #     #     +    #######     @@ -0,0 +1,6 @@ +Test Level +2 +##### +#@B.# +# B.# +##### @@ -0,0 +1,5 @@ +Test Level +2 +####### +#.B@B.# +####### @@ -0,0 +1,7 @@ +Test Level +1 +######### +#####   # +#@B     # +#####.### +    ###   @@ -0,0 +1,9 @@ +Test Level +3 +######### +#@      # +# #  #  # +# #BB#  # +# #  #  # +#.B.   .# +######### @@ -0,0 +1,12 @@ +Test Level +2 +########## +#@       # +#     #  # +#   B    # +#     #  # +# B      # +# .      # +#     #  # +#       .# +########## diff --git a/makefile b/makefile new file mode 100644 index 0000000..9cc2e62 --- /dev/null +++ b/makefile @@ -0,0 +1,57 @@ +# +# +#    dbox - Sokoban solver +# +#    Copyright (C) 2001  Ian Cowburn (ianc@noddybox.demon.co.uk) +# +#    This program is free software; you can redistribute it and/or modify +#    it under the terms of the GNU General Public License as published by +#    the Free Software Foundation; either version 2 of the License, or +#    (at your option) any later version. +# +#    This program is distributed in the hope that it will be useful, +#    but WITHOUT ANY WARRANTY; without even the implied warranty of +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +#    GNU General Public License for more details. +# +#    You should have received a copy of the GNU General Public License +#    along with this program; if not, write to the Free Software +#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +# +#    ------------------------------------------------------------------------- +# + + +TARGET	=	dbox + +SOURCES	=	dbox.c + +HEADERS	= + +OBJECTS	=	$(SOURCES:.c=.o) + +LIBS	=	-lncurses + +FLAGS	=	-O2 -g -Wall -pedantic -ansi + +DEPEND	=	depend.mak + +$(TARGET): $(OBJECTS) +	$(CC) $(FLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) + +%.o: %.c +	$(CC) $(CFLAGS) $(CPPFLAGS) $(FLAGS) $(TRACE) -c $< -o $@ + +-include depend.mak + +clean: +	-rm $(TARGET) $(TARGET).exe core *.stackdump *.o depend.mak + +depend: $(DEPEND) +	@echo Dependencies updated.... + +$(DEPEND): $(SOURCES) $(HEADERS) +	$(CC) -MM $(SOURCES) > $(DEPEND) + + +# END OF FILE @@ -0,0 +1,11 @@ +#!/bin/bash + +FILE=dbox.tar.gz + +make clean +tar cvfz $FILE level* makefile mktar *.c + +if [ `uname` != "Linux" ] ; +then +    mv $FILE ~/desktop +fi | 
