A General’s View – Complete Game

Author’s Note: I mentioned in my last post that I had been working on my final year project for college. Just wanted to share what I came up with in the end. The project is a two-player game based on A General’s View, the tabletop strategy game that I designed in 2015 and is written using the Allegro 4 game library. The game is not particularly sophisticated and there are a few interface bugs that need to be ironed out, but it works and could be used for the basis of a more sophisticated game in the future.

The game is played by two human players with the following controls:

Map keys

Up, Down, Left, Right – move cursor

Enter – enter menu

Menu keys

Up, Down – move cursor

Enter – select menu option highlighted by cursor

For full rules and objectives of the game, please see A General’s View: Rules (Alpha Version). Please note that in this version of the game, at most one unit from each player can occupy a tile at once.

The game (in both Windows executable and source code forms) can be downloaded from the following link: https://drive.google.com/folderview?id=0B_lGPZTjA4fzbHN4YVExelBEejA&usp=sharing

unit_moving

Screenshot_20160229_200035

The C Preprocessor

One of the peculiar things about the C programming language is that so many commonly occurring elements are not actually part of the language, per se. All of the functions in the standard library are actually extensions to C, additional parts which give us the input/output, mathematical and utility features which make C powerful. All of these are contained in a set of header files and binaries which are added to programs during the compilation process.

Another extension to C is the C preprocessor, and it is this that gives us the ability to extend the language to perform functions. The C preprocessor is a sort of computer language of its own sort, and while it is not Turing-complete, it is useful enough for the purposes for which it is called. The C preprocessor reads through a C source file, replacing various statements which are important to the preprocessor to ones which are important to the C compiler.

It is somewhat difficult to explain why the C preprocessor is important, but I will attempt to do so with a brief segue into the history of computer languages. Early high-level programming languages, such as Fortran and COBOL, were notable for being able to do one set of tasks very well and most others not so well at all. In some cases, this led to deficiencies which would be considered ghastly today; ALGOL 58 and 60, for instance, did not define any input/output operations, and any I/O routines would be completely machine-dependent.

In the later 1960s, language designers attempted to create new languages which would be suitable for multi-purpose applications. However, these languages, which included PL/I and ALGOL 68, were designed by committees who were made up of conflicting personalities, many of which were desperate to see their pet features included in the languages. As the complexity of the languages grew, so did the complexity of developing an efficient compiler. As computing resources were vastly smaller than they are now, these languages were only suitable for mainframe computers, and then not even efficiently.

Therefore, these language experiments tended to fail. PL/I has some residual support by being supported by IBM, but it is moribund outside of the confines of IBM machines; ALGOL 68 is dead and buried. When C came around, Dennis Ritchie was aiming to create a language which both implemented enough features in order to build an operating system and its applications, while being able to run efficiently on a much less powerful computer than those for which PL/I was designed.

The solution was to create a system in which only the subset of the functions that were required for a specific program would be implemented, rather than the full set. This made compilation of C more efficient, as the compiler generally only had to be concerned with a small number of functions at once. The method chosen to do this was to use the C preprocessor to keep the function definitions of most functions outside of the base language; when C was standardised in 1989 by the ANSI committee, and in 1990 by the ISO, all functions were taken out of the base language and put into header files.

Now that the history lesson is over, we can continue on to the operations of the preprocessor. As mentioned above, the preprocessor scans a C source file – or, in some circumstances, another source file; Brian Kernighan famously developed RATFOR to add similar features to Fortran as in C – and looks for statements that are important to it. It then replaces them with statements that are important to the C compiler or whatever other system the preprocessor is being used for.

The most fundamental operation of the preprocessor is #include. This operation looks for a file which is defined at a path included in the #include directive, then inserts its entire contents into the source file in place of the #include directive. The file’s contents might themselves contain C preprocessor statements, as is common in C header files, so the preprocessor goes through those and acts upon them appropriately.

One of the most common invocations of the #include directive is the following:

#include <stdio.h>

This directive locates the file, stdio.h, and places its contents into a source file. The use of angle brackets around the filename indicates that it is stored in a directory whose path is known to the C compiler, and which is defined as the standard storage path for header files. stdio.h itself contains several preprocessor statements, including #define and #include statements, which are resolved by the preprocessor appropriately.

Let’s define a simple program which can be used to test this. The program will be the standard “hello, world” program as defined in The C Programming Language (Brian Kernighan & Dennis Ritchie, 2nd Edition).

#include <stdio.h>

main()
{
    printf("hello, world\n");
}

Now, we can see some of the results when this is passed through the C preprocessor:

typedef long unsigned int size_t;
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;

...

struct _IO_FILE {
  int _flags;
  char* _IO_read_ptr;
  char* _IO_read_end;
  char* _IO_read_base;
  char* _IO_write_base;
  char* _IO_write_ptr;
  char* _IO_write_end;
  char* _IO_buf_base;
  char* _IO_buf_end;
  char *_IO_save_base;
  char *_IO_backup_base;
  char *_IO_save_end;
  struct _IO_marker *_markers;
  struct _IO_FILE *_chain;
  int _fileno;
  int _flags2;
  __off_t _old_offset;
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];
  _IO_lock_t *_lock;
  __off64_t _offset;
  void *__pad1;
  void *__pad2;
  void *__pad3;
  void *__pad4;
  size_t __pad5;
  int _mode;
  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};

...

extern int fprintf (FILE *__restrict __stream,
      __const char *__restrict __format, ...);
extern int printf (__const char *__restrict __format, ...);
extern int sprintf (char *__restrict __s,
      __const char *__restrict __format, ...) __attribute__ ((__nothrow__));
extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format,
       __gnuc_va_list __arg);
extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg);
extern int vsprintf (char *__restrict __s, __const char *__restrict __format,
       __gnuc_va_list __arg) __attribute__ ((__nothrow__));

...

