File indexing completed on 2021-12-21 12:50:21

0001 /*
0002  *  ksokoban - a Sokoban game by KDE
0003  *  Copyright (C) 1998  Anders Widell  <d95-awi@nada.kth.se>
0004  *
0005  *  This program is free software; you can redistribute it and/or modify
0006  *  it under the terms of the GNU General Public License as published by
0007  *  the Free Software Foundation; either version 2 of the License, or
0008  *  (at your option) any later version.
0009  *
0010  *  This program is distributed in the hope that it will be useful,
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  *  GNU General Public License for more details.
0014  *
0015  *  You should have received a copy of the GNU General Public License
0016  *  along with this program; if not, write to the Free Software
0017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018  */
0019 
0020 #include <stdlib.h>
0021 #include <string.h>
0022 #include <assert.h>
0023 #include <stdio.h>
0024 
0025 #include "Map.h"
0026 
0027 Map::Map() : xpos_(-1), ypos_(-1), width_(0), height_(0), objectsLeft_(-1) {
0028 }
0029 
0030 
0031 void
0032 Map::map (int x, int y, int val) {
0033   assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y);
0034   if ((map (x, y) & (OBJECT | GOAL)) == OBJECT) objectsLeft_--;
0035   if ((val & (OBJECT | GOAL)) == OBJECT) objectsLeft_++;
0036   currentMap_[y+1][x+1] = val;
0037 
0038   if (val != 0) {
0039     if (width_ <= x) width_ = x+1;
0040     if (height_ <= y) height_ = y+1;
0041   }
0042 }
0043 
0044 void
0045 Map::setMap (int x, int y, int bits) {
0046   assert ((map (x, y) & bits) == 0);
0047   if (goal (x, y) && ((bits & OBJECT) == OBJECT)) objectsLeft_--;
0048   assert (objectsLeft_ >= 0);
0049   currentMap_[y+1][x+1] |= bits;
0050 
0051   if (bits != 0) {
0052     if (width_ <= x) width_ = x+1;
0053     if (height_ <= y) height_ = y+1;
0054   }
0055 }
0056 
0057 void
0058 Map::clearMap (int x, int y, int bits) {
0059   assert ((map (x, y) & bits) == bits);
0060   if (goal (x, y) && ((bits & OBJECT) == OBJECT)) objectsLeft_++;
0061   currentMap_[y+1][x+1] &= ~bits;
0062 }
0063 
0064 void
0065 Map::clearMap () {
0066   memset (currentMap_, 0, (MAX_Y+3)*(MAX_X+3)*sizeof (char));
0067   objectsLeft_ = 0;
0068   width_ = height_ = 0;
0069 }
0070 
0071 bool
0072 Map::fillFloor (int x, int y) {
0073   if (badCoords (x, y)) return false;
0074   if ((currentMap_[y+1][x+1] & (WALL|FLOOR)) != 0) return true;
0075 
0076   currentMap_[y+1][x+1] |= FLOOR;
0077   bool a = fillFloor (x, y-1);
0078   bool b = fillFloor (x, y+1);
0079   bool c = fillFloor (x-1, y);
0080   bool d = fillFloor (x+1, y);
0081 
0082   return a && b && c && d;
0083 }
0084 
0085 bool
0086 Map::step (int _x, int _y) {
0087   assert (!badCoords (xpos_, ypos_));
0088   assert (empty (xpos_, ypos_));
0089 
0090   int xd=0, yd=0;
0091   if (_x < xpos_) xd = -1;
0092   if (_x > xpos_) xd =  1;
0093   if (_y < ypos_) yd = -1;
0094   if (_y > ypos_) yd =  1;
0095   if (badDelta (xd, yd) || badCoords (_x, _y)) return false;
0096 
0097   int x=xpos_, y=ypos_;
0098   do {
0099     x += xd;
0100     y += yd;
0101     if (!empty (x, y)) return false;
0102   } while (!(x==_x && y==_y));
0103 
0104   xpos_ = _x;
0105   ypos_ = _y;
0106 
0107   return true;
0108 }
0109 
0110 bool
0111 Map::push (int _x, int _y) {
0112   assert (!badCoords (xpos_, ypos_));
0113   assert (empty (xpos_, ypos_));
0114 
0115   int xd=0, yd=0;
0116   if (_x < xpos_) xd = -1;
0117   if (_x > xpos_) xd =  1;
0118   if (_y < ypos_) yd = -1;
0119   if (_y > ypos_) yd =  1;
0120   if (badDelta (xd, yd) || badCoords (_x+xd, _y+yd)) return false;
0121 
0122   int x=xpos_+xd, y=ypos_+yd;
0123   if (!object (x, y)) return false;
0124   if (!empty (_x+xd, _y+yd)) return false;
0125 
0126   while (!(x==_x && y==_y)) {
0127     x += xd;
0128     y += yd;
0129     if (!empty (x, y)) return false;
0130   }
0131 
0132   clearMap (xpos_+xd, ypos_+yd, OBJECT);
0133   setMap (_x+xd, _y+yd, OBJECT);
0134 
0135   xpos_ = _x;
0136   ypos_ = _y;
0137 
0138   return true;
0139 }
0140 
0141 bool
0142 Map::unstep (int _x, int _y) {
0143   return Map::step (_x, _y);
0144 }
0145 
0146 bool
0147 Map::unpush (int _x, int _y) {
0148   assert (!badCoords (xpos_, ypos_));
0149   assert (empty (xpos_, ypos_));
0150 
0151   int xd=0, yd=0;
0152   if (_x < xpos_) xd = -1;
0153   if (_x > xpos_) xd =  1;
0154   if (_y < ypos_) yd = -1;
0155   if (_y > ypos_) yd =  1;
0156   if (badDelta (xd, yd) || badCoords (_x+xd, _y+yd)) return false;
0157 
0158   int x=xpos_, y=ypos_;
0159   if (!object (x-xd, y-yd)) return false;
0160 
0161   do {
0162     x += xd;
0163     y += yd;
0164     if (!empty (x, y)) return false;
0165   } while (!(x==_x && y==_y));
0166 
0167   clearMap (xpos_-xd, ypos_-yd, OBJECT);
0168   setMap (_x-xd, _y-yd, OBJECT);
0169 
0170   xpos_ = _x;
0171   ypos_ = _y;
0172 
0173   return true;
0174 }
0175 
0176 void
0177 Map::printMap(void) {
0178   for (int y=0; y<height_; y++) {
0179     for (int x=0; x<width_; x++) {
0180       switch (map (x, y) & ~FLOOR) {
0181       case WALL:
0182     printf("#");
0183     break;
0184       case GOAL:
0185     printf("%c", x==xpos_ && y==ypos_ ? '+' : '.');
0186     break;
0187       case OBJECT:
0188     printf("$");
0189     break;
0190       case OBJECT|GOAL:
0191     printf("*");
0192     break;
0193       case 0:
0194     printf("%c", x==xpos_ && y==ypos_ ? '@' : ' ');
0195     break;
0196       default:
0197     printf("<%X>", map(x,y)&FLOOR);
0198     break;
0199       }
0200     }
0201     printf ("\n");
0202   }
0203 }
0204