/* XBlockOut a 3D Tetris Copyright (C) 1992,1993,1994 Thierry EXCOFFIER 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. Contact: Thierry.EXCOFFIER@liris.univ-lyon1.fr */ /**********************************************/ /* To change demo : change function deep_fall */ /**********************************************/ #include "bl.h" #if HAVE_STRING_H #include #else #include #endif #ifndef abs #define abs(X) ( (X)>0 ? (X) : -(X) ) #endif #define KABOOM -1000000000 /***********************************************************************/ static struct bloc *w= NULL ; void save_world(struct bloc *b) { if ( w==0 ) w = allocbloc(b->dx,b->dy,b->dz+1) ; if ( w->dx != b->dx || w->dy != b->dy || w->dz != b->dz+1 ) { freebloc(w) ; w = 0 ; save_world(b) ; } memcpy( &w->t[0][0][0] , &b->t[0][0][0] , b->dx*b->dy*b->dz*sizeof(b->t[0][0][0]) ) ; } void restore_world(struct bloc *b) { memcpy( &b->t[0][0][0] , &w->t[0][0][0] , b->dx*b->dy*b->dz*sizeof(b->t[0][0][0]) ) ; } /*----------------------------------------------------------------------*/ /* Compute the value of the world */ /* If you want to change heuristic, change this function */ /*----------------------------------------------------------------------*/ int deep_fall(struct movingbloc *b, int *gk) { int i,j,k,l,m,nb ; int stz ; int score ; char *t ; int dx,dy,dz ; char *height,**theight,*tend ; static int powtwo[20] = { 0 } ; if ( powtwo[0]==0 ) { powtwo[0] = 10 ; for( i=1 ; iworld ) ; stz = b->tz ; while( intersection(b,b->world)==0 ) b->tz++ ; /* Fall */ if ( b->tz==stz ) return(KABOOM) ; b->tz-- ; *gk = b->tz ; delete_level(b,b->world) ; dx = b->world->dx ; dy = b->world->dy ; dz = b->world->dz ; nb = dx*dy ; score = 0 ; /* Compute weight and height of the world */ /* Also take into account the hole */ height = &w->t[dz][0][0] ; for(i=0;iworld->t[k][0][0]+nb ; height = &w->t[dz][0][0] ; for( t = &b->world->t[k][0][0] ; tt[dz][0][0] ; for(i=0;it[dz] ; for(i=0;itz = stz ; restore_world( b->world ) ; return(score) ; } /*----------------------------------------------------------------------*/ /* Try to drop the bloc at various position */ /*----------------------------------------------------------------------*/ #define DO_TEST \ { \ k = deep_fall(b,&ggk) ; \ if ( k==KABOOM ) break ; \ if ( k>gdeep ) \ { \ gdeep = k ; \ *gi = b->tx-stx ; \ *gj = b->ty-sty ; \ *gk = ggk ; \ } \ } int trans_deep(struct movingbloc *b, int *gi, int *gj, int *gk) { int k,gdeep,ggk,stx,sty ; stx = b->tx ; sty = b->ty ; gdeep = deep_fall(b,&ggk) ; *gi = 0 ; *gj = 0 ; *gk = ggk ; for(;b->tx<=b->world->dx-b->work->dx;b->tx++) /* Go to the right */ { /* Go down (jump to the case below central one because it is yet tested */ for(b->ty=sty+(b->tx==stx);b->ty<=b->world->dy-b->work->dy;b->ty++) DO_TEST ; /* Test up */ for(b->ty=sty-1;b->ty>=0;b->ty--) DO_TEST ; } for(b->tx=stx-1;b->tx>=0;b->tx--) /* Go to the left */ { /* Go down */ for(b->ty=sty;b->ty<=b->world->dy-b->work->dy;b->ty++) DO_TEST ; /* Test up */ for(b->ty=sty-1;b->ty>=0;b->ty--) DO_TEST ; } b->tx = stx ; b->ty = sty ; return(gdeep) ; } void demo(struct bl *bl) { int i,j,k ; int gi,gj,gk,gdeep ; int m ; int sr ; static int t,r ; static int mgi,mgj,mgk,mgdeep ; static struct movingbloc *b ; static int last_score ; #define TRY 200 #define PULL 201 #define STOPTRY 202 static int try[] = { RZP,TRY,RZP,TRY,PULL,RZN,TRY, PULL,RXP,TRY,RZP,TRY,RZP,TRY,RZP,TRY, /* 7 */ PULL,RXN,TRY,RZP,TRY,RZP,TRY,RZP,TRY, /* 16 */ PULL,RYP,TRY,RZP,TRY,RZP,TRY,RZP,TRY, /* 25 */ PULL,RYN,TRY,RZP,TRY,RZP,TRY,RZP,TRY, /* 34 */ PULL,RYP,RYP,TRY,RZP,TRY,RZP,TRY,RZP,TRY, /* 43 */ STOPTRY } ; if ( bl == 0 ) { last_score = -1 ; return ; } if ( last_score!=bl->score ) { last_score = bl->score ; t = -1 ; } m = 3*BETWEEN ; if ( t==-2 ) { static int tt[] = {TXP,TXN,TYP,TYN,RXP,RZP,RYP,RXN,RYN,RZN} ; /* Piece is down, now try to translate or rotate it to remove hole */ /* Or to best place it (end of game) */ /* I recompute best deep I do so because the piece fall and then, it possible I can't go to the best solution I found. and for the nest stage I need to know the correct value */ mgdeep = deep_fall(&bl->bloc,&i) ; r = -1 ; for( i=0 ; ibloc,1) ) /* Try transformation */ { while( addtransfo(TZP,0,&bl->bloc,1) ) ; gdeep = deep_fall(&bl->bloc,&gk) ; /* OK, look value */ if ( gdeep>mgdeep ) /* Best than previous */ { mgdeep = gdeep ; r = i ; } } pull_moving_bloc(b) ; } if ( r!=-1 ) { /* Add this one */ addtransfo(tt[r],m,&bl->bloc,m) ;/* Add and quit */ while( addtransfo(TZP,0,&bl->bloc,1) ) ; return ; } bl->realtime.lastfall = bl->realtime.lrtime+m/BETWEEN ; t = -3 ; /* Do not try any more thing before fall */ } if ( t==-3 ) return ; if ( t == -1 ) { b = &bl->bloc ; mgdeep = trans_deep(b,&mgi,&mgj,&mgk) ; r = 0 ; } push_moving_bloc(b) ; while( try[++t]!=STOPTRY ) switch(try[t]) { case PULL : pull_moving_bloc(b) ; return ; case TRY : gdeep = trans_deep(b,&gi,&gj,&gk) ; if ( gdeep>mgdeep ) { mgdeep=gdeep ; mgi=gi ; mgj=gj ; mgk=gk ; r = t ; } break ; default : if ( !addtransfo(try[t],0,b,1) ) { /* No more try */ while( try[t]!=PULL && try[t]!=STOPTRY ) t++ ; t-- ; } break ; } pull_moving_bloc(b) ; sr = r ; if ( r!=0 ) { while( r>=0 && try[r]!=PULL ) r-- ; r++ ; do { if ( try[r]!=TRY ) addtransfo(try[r],m,&bl->bloc,m) ; } while( r++bloc,m) ; for(i=0;i>mgi;i--) addtransfo(TXN,m,&bl->bloc,m) ; for(j=0;jbloc,m) ; for(j=0;j>mgj;j--) addtransfo(TYN,m,&bl->bloc,m) ; for(k=0;kbloc,m) ; t = -2 ; }