main()
{
    printf("hello, world\n");
}

Most of the file has been truncated, but as we can see, the stdio.h header contains typedef declarations for various types, structure definitions including the above one for a FILE type as used in the file input/output routines, and function definitions. By being able to call this file from elsewhere, we save ourselves a lot of time and work from having to copy all of these definitions into our program manually.

While the above definition works for the standard header files, the location of the standard header files is restricted to read-only operations for non-administration users in many operating systems. There is, therefore, another way to specify the location of a source file, which may be an absolute path or relative to the working directory. A set of definitions of this type, using a relative and then an absolute definition, are shown below.

#include "foo.h"
#include "/home/jrandom/bar.h"

The operation of these preprocessor statements is similar to that of the one used for stdio.h; the major difference is in where the files are located. Instead of checking the standard directory for header files, the first definition checks the same directory as the source file for a header file named foo.h, while the second checks the absolute path leading to the /home/jrandom directory for a file named bar.h.

As it is common practice in C programming to leave #define statements, function prototypes and structure definitions in separate header files, this allows us to create our own header files without having to access the standard directory for header files.

The other particularly common invocation of preprocessor statements is the #define statement. The #define statement has two parts, an identifier and a token sequence. The preprocessor changes all instances of the identifier for the token sequence. This is useful for defining more legible names throughout the source code, particularly for so-called “magic numbers” whose purpose is not obvious from observation. A few examples of how this may be used are shown below:

#define MAX_FILENAME 255 /* Defines the maximum length of a filename path */
#define DIB_HEADER_SIZE 40 /* Defines the size of a BMP DIB header in bytes */
#define FOO_STRING "foobarbazquux"

In most cases, the #define tag is simply used to provide effective macros for obscure or complex definitions, but there is another sort of functionality which the #define statement can be used for. The #define statement can be used to define a macro with arguments, which is an effective way of creating shorthand for a piece of simple code which one doesn’t want to consistently repeat, but for which one doesn’t want the overhead of a function. An example of this is shown below:

#define SQUARE(x) (x) * (x)

We might see this definition invoked in a program like so:

#include 
#define SQUARE(x) (x) * (x)

int main(void)
{
    int a;

    printf("Enter an integer: ");
    scanf("%d", &a);
    printf("The square of %d is %d\n", a, SQUARE(a));
    return 0;
}

When this function is called, the SQUARE(a) invocation is replaced by (a) * (a). Note the brackets around the arguments in the macro; these are imperative for preserving the appropriate order of operations. Let’s say that we were to define SQUARE(x) as the following:

#define SQUARE(x) x * x

and then call it with the following code:

SQUARE(5 + 4)

This would expand out to the following:

5 + 4 * 5 + 4

As multiplication precedes addition, the multiplication in the middle would be performed first, with the multiplication of 4 and 5, giving 20, and then the flanking additions would be performed, giving an answer of 29. This is quite short from the 81 that we would expect from the square of 9. Therefore, it is important to appropriately define your macros in accordance with the expected order of operations.

Macros can have more than one argument, such as the following definition for a macro to find the larger of two numbers:

#define max(a, b) (a) > (b) ? (a) : (b)

Having defined something, we may want to undefine it further down the source file, possibly to prevent interference with certain operations, or to ensure that something is a function rather than a macro. For instance, in the standard libraries for low-power embedded platforms, getchar() and putchar() may be defined as macros in order to prevent the overhead of a function. In order to undefine something, we use #undef. The following code would undefine the SQUARE and max operation which we defined above:

#undef SQUARE
#undef max

Beyond the realms of #include and #define lie the conditional preprocessor directives. The first set of these are used to check whether something has already been defined, while the other set are used to check whether a C statement is true or false. We’ll discuss the definition-related directives first.

#ifdef is used to check if something has already been defined, while #ifndef is used to check whether something has not been defined. In professional code, this is regularly used to check the operating system and other details about the system which the program is to be compiled for, as the elementary operations which make up basic routines differ on different systems. We can also check if something is defined using the “defined” operator; this is useful if we want to continue checking after an #ifdef or #ifndef statement which was not satisfied.

Let’s say that we had a piece of source code which we needed to maintain on Windows, Mac OS X and Linux. Various bits of the source code might not apply to one or more of those operating systems. We could therefore hide the bits of source code that don’t apply to the current operating system using the following:

#ifdef _WIN32
#include 
#include 

#elif defined MACOSX
#include 
#include 

#elif defined LINUX
#include 
#include 

#endif

Note the use of #endif to close our set of conditional directives. This is part of the remainder of the conditional directives. #if checks if a C statement is true, and proceeds if it is, #elif is used to check another alternative if the preceding condition was not satisfied, #else is a universal alternative if none of the preceding conditions were satisfied, while #endif closes a block of conditional preprocessor statements. These operations work very similarly to the if…else if…else statements in C. The following example checks whether we are compiling for a 32-bit or 64-bit system:

#if !(defined __LP64__ || defined __LLP64__) || defined _WIN32 && \
    !defined _WIN64
/* we are compiling for a 32-bit system */
#else
/* we are compiling for a 64-bit system */
#endif

In this code, we’re looking for a definition of __LP64__ or __LLP64__, which define data models for 64-bit processors, to be false, or a definition of _WIN32, which defines a Windows software platform, to be true without a corresponding definition of _WIN64, which defines a 64-bit version of Windows, to be true. If this is true, the program is compiled for a 32-bit system, which will have different machine instructions to the 64-bit system.

While there are some other details of the preprocessor to discuss, they are best left to external reading. To conclude, there are a number of predefined macros in the C preprocessor, such as __LINE__, which calculates the line number, and __FILE__, which determines the filename. The C preprocessor can be somewhat obscure, but it gives the C language a great deal of flexibility – the sort of flexibility that sees its use on everything from microcontrollers to supercomputers.

A Project With Source Code: A Snake Clone in Allegro

#include <allegro.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define TILE_SIZE 20
#define TILES_HORIZ 32
#define TILES_VERT 24
#define MAX_ENTITIES 768

/* Length of snake */
int length = 5;
/* Grid reference for food */
int food_location[2] = {-1, -1};
/* Grid reference array for segments of snake */
int snake_segment[MAX_ENTITIES + 1][2];
/* Direction of snake - 0 for up, 1 for right, 2 for down, 3 for left */
int snake_direction = 3;

BITMAP *back, *snake_body, *food, *game_over;

/* Function prototypes */
void setup_screen();
void create_snake();
void draw_snake(int i);
void set_food_location();
void move_snake();
int collision_check();
void get_input();
void cleanup();

int main(void)
{
    int i, check;
    clock_t last_cycle;
    
    /* Set up Allegro */
    allegro_init();
    setup_screen();
    srand(time(NULL));
    install_keyboard();

    /* Establish beginning conditions */
    create_snake();     
    draw_snake(0);
    set_food_location();
    last_cycle = clock();

    while(!key[KEY_ESC]) {
	if ((clock() - last_cycle) / (double) CLOCKS_PER_SEC >= 0.1) {
	    last_cycle = clock();
	    move_snake();
	    check = collision_check();
	    /* If snake collided with walls or itself, end the game */
	    if (check == 1) {
		break;
	    } else if (check == 2) {
		/* If snake coincided with food, extend snake and reset food
		   location */
		length++;
		set_food_location();
	    }
	    get_input();
	}
    }

    game_over = load_bitmap("game_over.bmp", NULL);

    /* Display game over message when collision detected */
    while (!key[KEY_ESC]) {
	blit(game_over, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
    }

    cleanup();
    allegro_exit();
}
END_OF_MAIN()

void setup_screen()
{
    int i;

    set_color_depth(24);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
    
    back = create_bitmap(SCREEN_W, SCREEN_H);
    clear_bitmap(back);

    /* Create white grid on background bitmap, blit to screen */
    for (i = 0; i < SCREEN_W; i += TILE_SIZE) {
	vline(back, i, 0, SCREEN_H, makecol(255, 255, 255));
    }

    for (i = 0; i < SCREEN_H; i += TILE_SIZE) {
	hline(back, 0, i, SCREEN_W, makecol(255, 255, 255));
    }

    blit(back, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
}

void create_snake()
{
    int i, j;

    for (i = 0, j = 15; i < length; j++, i++) {
	snake_segment[i][0] = j;
	snake_segment[i][1] = 12;
    }
}

void draw_snake(int mode)
{
    int i;
    if (snake_body == NULL) {
	snake_body = load_bitmap("snake_body.bmp", NULL);
    }
    
    for (i = 0; i < length; i++) {
	draw_sprite(screen, snake_body, snake_segment[i][0] * TILE_SIZE + 1,
				snake_segment[i][1] * TILE_SIZE + 1);
    }

    /* If function called from move_snake(), remove final segment of snake
       from the screen */
    if (mode = 1) {
	blit(back, screen, snake_segment[length][0] * TILE_SIZE,
	     snake_segment[length][1] * TILE_SIZE, 
	     snake_segment[length][0] * TILE_SIZE,
	     snake_segment[length][1] * TILE_SIZE,
	     TILE_SIZE, TILE_SIZE);
    }
}

void set_food_location()
{
    int i, valid = 1;
    
    if (food == NULL) {
	food = load_bitmap("food.bmp", NULL);
    }
    
    /* Ensure food is not positioned on a snake segment */
    do {
	valid = 1;
	food_location[0] = rand() % TILES_HORIZ;
	food_location[1] = rand() % TILES_VERT;
	
	for (i = 0; i < length; i++) { 	    if (food_location[0] == snake_segment[i][0] && food_location[1] 		== snake_segment[i][1]) 		valid = 0; 	}     } while (!valid);     draw_sprite(screen, food, food_location[0] * TILE_SIZE + 1, 		food_location[1] * TILE_SIZE + 1); } void move_snake() {     int i;     /* Move all grid references for snake segments up one position */     for (i = length - 1; i >= 0; i--) {
	snake_segment[i + 1][0] = snake_segment[i][0];
	snake_segment[i + 1][1] = snake_segment[i][1];
    }

    /* Then, change the appropriate reference point depending on the snake's
       direction */
    if (snake_direction == 0) {
	--snake_segment[0][1];
    }
    else if (snake_direction == 1) {
	++snake_segment[0][0];
    }
    else if (snake_direction == 2) {
	++snake_segment[0][1];
    }
    else if (snake_direction == 3) {
	--snake_segment[0][0];
    }

    draw_snake(1);
}

int collision_check()
{
    int i;

    /* Snake collided with walls - end game */
    if (snake_segment[0][0] < 0 || snake_segment[0][0] >= TILES_HORIZ ||
	snake_segment[0][1] < 0 || snake_segment[0][1] >= TILES_VERT) {
	return 1;
    }

    /* Snake collided with itself - end game */
    for (i = 1; i < length; i++) {
	if (snake_segment[0][0] == snake_segment[i][0] &&
	    snake_segment[0][1] == snake_segment[i][1]) {
	    return 1;
	}
    }

    /* Snake coincided with food - extend snake and reset food position */
    if (snake_segment[0][0] == food_location[0] && snake_segment[0][1] ==
	food_location[1]) {
	return 2;
    }

    return 0;
}

void get_input()
{
    if (key[KEY_UP] && snake_direction != 2) {
	snake_direction = 0;
    }

    if (key[KEY_RIGHT] && snake_direction != 3) {
	snake_direction = 1;
    }

    if (key[KEY_DOWN] && snake_direction != 0) {
	snake_direction = 2;
    }

    if (key[KEY_LEFT] && snake_direction != 1) {
	snake_direction = 3;
    }
}

void cleanup()
{
    destroy_bitmap(back);
    destroy_bitmap(snake_body);
    destroy_bitmap(food);
    destroy_bitmap(game_over);
}

Ceramic Hunter – A Simple Game using the Allegro Library

Author’s Note: This is a little game that I designed as a project during the summer break from college. It’s not particularly sophisticated, nor is it especially well-programmed, but I still consider it a step, if a small one, towards what I eventually would like to be able to develop.

The software is provided under the BSD License, allowing you to modify and play with the software at your will. Several graphical resources will be required to play this game, and will be available under this note. They will have to be converted to Windows bitmap (.bmp) format in order to work with the game.

Note: The layout of this blog format doesn’t extend to the 80 columns required to show all of the source code appropriately. You can circumvent this restriction by dragging the mouse over all of the source code and copying it to a text editor; the hidden code will show up.

ammoround crosshair spentround target

/* Copyright (c) 2013, Richard A. Kiernan
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the  nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <allegro.h>
#include <stdlib.h>
#include <time.h>

/* screen definitions */
#define MODE GFX_AUTODETECT_WINDOWED
#define WIDTH 640
#define HEIGHT 480

/* colour definitions */
#define WHITE makecol(255, 255, 255)
#define TAN makecol(255, 242, 169)
#define BLACK makecol(0, 0, 0)

/* target definitions */
#define TARGET_XSIZE target_bmp->w
#define TARGET_YSIZE target_bmp->h
#define TARGET_TOPXSPEED 2

/* target bounds definitions */
#define TARGET_TOPY 40
#define TARGET_BOTTOMY SCREEN_H - 60

/* bitmap images */
BITMAP *buffer;
BITMAP *crosshair;
BITMAP *ammoround;
BITMAP *spentround;
BITMAP *target_bmp;

/* target structure */
struct type_target {
    int x, y;
    int x_speed, y_speed;
    int alive;
};

struct type_target target;

int rounds_magazine = 6, rounds_bandolier = 24;
int score = -1;
int updates = 0;

/* for limiting the rate of target creation and round firing */
clock_t last_target_time;
clock_t last_fired_time;

/* function prototypes */
void setupscreen(void);
void updatescore(void);
void drawbullets(void);
void drawbandoliercount(void);
void createtarget(void);
void updatetarget(void);
void roundfired(void);
void reloadmagazine(void);

int main(void)
{
    int mb;
    int ret;
    int n;

    /* initialise program */
    allegro_init();
    setupscreen();
    install_keyboard();
    install_mouse();
    install_timer();
    srand(time(NULL));

    /* create a secondary screen buffer */
    buffer = create_bitmap(WIDTH, HEIGHT);

    /* display title */
    textout_ex(buffer, font, "Ceramic Hunter (ESC to quit)", 0, 1, WHITE, 0);

    /* display score */
    updatescore();

    /* draw line under title & score */
    line(buffer, 0, 12, SCREEN_W, 12, TAN);

    /* display remaining round count in magazine */
    drawbullets();

    /* display remaining round count in bandolier */
    drawbandoliercount();

    /* load the mouse cursor */
    crosshair = load_bitmap("crosshair.bmp", NULL);
    set_mouse_sprite(crosshair);
    set_mouse_sprite_focus(15, 15);
    show_mouse(buffer);

    /* set up initial target */
    createtarget();

    /* main loop - continue while ESC key not pressed and rounds remaining in
     * magazine and/or bandolier */
    while (!key[KEY_ESC] && (rounds_magazine + rounds_bandolier > 0)) {
	mb = (mouse_b & 1);

	if (target.alive)  {
	    updatetarget();
	} else if ((clock() - last_target_time) 
		   / (double) CLOCKS_PER_SEC >= 2.5) {
	    createtarget();
	}

	if (mb && (clock() - last_fired_time) 
	    / (double) CLOCKS_PER_SEC > 0.5) {
	    if (rounds_magazine > 0) {
		roundfired();
	    }
	}

	if (key[KEY_R] && rounds_magazine < 6 && rounds_bandolier > 0) {
	    reloadmagazine();
	}

	blit(buffer, screen, 0, 0, 0, 0, 640, 480);
    }

    /* print final score */
    rest(500);
    for (n = 0; n < 3; n++) {
	/* flashing effects to indicate end of game */
	rectfill(screen, 0, 0, SCREEN_W, SCREEN_H, WHITE);
	rest(5);
	rectfill(screen, 0, 0, SCREEN_W, SCREEN_H, BLACK);
	rest(5);
    }
    textprintf_centre_ex(screen, font, SCREEN_W / 2, SCREEN_H / 2, WHITE, -1,
			 "Final Score: %d", score);
    textout_centre_ex(screen, font, "Press ESC to quit...",
		      SCREEN_W / 2, SCREEN_H / 2 + 10, WHITE, -1);
    while (!key[KEY_ESC])
	;

    /* exit program */
    allegro_exit();
    return 0;
}
END_OF_MAIN();

void setupscreen(void)
{
    int ret;
    set_color_depth(24);
    if ((ret = set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0)) != 0) {
	allegro_message("%s", allegro_error);
	return;
    }
}

void updatescore(void)
{
    /* update and display the score */
    score++;
    textprintf_right_ex(buffer, font, SCREEN_W - 5, 1, WHITE, 0,
			"SCORE: %d", score);
}

void drawbullets(void)
{
    int n;

    if (ammoround == NULL) {
	ammoround = load_bitmap("ammoround.bmp", NULL);
    }
    if (spentround == NULL) {
	spentround = load_bitmap("spentround.bmp", NULL);
    }

    for (n = 0; n < rounds_magazine; n++) { 	draw_sprite(buffer, ammoround, n * ammoround->w,
		    SCREEN_H - ammoround->h);
    }

    for (n; n < 6; n++) { 	draw_sprite(buffer, spentround, n * spentround->w,
		    SCREEN_H - spentround->h);
    }
}

void drawbandoliercount(void)
{
    textprintf_right_ex(buffer, font, SCREEN_W - 5, SCREEN_H - 8, WHITE, 0,
			"BANDOLIER: %2d", rounds_bandolier);
}

void createtarget(void)
{
    if (target_bmp == NULL) {
	target_bmp = load_bitmap("target.bmp", NULL);
    }
    target.alive = 1;
    target.x = rand() % 2 ? 0 : SCREEN_W - TARGET_XSIZE;
    target.y = (rand() % 360) + TARGET_TOPY;
    target.x_speed = target.x == 0 ?
	TARGET_TOPXSPEED : -(TARGET_TOPXSPEED);

    /* if target in top or bottom third of screen, it might have a y speed
     * component; otherwise, y speed is 0. */
    if (target.y < (SCREEN_H / 3)) {
 	target.y_speed = rand() & 1;
    } else if (target.y > (SCREEN_H - (SCREEN_H / 3))) {
	target.y_speed = -(rand() & 1);
    } else {
	target.y_speed = 0;
    }

    /* if target has a y speed component, x speed component might be
     * decreased/increased by 1 to change angle of entry */
    if (target.y_speed != 0) {
	target.x_speed += target.x_speed > 1 ? -(rand() & 1) : rand() & 1;
    }

    last_target_time = clock();
}

void updatetarget(void)
{
    int tx, ty;

    tx = target.x;
    ty = target.y;

    /* hide mouse pointer */
    scare_mouse();

    /* clear target movement area in buffer if updates > 20
     * to clear away graphical glitches caused by mouse movement */
    if (++updates > 20) {
	updates = 0;
	rectfill(buffer, 0, TARGET_TOPY, SCREEN_W, TARGET_BOTTOMY, BLACK);
    }

    /* erase target */
    rectfill(buffer, tx, ty, tx + TARGET_XSIZE, ty + TARGET_YSIZE, BLACK);

    target.x += target.x_speed;
    target.y += target.y_speed;

    if ((target.x > 0 && target.x + TARGET_XSIZE < SCREEN_W) &&
 	(target.y > TARGET_TOPY && target.y + TARGET_YSIZE < TARGET_BOTTOMY)) {
 	/* redraw target on buffer */
 	draw_sprite(buffer, target_bmp, target.x, target.y);
    } else {
 	target.alive = 0;
    }
    /* show mouse pointer */
    unscare_mouse();
}

void roundfired(void) {
     int n;
     --rounds_magazine;
     last_fired_time = clock();
     if ((mouse_x >= target.x && mouse_x < target.x + TARGET_XSIZE) &&
 	(mouse_y >= target.y && mouse_y < target.y + TARGET_YSIZE)) {
	/* destroy target */
	target.alive = 0;
        updatescore();
	rectfill(buffer, target.x, target.y, target.x + TARGET_XSIZE,
		 target.y + TARGET_YSIZE, BLACK);
	/* draw puff of smoke */
	for (n = 0; n < 100; n++) {
 	    putpixel(screen, target.x + (rand() % TARGET_XSIZE),
 		     target.y + (rand() % TARGET_XSIZE), WHITE);
 	}
 	rest(30);
     }
     drawbullets();
}

void reloadmagazine(void) {
     int temp;
     temp = rounds_magazine;
     if (rounds_bandolier > 6 || rounds_bandolier + rounds_magazine > 6) {
	rounds_magazine = 6;
	rounds_bandolier = (rounds_bandolier + temp) - rounds_magazine;
    } else {
	rounds_magazine = rounds_bandolier + temp;
	rounds_bandolier = 0; 
    }
    drawbullets();
    drawbandoliercount();
}

Basics of Structures in C

With this post, we get to one of the most useful elements of C: Structures. While structures didn’t exist in some of the early versions of C, they were soon added in as the developers of C and the Unix operating system saw how useful they could be for extending the utility of their pre-existing programs, and indeed, developing programs outside of the field of system programming. The C data structure is, along with functions, one of the elements that gives it extra utility compared to the programming languages that came before, like FORTRAN and BASIC.

A structure is, speaking succinctly, a way of wrapping multiple variables up into one “package”. To demonstrate why you might want to do this, we could say that you’re designing a simple data processing application like a rudimentary stock control system for a small shop. This stock control system works on a number of different variables, such as char arrays for storing the names of the products, float variables for storing the cost and sell price of these products, and int variables for storing the number of products left in stock. Without structures, we have to declare all of these variables discretely, as illustrated below:

char *name[100];

int *number;

double *cost;

double *price;

The reason we have declared all of these as pointers is because we will want to declare arrays of these variables, but unless you know exactly how many product types are in your database, you won’t know how much memory to allocate, and so, you will have to use malloc(), calloc() or realloc() to create arrays of the appropriate size.

The problem we have here is that none of the elements of these arrays has any particular connection to the corresponding elements in the other arrays. Let’s say you wanted to sort the products into alphabetical order. You’d perform your sorting algorithm on the name[] array, which would work perfectly well, but if you forgot to appropriately change around the other three arrays, you’d end up with a situation where all of the arrays were knocked out of sync. This demonstrates how fragile this stock control system would be – and how inefficient, as you’d have to appropriately change the positions of three other arrays in addition to the name[] array!

What’s more, this particular stock control program wouldn’t work very well when it came to passing the elements into a function. In order to perform a stock reordering function, what we’d have to do is pass four separate variables into the function. Let’s say that we just wanted to reorder a single product, which might use a function with a prototype like this:

int reorder(char **name, int *number, double *cost, double *price);

Pretty messy, don’t you think? One of the preferable things about structures is that they allow you to send a single variable into this function. The function prototype can be rewritten in the following fashion:

int reorder(struct item *product);

This is a lot cleaner and easier to handle. There’s a single variable in the arguments of type “pointer to struct item“, which contains all of the discrete variables which we had before. I’ll explain more about pointers to structures later. First of all, we’re going to leave our stock control system for a few moments and look at a simpler structure declaration.

One useful application that C can and regularly has been used for is graphical manipulation. In a raster graphical format, such as BMP, JPEG, GIF or PNG, each pixel has an x and a y coordinate. In the light of what we’ve seen above with the lack of robustness with discrete variables, we’re going to want to create a “package” – or structure – to hold both components of a pixel location together. We’ll create a structure type for doing this:

struct pixel {
    int x;
    int y;
};

What we’ve just created is a structure declaration, which essentially says, “Let’s create a new type, called struct pixel, whose elements will be an int variable named x, and an int variable named y“. This structure declaration now allows us to create variables of type struct pixel in other parts of the program.

Once we have the structure declaration, we create an element of this structure type like this:

struct pixel pixel_1;

The element pixel_1 is now created, just as we’d create an int, char or float variable. It follows some of the same rules as any of these other variables, in that it fills a certain amount of space (in this case, as it contains two int variables, its size will be sizeof(2 * int)). However, because it contains more than one variable itself, changing the values of these internal variables involves a different step than we’ve taken before.

To do this, we introduce the structure member operator, “.” (a single full stop). Let’s illustrate how this works by setting the value of the x coordinate in pixel_1 to 150:

pixel_1.x = 150;

The structure member operator is very high in the order of precedence in C; it has a higher precedence than the pointer dereference operator, and equivalent precedence to brackets and square brackets.

We’ll put this all together in a simple program:

#include <stdio.h>

struct pixel {
    int x;
    int y;
};

int main(void)
{
    /* We'll create a variable of type struct pixel */
    struct pixel pixel_1;

    /* Set the elements of pixel_1 /*
    pixel1.x = 200;
    pixel1.y = 350;
    return 0;
}

The elements of a structure can be any legal variable, such as int, char, float and double. Notably, a structure, once it has been declared, is a legal variable. This means that structures are themselves legal elements of a structure – as long as they are structures of a different type. Extending our metaphor of a graphics program, we can use these so-called nested structures to create a representation of a rectangle. Our simple representation of a rectangle will consist of two pixels representing the origin and the diagonally opposite corner:

struct rect {
    struct pixel pt_1;
    struct pixel pt_2;
};

Indeed, the dimensions of a standard computer screen can be represented by a rectangular structure. We will illustrate how we would use our nested structure here for a 1920×1200 screen:

struct rect screen;

screen.pt_1.x = 0;
screen.pt_1.y = 0;
screen.pt_2.x = 1919;
screen.pt_2.y = 1199;

Unfortunately, without graphical functions to act upon these structures, we can’t do much with our pixel and rectangle structures. We return, therefore, to the stock control program described earlier. Having seen some simple structures, we can now design a structure which will represent a data entry.

struct item {
  char name[100];
  int number;
  float cost;
  float price;
};

This structure contains the variables for which we would have had to declare separate arrays in the previous program. In using a structure, we have packaged all of these variables together, giving them a mutual association. We’ll demonstrate how this may be used, given a database containing the following, which we can save to a file:

Bread 12 1.65 2.25
Milk 23 1.40 1.80
Eggs 20 1.60 2.15
Cheese 11 1.85 2.50
Bacon 6 2.65 3.15

Now, we write a program to take these values in and to print them out. This program will take a single additional command-line argument, which will be the file name of the database that we defined above:

#include <stdio.h>

struct item {
    char name[100];
    int number;
    float cost;
    float price;
};

int main(int argc, char *argv[])
{
    struct item item_array[5];
    FILE *ifp;
    int i;

    if (argc != 2) {
	printf("Usage: basic_database <filename>\n");
	return -1;
    } else if ((ifp = fopen(argv[1], "r")) == NULL) {
	printf("Error: Could not open file %s\n", argv[1]);
	return -2;
    } else {
	for (i = 0; i <= 5; i++) {
	    fscanf(ifp, "%s%d%f%f", item_array[i].name,
	    &item_array[i].number,
	    &item_array[i].price, &item_array[i].cost);
	}
	fclose(ifp);
    }

    for (i = 0; i <= 4; i++) {
	printf("%s %5d %8.2f %8.2f\n", item_array[i].name, item_array[i].number,
	item_array[i].price, item_array[i].cost);
    }
    return 0;
}

When we call it with our data from before, we get the following result:

Bread 12 1.65 2.25 
Milk 23 1.40 1.80 
Eggs 20 1.60 2.15 
Cheese 11 1.85 2.50 
Bacon 6 2.65 3.15

So, we’ve defined the framework for a simple database. We could do things with these values, such as searching through them to find the item with the highest price for the consumer:

float highest_price = 0;
int highest_price_pos = 0;

for (i = 0; i < 5; i++) {
    if (item_array[i].price > highest_price) {
	highest_price = item_array[i].price;
	highest_price_pos = i;
    }
}

A problem arises, though, when we look at this in greater detail. What happens if the database – as is very likely – contains more than five items? We don’t want to have to recompile our program every time we get a new item to sell, so we do what we would do if we required additional variables of other types: We use dynamic memory allocation. In order to do this, we will require a pointer to our structure type, but before I change our program, we need to discuss pointers to structures.

Pointers to structures operate similarly to pointers to other variables, in that they store memory addresses to structures. They are also declared similarly, with the following example being a pointer to type struct item:

struct item *item_pointer;

However, the order of precedence in C creates a bit of a problem when it comes to using the traditional dereference operator to access the contents of a pointer to a structure. The traditional syntax for accessing data in the elements of a pointer to a structure looks peculiar and confusing:

item_pointer = item_array[3];

(*item_pointer).price = 2.50;

Note that we have to use brackets around the dereference operator and the thing it’s dereferencing. The order of precedence for the structure member operator is higher than that of the dereference operator, and therefore we have to use brackets, which have the same precedence as the structure member operator, in order to allow the pointer to access its memory address before the structure member is called.

Luckily, there is a separate operator used specifically for allowing a pointer to a structure to access its elements without having the potential source of confusion caused by the dereference operator in this circumstance. The structure pointer operator, -> (a minus sign, followed by a greater-than sign), has the same precedence as the structure member operator, and reduces the ambiguity existing with the traditional syntax.

Having discussed that, we can modify our program from before to dynamically allocate memory based on the number of elements contained in the list. We will use malloc() to initially allocate memory for a single element of type struct item *, then use fscanf() to read in the values into the elements of this structure. For each line that fscanf() doesn’t read in the EOF character, the program increases the size of the dynamically allocated memory by the size of the struct item type using the realloc() function. Then, the elements of the structure array are read out as above.

#include <stdio.h>
#include <stdlib.h>

struct item {
    char name[100];
    int number;
    float cost;
    float price;
};

int main(int argc, char *argv[])
{
    struct item *item_array;
    FILE *ifp;
    int i;
    int array_elements = 0;
    int el_size;

    /* Store the size of a single element */
    el_size = sizeof(struct item);

    /* Start off by declaring a single element */
    item_array = (struct item *) malloc (el_size);

    if (argc != 2) {
	printf("Usage: basic_database <filename>\n");
	return -1;
    } else if ((ifp = fopen(argv[1], "r")) == NULL) {
	printf("Error: Could not open file %s\n", argv[1]);
	return -2;
    } else {
	/* Keep going until fscanf hits the EOF character */
	while (fscanf(ifp, "%s%d%f%f", item_array[array_elements].name,
		      &item_array[array_elements].number,
		      &item_array[array_elements].cost,
		      &item_array[array_elements].price) != EOF) {
	    /* Reallocate memory, then increment the elements counter */
	    /* NOTE: We've got a bodge in here. The memory allocated will
	     * always be one element more than we need. */
	    item_array = (struct item *)
		realloc(item_array, (el_size * ++array_elements) + el_size);
	    if (item_array == NULL) {
		printf("Error: Cannot allocate memory\n");
		return -1;
	    }
	}
	fclose(ifp);
    }
    for (i = 0; i < array_elements; i++) {
	printf("%s %d %.2f %.2f\n", item_array[i].name, item_array[i].number,
	       item_array[i].cost, item_array[i].price);
    }

    free(item_array);
    return 0;
}

Fundamentals of String Manipulation in C: Part 2

Having discussed most of the important functions relating to strings before, there are only a few others of particular note. We saw gets() previously, which acts like scanf(“%s”, string), and while it performs the job it’s asked to do, it is regarded as somewhat dangerous as it is prone to buffer overflow. A function does exist in the C standard library in <stdio.h> which is somewhat safer.

fgets() is an equivalent function to gets() designed to work on file input. Unlike gets(), you can specify a maximum number of characters to be taken in, which mitigates the buffer overflow that can occur with gets(). fgets() is called with three arguments: the string where input will be stored; the maximum number of characters, including the null character and either stdin, the reference of the standard input stream, or a pointer to a variable of the type FILE. File pointers will be discussed later; for now, we are only interested in stdin.

An example of the use of fgets() is illustrated below:

#include <stdio.h>

int main(void)
{
    char string[30];
    printf("Please enter a string: ");
    fgets(string, 30, stdin);
    puts(string);
    return 0;
}

One peculiar difference between fgets() and gets() is that fgets() does not remove newline characters from its input, while gets() does. This is to be noted when trying to concatenate two strings with strcat() which have been entered from the standard input stream with fgets().

Previously, we also saw the strcmp() function for comparing two strings. A similar function, strstr() (for string string) can be used to find an instance of a string of smaller or equal size within another string. It takes two arguments, both of them strings, and returns a pointer to the first instance of the string being searched for in the string being searched. The following program demonstrates strstr() in action.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char string[] = "yellow dinosaurs eat snow reluctantly";
    char *p;
    int index;

    /* Looking for the location of "eat" in string[] */
    p = strstr(string, "eat");
    /* Finding the element within the array where "eat" begins */
    index = p - string;
    printf("The string \"eat\" begins at index %d of string[]\n");

  return 0;
}

This returns the following:

The string "eat" begins at index 16 of string[]

Searching for multiple instances of strings using strstr() requires a slight modification of our program. We can do this by creating an index, or a point in the array where the last instance of the string was found, and call the strstr() function from the next contiguous point in memory (i.e. the pointer string + index + 1). This example will benefit from the following illustration:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char long_string[] = "The C programming language was invented in the \n"
    "early 1970s by the computer scientist, Dennis Ritchie, who was then \n"
    "working at Bell Labs in New Jersey, which had just removed its \n"
    "support from the Multics project.\n";
    int index = -1, count = 0, i;
    char *p;

    printf("%s", long_string);

    for (i = 0; i < strlen(long_string); i += index) {
	p = strstr(long_string + index + 1, "in");
	if ((index = p - long_string) >= strlen(long_string) || p == NULL)
	break;
	++count;
    }
    printf("\nThe string \"in\" has been located in the string %d times\n", count);
    return 0;
}

This example returns the following:

The C programming language was invented in the 
early 1970s by the computer scientist, Dennis Ritchie, who was then 
working at Bell Labs in New Jersey, which had just removed its 
support from the Multics project.

The string "in" has been located in the string 5 times

One thing to notice about this program is that the counter variable is not incremented by 1 on every loop, but instead by the value of index; this ensures that the loop continues only as long as there are still instances of the string being searched for to be counted.

