/*
Slider Puzzle 2.0
Copyright (C) 2000-2002,2007 Techno-Plaza
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 2
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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SLIDER_H
#define _SLIDER_H
/* Begin the constant definitions */
// define puzzle piece sprite height
#define PIECE_HEIGHT 16
/* Begin the static sprite definitions */
// define the puzzle sprites
// multi-dimensional array - a pointer of pointers...
// 16 sprites, 16 rows tall
static unsigned short int pieces[16][16] = {
{0xFFFF,0xC003,0x8001,0x8181,0x8781,0x8181,0x8181,0x8181,
0x8181,0x8181,0x8181,0x8181,0x8181,0x8001,0xC003,0xFFFF}, // piece 1
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8661,0x8061,0x80C1,
0x8181,0x8301,0x8601,0x8601,0x87E1,0x8001,0xC003,0xFFFF}, // piece 2
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8061,0x8061,0x81C1,
0x8061,0x8061,0x8061,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 3
{0xFFFF,0xC003,0x8001,0x80C1,0x81C1,0x83C1,0x83C1,0x86C1,
0x86C1,0x8CC1,0x8FF1,0x80C1,0x80C1,0x8001,0xC003,0xFFFF}, // piece 4
{0xFFFF,0xC003,0x8001,0x87E1,0x8601,0x8601,0x8601,0x87C1,
0x8661,0x8061,0x8061,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 5
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8601,0x8601,0x87C1,
0x8661,0x8661,0x8661,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 6
{0xFFFF,0xC003,0x8001,0x87E1,0x8061,0x80C1,0x80C1,0x8181,
0x8181,0x8181,0x8301,0x8301,0x8301,0x8001,0xC003,0xFFFF}, // piece 7
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8661,0x8661,0x83C1,
0x8661,0x8661,0x8661,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 8
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8661,0x8661,0x8661,
0x83E1,0x8061,0x8061,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 9
{0xFFFF,0xC003,0x8001,0x8C79,0xBCCD,0x8CCD,0x8CCD,0x8CCD,
0x8CCD,0x8CCD,0x8CCD,0x8CCD,0x8C79,0x8001,0xC003,0xFFFF}, // piece 10
{0xFFFF,0xC003,0x8001,0x8C31,0xBCF1,0x8C31,0x8C31,0x8C31,
0x8C31,0x8C31,0x8C31,0x8C31,0x8C31,0x8001,0xC003,0xFFFF}, // piece 11
{0xFFFF,0xC003,0x8001,0x8C79,0xBCCD,0x8CCD,0x8C0D,0x8C19,
0x8C31,0x8C61,0x8CC1,0x8CC1,0x8CFD,0x8001,0xC003,0xFFFF}, // piece 12
{0xFFFF,0xC003,0x8001,0x8CF1,0xBD99,0x8C19,0x8C19,0x8C71,
0x8C19,0x8C19,0x8C19,0x8D99,0x8CF1,0x8001,0xC003,0xFFFF}, // piece 13
{0xFFFF,0xC003,0x8001,0x8C0D,0xBC1D,0x8C3D,0x8C3D,0x8C6D,
0x8C6D,0x8CCD,0x8CFD,0x8C0D,0x8C0D,0x8001,0xC003,0xFFFF}, // piece 14
{0xFFFF,0xC003,0x8001,0x8CFD,0xBCC1,0x8CC1,0x8CC1,0x8CF9,
0x8CCD,0x8C0D,0x8C0D,0x8CCD,0x8C79,0x8001,0xC003,0xFFFF} // piece 15
};
/* Begin Function Proto-type Definitions Here */
// initialize the puzzle array
void initPuzzle(int *);
// randomize the puzzle position pieces
void randomizePuzzle(int *);
// draw the puzzle on screen
void drawPuzzle(int *, int *, int *);
// draw the background screen text
inline void drawScreen(void);
// create and play a new game
void newGame(int *, int *, int *);
// the main method -- program execution begins here
void _main(void);
#endif
Header files are one of the most important concepts in modularized
programming. They let us break down our programs into functions and
data, and keep track of both within a single file. Although header files
play a much bigger role when we are using multiple source files, it's
still a good idea to start using them in smaller projects so you can get
the feel of how they would be used when you start writing big projects
that really need them. With that in mind, let's take a look at some of
the things embedded in this header file.
#ifndef _SLIDER_H
#define _SLIDER_H
#endif
The first thing to notice about the header file is we have introduced
new preprocessor directives, the #ifndef and #endif directives. These
are very commonly used in C programming to help us in large programming
projects. Although the programs we write right now are small, it's good
to learn concepts which will make large program writing easier so that
when we start writing large programs, we will already have several good
techniques to use.
The #ifndef directive, in this context, is used to check to make sure a
header file is not included more than once. Since it's possible in a
large project that a header file might be included more than once, we
don't want to add extra definitions or anything duplicated which would
cause weird problems for the compiler. To combat this problem, we use
the #ifndef directive to check for a certain preprocessor variable. So,
if the variable _SLIDER_H is not defined, then we define that variable.
This makes sure that the next time we try to include this header,
_SLIDER_H will already be defined, and we will not include the header
file twice. Only the code inside the #ifndef and the #endif directives
will be included in this exclusionary clause. You can see these kinds of
directives used throughout the TIGCC header library. Just open up any
of the files and you will see these directives in place.
// define the puzzle sprites
// multi-dimensional array - a pointer of pointers...
// 16 sprites, 16 rows tall
static unsigned short int pieces[16][16] = {
{0xFFFF,0xC003,0x8001,0x8181,0x8781,0x8181,0x8181,0x8181,
0x8181,0x8181,0x8181,0x8181,0x8181,0x8001,0xC003,0xFFFF}, // piece 1
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8661,0x8061,0x80C1,
0x8181,0x8301,0x8601,0x8601,0x87E1,0x8001,0xC003,0xFFFF}, // piece 2
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8061,0x8061,0x81C1,
0x8061,0x8061,0x8061,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 3
{0xFFFF,0xC003,0x8001,0x80C1,0x81C1,0x83C1,0x83C1,0x86C1,
0x86C1,0x8CC1,0x8FF1,0x80C1,0x80C1,0x8001,0xC003,0xFFFF}, // piece 4
{0xFFFF,0xC003,0x8001,0x87E1,0x8601,0x8601,0x8601,0x87C1,
0x8661,0x8061,0x8061,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 5
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8601,0x8601,0x87C1,
0x8661,0x8661,0x8661,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 6
{0xFFFF,0xC003,0x8001,0x87E1,0x8061,0x80C1,0x80C1,0x8181,
0x8181,0x8181,0x8301,0x8301,0x8301,0x8001,0xC003,0xFFFF}, // piece 7
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8661,0x8661,0x83C1,
0x8661,0x8661,0x8661,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 8
{0xFFFF,0xC003,0x8001,0x83C1,0x8661,0x8661,0x8661,0x8661,
0x83E1,0x8061,0x8061,0x8661,0x83C1,0x8001,0xC003,0xFFFF}, // piece 9
{0xFFFF,0xC003,0x8001,0x8C79,0xBCCD,0x8CCD,0x8CCD,0x8CCD,
0x8CCD,0x8CCD,0x8CCD,0x8CCD,0x8C79,0x8001,0xC003,0xFFFF}, // piece 10
{0xFFFF,0xC003,0x8001,0x8C31,0xBCF1,0x8C31,0x8C31,0x8C31,
0x8C31,0x8C31,0x8C31,0x8C31,0x8C31,0x8001,0xC003,0xFFFF}, // piece 11
{0xFFFF,0xC003,0x8001,0x8C79,0xBCCD,0x8CCD,0x8C0D,0x8C19,
0x8C31,0x8C61,0x8CC1,0x8CC1,0x8CFD,0x8001,0xC003,0xFFFF}, // piece 12
{0xFFFF,0xC003,0x8001,0x8CF1,0xBD99,0x8C19,0x8C19,0x8C71,
0x8C19,0x8C19,0x8C19,0x8D99,0x8CF1,0x8001,0xC003,0xFFFF}, // piece 13
{0xFFFF,0xC003,0x8001,0x8C0D,0xBC1D,0x8C3D,0x8C3D,0x8C6D,
0x8C6D,0x8CCD,0x8CFD,0x8C0D,0x8C0D,0x8001,0xC003,0xFFFF}, // piece 14
{0xFFFF,0xC003,0x8001,0x8CFD,0xBCC1,0x8CC1,0x8CC1,0x8CF9,
0x8CCD,0x8C0D,0x8C0D,0x8CCD,0x8C79,0x8001,0xC003,0xFFFF} // piece 15
};
The next thing of note is our use of the sprite array. Last time, to
keep things simple, I defined 15 arrays for the sprites, and then a
pointer to all the sprite arrays so we could access them from a single
variable. Looking back, that may have been more confusing than just
doing this. But here is the basic premise of this array. Each of the 15
sprites are defined within a single array, but since we want to have all
the sprites accessible from a single variable, we need to have a
multidimensional array. Since we have 16 sprites, and they are 16 pixels
tall each, we have a 16 x 16 array, which is declared at the start as
pieces[16][16]. We have not used multidimensional arrays before, but the
premise is simple, we use two array indexes, the first array index
points to another array, and the second array index points to the
elements within that array. C gives us this way of easily thinking about
arrays in this manner, but in reality, the array is just a block of
memory the first index size length * the second index size length. So,
this array is basically the same as a pieces[256] array, but using the
multi-dimensional array marker makes it easier for us to think about it.
Although we use this giant array, all the data inside the array is
static, and as such, there is no need to make a dynamic array space for
it, because we already have to store all the integers associated with
the piece definitions anyway, so we can declare this as a global array
and save us the hassle of memory management, which won't help us here
anyway. Remember that if you have data in an array that never changes,
there is no reason to use dynamic memory allocation, because you can't
save any space.
You might remember from last time how I said the static keyword was
unnecessary. The same goes here. static in this context has nothing to
do with static memory.
/* Begin Function Proto-type Definitions Here */
// initialize the puzzle array
void initPuzzle(int *);
// randomize the puzzle position pieces
void randomizePuzzle(int *);
// draw the puzzle on screen
void drawPuzzle(int *, int *, int *);
// draw the background screen text
inline void drawScreen(void);
// create and play a new game
void newGame(int *, int *, int *);
// the main method -- program execution begins here
void _main(void);
The last thing to note is the function prototypes. Remember that we
should always define function prototypes for our functions. It just
makes it easy for the C compiler to find things, because you can't
always define functions before they are used by another function.
Although so far we have done this, it's easy to get mixed up when you
have a large number of functions to write.
Remember from lesson 4 that when we declare function prototypes, we use
the return type, function name, and argument return types, and follow
the prototype with a semicolon. There is no need to add names to the
return types of arguments inside function prototypes, but you can if you
want. This is up to you.
This is all I really wanted to cover about the program. The rest of the
program is nearly identical to the first slider puzzle version, with the
small exception of all the code being inside the _main() method. If you
have more questions about this, you should consult the first review
lesson.