Last active
January 6, 2017 23:57
-
-
Save apg/6557becbe8d631a85e6e01009e606184 to your computer and use it in GitHub Desktop.
dirt simple sokoban game supporting 8x8 boards.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* soklevel.c: dirt simple sokoban ASCII > sokobon.c compatible | |
* level editor. | |
* | |
* Copyright 2017: Andrew Gwozdziewycz <[email protected]> | |
* | |
* 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 3 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, see <http://www.gnu.org/licenses/>. | |
* | |
* | |
* Usage: soklevel < level.txt | |
* | |
* Level's should be no more than 8x8. | |
* Each line should end with a newline, on column 9 or less. | |
* The defines below give you the format of the rest. | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#define WALL '#' | |
#define PLAYER '@' | |
#define PLAYER_ON_GOAL '+' | |
#define BOX '$' | |
#define BOX_ON_GOAL '*' | |
#define GOAL '.' | |
unsigned char walls[8] = { | |
0, 0, 0, 0, 0, 0, 0, 0 | |
}; | |
unsigned char boxes[8] = { | |
0, 0, 0, 0, 0, 0, 0, 0 | |
}; | |
unsigned char goals[8] = { | |
0, 0, 0, 0, 0, 0, 0, 0 | |
}; | |
int playerx = 0; | |
int playery = 0; | |
static void | |
bitset(unsigned char *x, int b) | |
{ | |
*x |= (1 << b); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
char buf[10]; | |
char *out; | |
int i, y = 0, x = 0; | |
while ((out = fgets(buf, 10, stdin)) && y < 8) { | |
for (x = 0; buf[x] != '\n' && buf[x] != '\0'; x++) { | |
switch (buf[x]) { | |
case WALL: | |
bitset(&(walls[y]), 7-x); | |
break; | |
case BOX: | |
bitset(&(boxes[y]), 7-x); | |
break; | |
case BOX_ON_GOAL: | |
bitset(&(boxes[y]), 7-x); | |
bitset(&(goals[y]), 7-x); | |
break; | |
case GOAL: | |
bitset(&(goals[y]), 7-x); | |
break; | |
case PLAYER: | |
playerx = x; | |
playery = y; | |
break; | |
case PLAYER_ON_GOAL: | |
playerx = x; | |
playery = y; | |
bitset(&(goals[y]), 7-x); | |
break; | |
} | |
} | |
y++; | |
} | |
printf(".walls = {"); | |
for (i = 0; i < 7; i++) { | |
printf("0x%x, ", walls[i]); | |
} | |
printf("0x%x", walls[7]); | |
printf("},\n"); | |
printf(".goals = {"); | |
for (i = 0; i < 7; i++) { | |
printf("0x%x, ", goals[i]); | |
} | |
printf("0x%x", goals[7]); | |
printf("},\n"); | |
printf(".boxes = {"); | |
for (i = 0; i < 7; i++) { | |
printf("0x%x, ",boxes[i]); | |
} | |
printf("0x%x", boxes[7]); | |
printf("},\n"); | |
printf(".x = %d,\n", playerx); | |
printf(".y = %d\n", playery); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* sokoban.c: dirt simple sokoban game supporting 8x8 boards | |
* | |
* Copyright 2017: Andrew Gwozdziewycz <[email protected]> | |
* | |
* 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 3 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, see <http://www.gnu.org/licenses/>. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#define WALL '#' | |
#define PLAYER '@' | |
#define PLAYER_ON_GOAL '+' | |
#define BOX '$' | |
#define BOX_ON_GOAL '*' | |
#define GOAL '.' | |
#define FLOOR ' ' | |
#define UP 'w' | |
#define LEFT 'a' | |
#define DOWN 's' | |
#define RIGHT 'd' | |
#define INBOUNDS(x, y, min, max) \ | |
((x >= min) && (y >= min) && (x < max) && (y < max)) | |
struct game { | |
unsigned char walls[8]; | |
unsigned char boxes[8]; | |
unsigned char goals[8]; | |
char x; | |
char y; | |
} games[2] = { | |
{ | |
.walls = {0xF8, 0x88, 0xF8, 0x0, 0x0, 0x0, 0x0, 0x0}, | |
.goals = {0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, | |
.boxes = {0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, | |
.x = 1, | |
.y = 1 | |
}, | |
{ | |
.walls = {0xfe, 0x8a, 0x82, 0x82, 0x82, 0x82, 0xfe, 0x0}, | |
.goals = {0x0, 0x40, 0x20, 0x0, 0x30, 0x10, 0x0, 0x0}, | |
.boxes = {0x0, 0x0, 0x68, 0x8, 0x0, 0x10, 0x0, 0x0}, | |
.x = 2, | |
.y = 1 | |
} | |
}; | |
struct game game; | |
static int | |
bittest(unsigned char x, int b) | |
{ | |
return x & (1 << b); | |
} | |
static void | |
bitset(unsigned char *x, int b) | |
{ | |
*x |= (1 << b); | |
} | |
static void | |
bitclr(unsigned char *x, int b) | |
{ | |
*x ^= (1 << b); | |
} | |
static void | |
move(int dx, int dy) | |
{ | |
int tx = game.x + dx; | |
int ty = game.y + dy; | |
// potential next box position. | |
int bx = 0; | |
int by = 0; | |
// general bounds checking | |
if (!INBOUNDS(tx, ty, 0, 8)) { | |
return; | |
} | |
// in a wall? | |
if (bittest(game.walls[ty], 7-tx)) { | |
return; | |
} | |
// Pushing up against a box? | |
if (bittest(game.boxes[ty], 7-tx)) { | |
// possibly push the box. | |
bx = tx + dx; | |
by = ty + dy; | |
if (!INBOUNDS(bx, by, 0, 8)) { | |
return; | |
} | |
// Wall prohibits box from moving there. | |
if (bittest(game.walls[by], 7-bx)) { | |
return; | |
} | |
// Box prohibits other box from moving there. | |
if (bittest(game.boxes[by], 7-bx)) { | |
return; | |
} | |
// unset box at tx, ty | |
// set box at bx, by | |
bitclr(&(game.boxes[ty]), 7-tx); | |
bitset(&(game.boxes[by]), 7-bx); | |
} | |
game.x = tx; | |
game.y = ty; | |
} | |
static int | |
wins() | |
{ | |
int y; | |
for (y = 0; y < 8; y++) { | |
if (game.boxes[y] != game.goals[y]) { | |
return 0; | |
} | |
} | |
return 1; | |
} | |
static int draw() | |
{ | |
int x, y; | |
int player = 0; | |
int goal = 0; | |
int box = 0; | |
for (y = 0; y < 8; y++) { | |
if (game.walls[y] == 0 && y > 3) { | |
break; | |
} | |
for (x = 0; x < 8; x++) { | |
if (bittest(game.walls[y], 7-x)) { | |
putchar(WALL); | |
continue; | |
} | |
player = (game.x == x && game.y == y) ? 1: 0; | |
box = bittest(game.boxes[y], 7-x); | |
goal = bittest(game.goals[y], 7-x); | |
if (player && goal) { | |
putchar(PLAYER_ON_GOAL); | |
} else if (player) { | |
putchar(PLAYER); | |
} else if (box && goal) { | |
putchar(BOX_ON_GOAL); | |
} else if (box) { | |
putchar(BOX); | |
} else if (goal) { | |
putchar(GOAL); | |
} else { | |
putchar(FLOOR); | |
} | |
} | |
putchar('\n'); | |
} | |
putchar('\n'); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
int c, moves = 0, gamei; | |
game = games[0]; | |
if (argc == 2) { | |
gamei = atoi(argv[1]); | |
if (gamei >= 0 && gamei < 2) { | |
game = games[gamei]; | |
} | |
} | |
draw(); | |
while (c = getchar()) { | |
if (c == '\n') { | |
continue; | |
} | |
switch (c) { | |
case UP: | |
move(0, -1); | |
break; | |
case DOWN: | |
move(0, 1); | |
break; | |
case LEFT: | |
move(-1, 0); | |
break; | |
case RIGHT: | |
move(1, 0); | |
break; | |
default: | |
continue; | |
} | |
moves++; | |
if (wins()) { | |
draw(); | |
printf("Congratulations! You won in %d moves.\n", moves); | |
return 0; | |
} | |
draw(); | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./sokoban | |
##### | |
#@$.# | |
##### | |
w | |
##### | |
#@$.# | |
##### | |
a | |
##### | |
#@$.# | |
##### | |
d | |
##### | |
#_@*# | |
##### | |
Congratulations! You won in 3 moves. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment