#include <stdio.h>
#include <stdlib.h>
enum FloorType {
floor, goal, wall
};
enum ObjectType {
box, player, empty
};
enum Direction {
up, right, down, left
};
class Sokoban;
class Map;
class MapManager;
class Map {
public:
int width;
int height;
FloorType **floorMatrix;
ObjectType **objectMatrix;
};
class MapManager {
public :
void printMap(Map *map) {
int width = map->width;
int height = map->height;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
char charToPrint;
if (map->floorMatrix[i][j] == floor && map->objectMatrix[i][j] == empty) {
charToPrint = ' ';
} else if (map->floorMatrix[i][j] == floor && map->objectMatrix[i][j] == player) {
charToPrint = 'p';
} else if (map->floorMatrix[i][j] == floor && map->objectMatrix[i][j] == box) {
charToPrint = 'o';
} else if (map->floorMatrix[i][j] == goal && map->objectMatrix[i][j] == empty) {
charToPrint = '.';
} else if (map->floorMatrix[i][j] == goal && map->objectMatrix[i][j] == player) {
charToPrint = 'P';
} else if (map->floorMatrix[i][j] == goal && map->objectMatrix[i][j] == box) {
charToPrint = 'O';
} else if (map->floorMatrix[i][j] == wall) {
charToPrint = '#';
}
printf("%c", charToPrint);
}
printf("\n");
}
}
Map *phaseStringToMap(char *string[], int width, int height) {
Map *map = new Map();
map->width = width;
map->height = height;
map->floorMatrix = (FloorType**) (malloc(sizeof(FloorType*) * height));
map->objectMatrix = (ObjectType**) (malloc(sizeof(ObjectType*) * height));
for (int i = 0; i < height; i++) {
map->floorMatrix[i] = (FloorType*) (malloc(sizeof(FloorType)* width));
map->objectMatrix[i] = (ObjectType*)(malloc(sizeof(ObjectType)* width));
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (string[i][j] == ' ') {
map->floorMatrix[i][j] = floor;
map->objectMatrix[i][j] = empty;
} else if (string[i][j] == '#') {
map->floorMatrix[i][j] = wall;
map->objectMatrix[i][j] = empty;
} else if (string[i][j] == 'p') {
map->floorMatrix[i][j] = floor;
map->objectMatrix[i][j] = player;
} else if (string[i][j] == 'P') {
map->floorMatrix[i][j] = goal;
map->objectMatrix[i][j] = player;
} else if (string[i][j] == '.') {
map->floorMatrix[i][j] = goal;
map->objectMatrix[i][j] = empty;
} else if (string[i][j] == 'o') {
map->floorMatrix[i][j] = floor;
map->objectMatrix[i][j] = box;
} else if (string[i][j] == 'O') {
map->floorMatrix[i][j] = goal;
map->objectMatrix[i][j] = box;
} else {
map->floorMatrix[i][j] = floor;
map->objectMatrix[i][j] = empty;
}
}
}
return map;
}
};
class Sokoban {
public:
Sokoban() {
mapManager = new MapManager();
map = NULL;
playerX = -1;
playerY = -1;
numberOfGoals = 0;
numberOfFilledGoals = 0;
numberOfMoves = 0;
}
void setGame(Map *newMap) {
map = newMap;
for (int i = 0; i < map->height; i++) {
for (int j = 0; j < map->width; j++) {
if (map->floorMatrix[i][j] == wall) {
map->objectMatrix[i][j] = empty;
} else if (map->floorMatrix[i][j] == goal) {
numberOfGoals++;
}
if (map->objectMatrix[i][j] == player) {
if (playerX >= 0) {
map->objectMatrix[playerY][playerX] = empty;
}
playerX = j;
playerY = i;
}
}
}
update();
}
void movePlayer(Direction direction) {
if (moveObject(playerX, playerY, direction) == true) {
numberOfMoves++;
update();
}
}
void print() {
mapManager->printMap(map);
printf("%d, %d, %d\n", numberOfGoals, numberOfFilledGoals, numberOfMoves);
}
private:
MapManager *mapManager;
Map *map;
int playerX;
int playerY;
int numberOfGoals;
int numberOfFilledGoals;
int numberOfMoves;
bool moveObject(int x, int y, Direction direction) {
int frontX = x;
int frontY = y;
if (direction == up) {
frontY -= 1;
}
else if (direction == right) {
frontX += 1;
}
else if (direction == down) {
frontY += 1;
}
else if (direction == left) {
frontX -= 1;
}
if (frontX < 0 || frontX >= map->width || frontY < 0 || frontY >= map->height) {
return false;
}
ObjectType thisObject = map->objectMatrix[y][x];
FloorType thisFloor = map->floorMatrix[y][x];
ObjectType frontObject = map->objectMatrix[frontY][frontX];
FloorType frontFloor = map->floorMatrix[frontY][frontX];
if (thisFloor == wall) {
return false;
}
else if (thisObject == empty) {
return true;
}
else if (thisObject == box && (frontObject == box || frontFloor == wall)) {
return false;
}
else if (moveObject(frontX, frontY, direction) == true) {
map->objectMatrix[frontY][frontX] = map->objectMatrix[y][x];
map->objectMatrix[y][x] = empty;
return true;
}
else {
return false;
}
}
void update() {
numberOfFilledGoals = 0;
for (int i = 0; i < map->height; i++) {
for (int j = 0; j < map->width; j++) {
if (map->objectMatrix[i][j] == box) {
if (map->floorMatrix[i][j] == goal) {
numberOfFilledGoals++;
}
}
else if (map->objectMatrix[i][j] == player) {
playerY = i;
playerX = j;
}
}
}
}
};
int main() {
char *string[] = {
"########",
"# .. p #",
"# o o #",
"# p #",
"########"
};
char input;
MapManager *mapManager = new MapManager();
Map *map = mapManager->phaseStringToMap(string, 8, sizeof(string) / sizeof(string[0]));
Sokoban *sokoban = new Sokoban();
sokoban->setGame(map);
while (true) {
sokoban->print();
printf(":");
scanf_s("%c%*c", &input);
if (input == 'w') {
sokoban->movePlayer(up);
} else if (input == 'd') {
sokoban->movePlayer(right);
} else if (input == 's') {
sokoban->movePlayer(down);
} else if (input == 'a') {
sokoban->movePlayer(left);
}
}
}