In the last tutorial, We demonstrated atoi(), a function which converts a string consisting of numeral digits into a decimal integer. It was mentioned at the time that other functions of the same type exist. atof(), for instance, converts a string consisting of numeral digits, exponents and at most one radix point into a double; atol() operates like atoi(), except that it returns a long int. On most modern compilers, atol() works exactly like atoi(), but on older compilers with 2-byte ints, the two functions work differently.

The implementation of simple versions of these two functions is discussed in The C Programming Language (Kernighan & Ritchie, 2nd Edition, 1988). Other functions of this type with more flexibility exist, like strtod(), strtol() and strtoul(), the operations of which can be found in any good C reference material.

More Raspberry Pi Electronics Experiments – Gertboard and Potentiometer-Controlled LED Cluster

One of the things which alerted me to the potential of the Raspberry Pi as an electronics control system was the announcement of the Gertboard before the Raspberry Pi was released into the market. When the Gertboard was announced for sale in November 2012, it was fully my intention to buy one, but a lack of money kept me from purchasing it at that point. The unassembled Gertboard kits soon sold out, leaving element14, who distribute the Gertboard, to decide to release an assembled Gertboard. This went on sale very recently, and shortly after release, I bought one from Premier Farnell’s Irish subsidiary.

The Gertboard, for the uninitiated, is an I/O expansion board that plugs into the GPIO header on the Raspberry Pi. Designed by Gert van Loo, designer of the Raspberry Pi alpha hardware, the Gertboard not only protects the GPIO pins from physical and electrical damage, but also provides a set of additional features. These include input/output buffers, a motor controller, an open collector driver, an MCP3002 ADC and MCP4802 DAC and an Atmel ATMega328P microcontroller which is compatible with the Arduino IDE and programming environment.

