Structs
COP-3223H
Table of Contents
Structs bundle variables
Instead of having to define separate variables for one player, e.g.,
int player_x; int player_y; char player_c;
Bundle these instead a single variable
struct {
int x;
int y;
char c;
} player;
Accessing struct fields
Structs create namespaces, e.g., x can be used both in the struct and as a local variable.
struct {
int x;
int y;
char c;
} player;
player.x = 2;
int x = 10;
Struct declarations create new datatypes
// datatype is int name is x
int x;
// datatype is a new struct name is sprite
struct { int x; int y; char c; } sprite;
Reusing struct datatypes
You can name a struct and use it for many variables.
// the new struct type is called "sprite". no variable name needed
struct sprite { int x; int y; char c; };
// no need to repeat the full struct declaration to use it
struct sprite player;
struct sprite enemy;
// now all variable have the same constituent variables
player.x = 1;
player.y = 10
enemy.x = 2;
enemy.y = 3;
Chase game with structs
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example
#include <stdio.h>
#include <stdbool.h>
#include "term.c"
int main(int argc, char **argv) {
set_input_mode ();
printf("\033[?25l"); // hide cursor
int width = 40;
int height = 20;
struct character {
int state;
int x;
int y;
};
struct character player;
struct character enemy;
enum { vulnerable, invincible, dead };
player.state = vulnerable;
player.x = width / 2;
player.y = height / 2;
enum { chasing, running, defeated };
enemy.state = chasing;
enemy.x = 1;
enemy.y = 1;
struct {
struct character character;
int counter;
int random;
} potion;
enum { available, using, done };
potion.character.state = available;
potion.character.x = 29;
potion.character.y = 11;
potion.counter = 0;
potion.random = 1;
while (1) {
printf("\x1b[2J");
printf("\x1b[H");
// 0 available
// 1 using
// 2 done
// initial state is 0
// switch (potion_state) {
// case 0:
// }
switch (potion.character.state) {
case available:
printf("\033[%d;%dH", potion.character.y, potion.character.x);
printf("/\\");
printf("\033[%d;%dH", potion.character.y + 1, potion.character.x);
printf("\\/");
break;
case using:
// intentionally empty
break;
}
printf("\033[%d;%dH", enemy.y, enemy.x);
switch (enemy.state) {
case chasing: // case 0:
putchar('@');
break;
case running: // case 1:
putchar('@');
break;
case defeated: // case 2:
putchar('X');
}
printf("\033[%d;%dH", player.y, player.x);
switch (player.state) {
case vulnerable:
putchar('h');
break;
case invincible:
putchar('H');
break;
case dead:
printf(":(");
}
// debugging output
printf("\033[%d;%dH", height + 1, 0);
printf("player.y: %d\n", player.y);
printf("player.x: %d\n", player.x);
printf("enemy.y: %d\n", enemy.y);
printf("enemy.x: %d\n", enemy.x);
printf("potion.character.y: %d\n", potion.character.y);
printf("potion.character.x: %d\n", potion.character.x);
// read input
int direction_x = 0;
int direction_y = 0;
bool valid = true;
do {
char c = '\0';
scanf("%c", &c);
switch (c) {
case 'i':
direction_y = -2;
break;
case 'k':
direction_y = 2;
break;
case 'j':
direction_x = -2;
break;
case 'l':
direction_x = 2;
break;
default:
valid = false;
break;
}
} while (! valid);
switch(player.state) {
case vulnerable: // case 0:
player.x += direction_x;
player.y += direction_y;
break;
case invincible: // case 1:
player.x += direction_x;
player.y += direction_y;
if (enemy.x - 1 <= player.x && player.x <= enemy.x + 1 &&
enemy.y - 1 <= player.y && player.y <= enemy.y + 1) {
player.state = vulnerable;
enemy.state = defeated;
potion.character.state = done;
}
break;
}
switch (enemy.state) {
case chasing: // chasing
if (player.x > enemy.x) {
enemy.x += 1;
}
if (player.x < enemy.x) {
enemy.x -= 1;
}
if (player.y > enemy.y) {
enemy.y += 1;
}
if (player.y < enemy.y) {
enemy.y -= 1;
}
if ((player.x == enemy.x || player.x == enemy.x + 1) &&
(player.y == enemy.y || player.y == enemy.y + 1)) {
player.state = dead;
}
break;
case running:
if (player.x > enemy.x) {
enemy.x -= 1;
}
if (player.x < enemy.x) {
enemy.x += 1;
}
if (player.y > enemy.y) {
enemy.y -= 1;
}
if (player.y < enemy.y) {
enemy.y += 1;
}
if (enemy.x < 0) {
enemy.x = 0;
}
if (enemy.x > width) {
enemy.x = width;
}
if (enemy.y < 0) {
enemy.y = 0;
}
if (enemy.y > height) {
enemy.y = height;
}
break;
}
switch (potion.character.state) {
case available:
if ((player.x == potion.character.x || player.x == potion.character.x + 1) &&
(player.y == potion.character.y || player.y == potion.character.y + 1)) {
player.state = invincible;
enemy.state = running;
potion.character.state = using;
potion.counter = 10;
}
break;
case using:
potion.counter -= 1;
if (potion.counter == 1) {
player.state = vulnerable;
enemy.state = chasing;
potion.character.state = available;
potion.random = (potion.random * 97) % 65533;
potion.character.x = potion.random % width;
potion.random = (potion.random * 97) % 65533;
potion.character.y = potion.random % height;
}
break;
}
}
}