Note: I wasn't sure whether this should be under Turing Tutorials or General Programming. Although the game is written in Turing, the lessons here may be applicable to game programming in other (imperative) languages.
What is this About?
In this series of lessons, we'll be exploring a simple way of designing and programming an entire game. As this is a Basic tutorial, our game will be fairly basic as well: we will write a Minesweeper clone.
To understand this tutorial, you should know variable declarations and picture use, and most importantly arrays.
Game Design - Listing Specifications
Normally, we would have to come up with a set of rules and gameplay elements for our game. However, since we're just cloning Minesweeper, we can skip this step. All we have to do is list the rules and gameplay of Minesweeper:
- The game is played on a grid of squares. For our purposes, we will assume that the maximum game size is 100 squares on a side.
- Some of these squares are filled with a mine, while others are empty.
- The objective of the game is to flag all of the mines and reveal all of the empty spaces without setting off any of the mines.
- The player plays by clicking on the squares of the grid. Left-clicking on a square reveals the square, while right-clicking cycles between no marking, a flag and a question mark.
- If the player reveals a mine, it explodes and the player loses the game.
- Once all of the grid squares empty grid squares have been cleared and all of the mines have been flagged correctly, the player wins.
- The only information that the players get towards solving the puzzle is that each non-mine cleared shows the number of mines in adjacent squares.
Program Design - Laying the Foundation
We'll start by deciding how we're going to store information for our game.
The core of the program will be a two-dimensional array of squares. Each square can be represented by a pair of integers, which we will give various values to represent various states. One number will represent the state of the square (mine, empty or a number), while the other will represent the user state (untouched, cleared, flagged or question-mark). So, we define the following:
% MAP and USER-STATE constants
% Anything between these two values are taken as the literal numerical values displayed in each square.
const MAP_MINE : int := 10
const MAP_EMPTY : int := 0
const USER_NONE : int := 0 % User hasn't yet interacted with the square
const USER_REVEALED : int := 1 % User has revealed the square
const USER_FLAGGED : int := 2 % User has flagged the square as a mine
const USER_QUESTION : int := 3 % User has marked the square as a question mark
% MAP and STATE
var map : array 1..100, 1..100 of int
var user_state : array 1..100, 1..100 of int
There are several different states each square can be in, and since we want to express these all with images. Here is a listing of all possible states:
- None - these squares have not been cleared or marked in any way yet.
- Flag - these squares have been given a "mine here!" flag.
- Question Mark - these squares have been assigned a question mark.
- Explosion - this image is only used if the player loses the game, and appears in the square with the mine they exploded.
- Flagged-Empty - this image is only used if the player loses the game; it appears on squares which were incorrectly flagged by the player.
- Bomb - this image is only used if the player loses the game; it appears on squares which contain a mine but have not been flagged by the player.
- Numbers - these images appear in revealed squares which are adjacent to some number of mines.
pic_base_flag : int := Pic.FileNew ( "flag.bmp" )
pic_base_none : int := Pic.FileNew ( "none.bmp" )
pic_base_boom : int := Pic.FileNew ( "exploded_bomb.bmp" )
pic_base_bomb : int := Pic.FileNew ( "bomb.bmp" )
pic_base_flagged_empty : int := Pic.FileNew ( "flagged_empty.bmp" )
pic_base_question : int := Pic.FileNew ( "question.bmp" )
pic_base_number : array 0
..8 of int := init ( 0
i : 0
..8 % This is a clever trick. The files are named "number1.bmp", "number2.bmp", etc, which lets us automatically load these files by their sequential names.
i) := Pic.FileNew ( "number"
You might wonder why these variables have "base" in them. This is because we will need to scale each image, which we'll be doing into a set of non-base pictures:
% All of the following are initialized to -10 (picture not yet created)
var pic_flag, pic_none, pic_boom, pic_bomb, pic_question, pic_flagged_empty : int := -10
var pic_number : array 0..8 of int := init ( -10,-10,-10,-10,-10,-10,-10,-10,-10 )
In the next lesson, we'll initialize the scaled images and place the mines, then we'll move on to drawing the map. In the meantime, feel free to reply to this post with comments, criticisms or concerns.[/list]