I was very impressed by the quick response from element14 after my purchase; my delivery came only two days after ordering and would have come even sooner if I hadn’t missed the 20.00 deadline on the day I had ordered it. The Gertboard was packaged with a number of female-to-female jumper wires, a set of jumpers, plastic feet for the board and a CD-ROM with a set of development tools for the ARM Cortex-M platform.

gertboard_package

So far, I’ve only had occasion to test the buffered I/O, the ADC and DAC and the microcontroller; I still don’t have parts to test the motor controller or open collector driver. Aside from some documented peculiarities regarding the input buffers when at a floating voltage, including the so-called “proximity sensor” effect, things seem to have been going rather well.

The acquisition of the Gertboard gave me the impetus to really get down to trying to test my own expansions to the simple test circuits I had implemented before. One interesting application that I considered was to use a potentiometer to control a bank of LEDs in order to provide some sort of status indication.

The following Fritzing circuit diagram shows the layout of this circuit without the use of the Gertboard; the onboard LEDs and GPIO pins lined up in a row on the Gertboard makes it slightly less messy in terms of wiring.

Potentiometer Controlled LEDs_bb

In this diagram, GPIO pins 0, 1, 4, 17, 18, 21, 22 and 23 are used to control the LEDs, although you could also use pins 24 or 25 without conflict with either the SPI bus – which is necessary for the MCP3002 ADC – or the serial UART on pins 14 and 15. However, this is a lot of GPIO pins taken up for one application, which may warrant the use of a shift register or an I2C I/O expander such as the MCP23008 or MCP23017 in order to control more LEDs with less pins.

