Sokoban
Overview
Sokoban is a simple Japanese puzzle game from the 80's, although the rules are simple, levels can be deceptively hard.The main idea of Sokoban is a small grid board, containing walls, boxes, storage locations and a single player. The player moves around the board pushing boxes around until they manage to get all boxes stored in one of the storage locations! Feel free to check out the wikipedia entry for Sokoban too.
For this assignment, you will be building both a level generator for the game, as well as the mechanics to play your created levels!
The main idea of Sokoban is a small grid board, containing walls, boxes, storage locations and a single player. The player moves around the board pushing boxes around until they manage to get all boxes stored in one of the storage locations! Feel free to check out the wikipedia entry for Sokoban too.
For this assignment, you will be building both a level generator for the game, as well as the mechanics to play your created levels!
Getting Started
- Create a new folder for your assignment. Here is an example:
mkdir ass1
cd ass1
- Fetch the starter code using the command below. Alternatively download the starter code here.
1091 fetch-activity cs_sokoban
- Check that everything works by running the autotest.
1091 autotest cs_sokoban
(These should fail initially. If you want to exit running the autotest midway, press [ctrl-c]
.)
Initial Code and Data Structures
The starter code for this assignment includes some functions and defined types:
- A
print_board(...)
function:- This prints out the current state of the board, allowing the user to play the game.
- This ensures that the board will be consistent between you and the autotest.
- A
init_board(...)
function:- This sets up the board with default values.
- A
struct tile
struct:- Each square of the board (aka the 2D array) holds a
struct tile
. This tells us information about what is at that location in the board. - Note that the player location is stored separately to the contents of the board.
- Each square of the board (aka the 2D array) holds a
- A
enum base
enum:- This is used within
struct tile
. Every position on the board must be exactly 1 of these values (NONE
,WALL
, orSTORAGE
).
- This is used within
Reference Implementation
To help you understand how the assignment works, we have written a reference implementation for you to run. You can run it via the command 1091 cs_sokoban
.
1091 cs_sokoban === Level Setup === ...
FAQ
Stages
We have broken the assignment spec down into incremental stages:
- Stage 1: Level Builder - adding boxes, walls, and storage locations.
- Stage 2: Player Movement - adding player starting location, player movement and move counter.
- Stage 3: Core Game Mechanics - moving boxes, win condition, and reset level.
- Stage 4: Advanced Game Mechanics - undo command, pushing multiple boxes, and linking boxes.
- Extension (no marks): Adding graphics, multiple levels per game, and storing levels in text files.
Your Tasks
This assignment consists of four stages. Each stage builds on the work of the previous stage, and each stage has a higher complexity than its predecessor. You should complete the stages in order.
Stage 1
In Stage 1, you will set up the level builder for the Sokoban game. It includes asking the user for commands to place walls, boxes, and storage locations.
There is a reference implementation that you can play by running the command 1091 cs_sokoban
in the terminal.
Here is an example of input for a finished stage 1 that you can try within the reference implementation.
1091 cs_sokoban
w 0 0
s 1 1
s 10 10
b 1 0
b 1 1
W 0 0 9 0
[ctrl-d]
(note: the lowercase w
and capital W
are different commands)
In Stage 1, you will set up the level builder for the Sokoban game. It includes asking the user for commands to place walls, boxes, and storage locations.
There is a reference implementation that you can play by running the command 1091 cs_sokoban
in the terminal.
Here is an example of input for a finished stage 1 that you can try within the reference implementation.
1091 cs_sokoban w 0 0 s 1 1 s 10 10 b 1 0 b 1 1 W 0 0 9 0 [ctrl-d]
(note: the lowercase w
and capital W
are different commands)
Stage 1.1: Setting up level builder
To create a level builder, we need to give the user the ability to add items onto the board via commands until they decide to start playing the game. In this substage you will create a command loop that lets players add WALL
or STORAGE
to the board.
In this substage, you will need to do the following:
- Print out
=== Level Setup ===\n
. - Setup a loop for reading in commands.
- Given the command:
w [row] [col]
a wall will be placed at position [row][col]
. - Given the command:
s [row] [col]
a storage location will be placed at position [row][col]
. - Before reading in the next command, print out the board with the provided
print_board()
function. - The loop should stop when the user inputs
[ctrl-d]
.
Don't worry about error checking for this, we will cover that in a future stage :)
To create a level builder, we need to give the user the ability to add items onto the board via commands until they decide to start playing the game. In this substage you will create a command loop that lets players add WALL
or STORAGE
to the board.
In this substage, you will need to do the following:
- Print out
=== Level Setup ===\n
. - Setup a loop for reading in commands.
- Given the command:
w [row] [col]
a wall will be placed at position[row][col]
. - Given the command:
s [row] [col]
a storage location will be placed at position[row][col]
. - Before reading in the next command, print out the board with the provided
print_board()
function. - The loop should stop when the user inputs
[ctrl-d]
.
Don't worry about error checking for this, we will cover that in a future stage :)
Clarifications
- If a wall gets placed on a storage location, or vice versa, override the value.
- We will only test valid
row
and col
values within the map during this stage. - We will only test valid commands.
- If a wall gets placed on a storage location, or vice versa, override the value.
- We will only test valid
row
andcol
values within the map during this stage. - We will only test valid commands.
Examples:
Autotest
Stage 1.2: Array bounds checking
In stage 1.1, we didn't check if the given values are outside of the bounds of our array/board. Currently our program will crash in these cases, so let's fix that now!
In this substage, you will need to do the following:
- When the user enters the
w
or s
command, check that row
and col
are within the bounds of the board. If either one is out of bounds, print out Location out of bounds
and don't modify the board.
In stage 1.1, we didn't check if the given values are outside of the bounds of our array/board. Currently our program will crash in these cases, so let's fix that now!
In this substage, you will need to do the following:
- When the user enters the
w
ors
command, check thatrow
andcol
are within the bounds of the board. If either one is out of bounds, print outLocation out of bounds
and don't modify the board.
Clarifications
row
and col
will always be integer values.
row
andcol
will always be integer values.
Examples
Autotest
Examples
Autotest
Stage 1.4: Add lines of walls
Add the capital W
commmand to add lines of walls.
In this substage, you will need to the following:
- Given the command
W [start_row] [start_col] [end_row] [end_col]
, add a line of walls from [start_row][start_col]
to [end_row][end_col]
. - If both start and end locations are out of bounds, print
Location out of bounds
. - If only part of the line is out of bounds, add in the valid positions (ignore the out of bounds values) and don't print an error message.
Add the capital W
commmand to add lines of walls.
In this substage, you will need to the following:
- Given the command
W [start_row] [start_col] [end_row] [end_col]
, add a line of walls from[start_row][start_col]
to[end_row][end_col]
. - If both start and end locations are out of bounds, print
Location out of bounds
. - If only part of the line is out of bounds, add in the valid positions (ignore the out of bounds values) and don't print an error message.
Clarifications
- We will only ask for values that form horizontal or vertical lines. We will never ask for a diagonal line.
- We will only test values when
start_row
<= end_row
and start_col
<= end_col
- We will only ask for values that form horizontal or vertical lines. We will never ask for a diagonal line.
- We will only test values when
start_row
<=end_row
andstart_col
<=end_col
Examples
Autotest
Testing and Submission
Are you finished with this stage? If so, you should make sure to do the following:
- Run
1091 style
, and clean up any issues a human may have reading your code. Don't forget -- 20% of your mark in the assignment is based on style! - Autotest for this stage of the assignment by running the
autotest-stage
command as shown below. - Remember -- give early, and give often. Only your last submission counts, but why not be safe and submit right now?
1091 style cs_sokoban.c
1091 autotest-stage 01 cs_sokoban
give dp1091 ass1_cs_sokoban cs_sokoban.c
Are you finished with this stage? If so, you should make sure to do the following:
- Run
1091 style
, and clean up any issues a human may have reading your code. Don't forget -- 20% of your mark in the assignment is based on style! - Autotest for this stage of the assignment by running the
autotest-stage
command as shown below. - Remember -- give early, and give often. Only your last submission counts, but why not be safe and submit right now?
1091 style cs_sokoban.c 1091 autotest-stage 01 cs_sokoban give dp1091 ass1_cs_sokoban cs_sokoban.c