In order to control this circuit, I took the sample Gertboard test software and modified it slightly. As the potentiometer is turned to the right, the ADC value increases to a maximum of 1023; therefore, the distance between each LED’s activation point should be 1023 divided by 8 – very close to 128. The LEDs will light from left-to-right as the potentiometer’s resistance decreases, with one LED lighting at an ADC reading of 0, two LEDs at 128, all the way up to all eight LEDs at 1023.

//
// Gertboard Demo
//
// SPI (ADC/DAC) control code
//
// This code is part of the Gertboard test suite
//
//
// Copyright (C) Gert Jan van Loo & Myra VanInwegen 2012
// No rights reserved
// You may treat this program as if it was in the public domain
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include "gb_common.h"
#include "gb_spi.h"

void setup_gpio(void);

int leds[] = {1 << 23, 1 << 22, 1 << 21, 1 << 18, 1 << 17, 1 << 4, 1 << 1,
	      1 << 0};

int main(void)
{
    int r, v, s, i, chan, nleds;

    do {
	printf("Which channel do you want to test? Type 0 or 1.\n");
	chan = (int) getchar();
	(void) getchar();
    } while (chan != '0' && chan != '1');

    printf("When ready, press Enter.");
    (void) getchar();

    setup_io();
    setup_gpio();
    setup_spi();

    for (r = 0; r < 1000000; r++) {
	v = read_adc(chan);
	for (i = 0; i < 8; i++) {
	    GPIO_CLR0 = leds[i];
	}
	nleds = v / (1023 / 8); /* number of LEDs to turn on */
	for (i = 0; i < nleds; i++) {
	    GPIO_SET0 = leds[i];
	}
	short_wait();
    }

    printf("\n");
    restore_io();
    return 0;
}

void setup_gpio()
{
    /* Setup alternate functions of SPI bus pins and SPI chip select A */
    INP_GPIO(8); SET_GPIO_ALT(8, 0);
    INP_GPIO(9); SET_GPIO_ALT(9, 0);
    INP_GPIO(10); SET_GPIO_ALT(10, 0);
    INP_GPIO(11); SET_GPIO_ALT(11, 0);
    /* Setup LED GPIO pins */
    INP_GPIO(23); OUT_GPIO(23);
    INP_GPIO(22); OUT_GPIO(22);
    INP_GPIO(21); OUT_GPIO(21);
    INP_GPIO(18); OUT_GPIO(18);
    INP_GPIO(17); OUT_GPIO(17);
    INP_GPIO(4); OUT_GPIO(4);
    INP_GPIO(1); OUT_GPIO(1);
    INP_GPIO(0); OUT_GPIO(0);
}