ex18 extra credit + ex19
This commit is contained in:
parent
a8c603e8e5
commit
9569ff1805
@ -1,11 +1,15 @@
|
|||||||
|
SHELL=/bin/bash
|
||||||
CFLAGS=-Wall -g
|
CFLAGS=-Wall -g
|
||||||
|
|
||||||
EXERCISES := $(shell ./list-exercises)
|
EXERCISES := $(shell ./list-exercises)
|
||||||
|
|
||||||
all: $(EXERCISES)
|
all: $(EXERCISES)
|
||||||
|
|
||||||
|
ex19: object.o
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(EXERCISES)
|
shopt -s nullglob ; \
|
||||||
|
$(RM) $(EXERCISES) *.o *.a
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@./runtests
|
@./runtests
|
||||||
|
119
lcthw-remnants-2/ex18-ec.c
Normal file
119
lcthw-remnants-2/ex18-ec.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/** Our old friend die from ex17. */
|
||||||
|
void die(const char *message)
|
||||||
|
{
|
||||||
|
if(errno) {
|
||||||
|
perror(message);
|
||||||
|
} else {
|
||||||
|
printf("ERROR: %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// a typedef creates a fake type, in this
|
||||||
|
// case for a function pointer
|
||||||
|
typedef int (*compare_cb)(int a, int b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A classic bubble sort function that uses the
|
||||||
|
* compare_cb to do the sorting.
|
||||||
|
*/
|
||||||
|
int *bubble_sort(int *numbers, int count, compare_cb cmp)
|
||||||
|
{
|
||||||
|
int temp = 0;
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
int *target = malloc(count * sizeof(int));
|
||||||
|
|
||||||
|
if(!target) die("Memory error.");
|
||||||
|
|
||||||
|
memcpy(target, numbers, count * sizeof(int));
|
||||||
|
|
||||||
|
for(i = 0; i < count; i++) {
|
||||||
|
for(j = 0; j < count - 1; j++) {
|
||||||
|
if(cmp(target[j], target[j+1]) > 0) {
|
||||||
|
temp = target[j+1];
|
||||||
|
target[j+1] = target[j];
|
||||||
|
target[j] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sorted_order(int a, int b)
|
||||||
|
{
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reverse_order(int a, int b)
|
||||||
|
{
|
||||||
|
return b - a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strange_order(int a, int b)
|
||||||
|
{
|
||||||
|
if(a == 0 || b == 0) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return a % b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to test that we are sorting things correctly
|
||||||
|
* by doing the sort and printing it out.
|
||||||
|
*/
|
||||||
|
void test_sorting(int *numbers, int count, compare_cb cmp)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int *sorted = bubble_sort(numbers, count, cmp);
|
||||||
|
|
||||||
|
if(!sorted) die("Failed to sort as requested.");
|
||||||
|
|
||||||
|
for(i = 0; i < count; i++) {
|
||||||
|
printf("%d ", sorted[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
free(sorted);
|
||||||
|
|
||||||
|
unsigned char *data = (unsigned char *)cmp;
|
||||||
|
|
||||||
|
for(i = 0; i < 25; i++) {
|
||||||
|
printf("%02x:", data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if(argc < 2) die("USAGE: ex18 4 3 1 5 6");
|
||||||
|
|
||||||
|
int count = argc - 1;
|
||||||
|
int i = 0;
|
||||||
|
char **inputs = argv + 1;
|
||||||
|
|
||||||
|
int *numbers = malloc(count * sizeof(int));
|
||||||
|
if(!numbers) die("Memory error.");
|
||||||
|
|
||||||
|
for(i = 0; i < count; i++) {
|
||||||
|
numbers[i] = atoi(inputs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_sorting(numbers, count, sorted_order);
|
||||||
|
test_sorting(numbers, count, reverse_order);
|
||||||
|
test_sorting(numbers, count, strange_order);
|
||||||
|
|
||||||
|
free(numbers);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
215
lcthw-remnants-2/ex19.c
Normal file
215
lcthw-remnants-2/ex19.c
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "ex19.h"
|
||||||
|
|
||||||
|
|
||||||
|
int Monster_attack(void *self, int damage)
|
||||||
|
{
|
||||||
|
Monster *monster = self;
|
||||||
|
|
||||||
|
printf("You attack %s!\n", monster->_(description));
|
||||||
|
|
||||||
|
monster->hit_points -= damage;
|
||||||
|
|
||||||
|
if(monster->hit_points > 0) {
|
||||||
|
printf("It is still alive.\n");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
printf("It is dead!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Monster_init(void *self)
|
||||||
|
{
|
||||||
|
Monster *monster = self;
|
||||||
|
monster->hit_points = 10;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object MonsterProto = {
|
||||||
|
.init = Monster_init,
|
||||||
|
.attack = Monster_attack
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void *Room_move(void *self, Direction direction)
|
||||||
|
{
|
||||||
|
Room *room = self;
|
||||||
|
Room *next = NULL;
|
||||||
|
|
||||||
|
if(direction == NORTH && room->north) {
|
||||||
|
printf("You go north, into:\n");
|
||||||
|
next = room->north;
|
||||||
|
} else if(direction == SOUTH && room->south) {
|
||||||
|
printf("You go south, into:\n");
|
||||||
|
next = room->south;
|
||||||
|
} else if(direction == EAST && room->east) {
|
||||||
|
printf("You go east, into:\n");
|
||||||
|
next = room->east;
|
||||||
|
} else if(direction == WEST && room->west) {
|
||||||
|
printf("You go west, into:\n");
|
||||||
|
next = room->west;
|
||||||
|
} else {
|
||||||
|
printf("You can't go that direction.");
|
||||||
|
next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next) {
|
||||||
|
next->_(describe)(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Room_attack(void *self, int damage)
|
||||||
|
{
|
||||||
|
Room *room = self;
|
||||||
|
Monster *monster = room->bad_guy;
|
||||||
|
|
||||||
|
if(monster) {
|
||||||
|
monster->_(attack)(monster, damage);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("You flail in the air at nothing. Idiot.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Object RoomProto = {
|
||||||
|
.move = Room_move,
|
||||||
|
.attack = Room_attack
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void *Map_move(void *self, Direction direction)
|
||||||
|
{
|
||||||
|
Map *map = self;
|
||||||
|
Room *location = map->location;
|
||||||
|
Room *next = NULL;
|
||||||
|
|
||||||
|
next = location->_(move)(location, direction);
|
||||||
|
|
||||||
|
if(next) {
|
||||||
|
map->location = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Map_attack(void *self, int damage)
|
||||||
|
{
|
||||||
|
Map *map = self;
|
||||||
|
Room *location = map->location;
|
||||||
|
|
||||||
|
return location->_(attack)(location, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Map_init(void *self)
|
||||||
|
{
|
||||||
|
Map *map = self;
|
||||||
|
|
||||||
|
// make some rooms for a small map
|
||||||
|
Room *hall = NEW(Room, "The great Hall");
|
||||||
|
Room *throne = NEW(Room, "The throne room");
|
||||||
|
Room *arena = NEW(Room, "The arena, with the minotaur");
|
||||||
|
Room *kitchen = NEW(Room, "Kitchen, you have the knife now");
|
||||||
|
|
||||||
|
// put the bad guy in the arena
|
||||||
|
arena->bad_guy = NEW(Monster, "The evil minotaur");
|
||||||
|
|
||||||
|
// setup the map rooms
|
||||||
|
hall->north = throne;
|
||||||
|
|
||||||
|
throne->west = arena;
|
||||||
|
throne->east = kitchen;
|
||||||
|
throne->south = hall;
|
||||||
|
|
||||||
|
arena->east = throne;
|
||||||
|
kitchen->west = throne;
|
||||||
|
|
||||||
|
// start the map and the characters off in the hall
|
||||||
|
map->start = hall;
|
||||||
|
map->location = hall;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object MapProto = {
|
||||||
|
.init = Map_init,
|
||||||
|
.move = Map_move,
|
||||||
|
.attack = Map_attack
|
||||||
|
};
|
||||||
|
|
||||||
|
int process_input(Map *game)
|
||||||
|
{
|
||||||
|
printf("\n> ");
|
||||||
|
|
||||||
|
char ch = getchar();
|
||||||
|
getchar(); // eat ENTER
|
||||||
|
|
||||||
|
int damage = rand() % 4;
|
||||||
|
|
||||||
|
switch(ch) {
|
||||||
|
case -1:
|
||||||
|
printf("Giving up? You suck.\n");
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
game->_(move)(game, NORTH);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
game->_(move)(game, SOUTH);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
game->_(move)(game, EAST);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'w':
|
||||||
|
game->_(move)(game, WEST);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
game->_(attack)(game, damage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
printf("You can go:\n");
|
||||||
|
if(game->location->north) printf("NORTH\n");
|
||||||
|
if(game->location->south) printf("SOUTH\n");
|
||||||
|
if(game->location->east) printf("EAST\n");
|
||||||
|
if(game->location->west) printf("WEST\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("What?: %d\n", ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// simple way to setup the randomness
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
// make our map to work with
|
||||||
|
Map *game = NEW(Map, "The Hall of the Minotaur.");
|
||||||
|
|
||||||
|
printf("You enter the ");
|
||||||
|
game->location->_(describe)(game->location);
|
||||||
|
|
||||||
|
while(process_input(game)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
67
lcthw-remnants-2/object.c
Normal file
67
lcthw-remnants-2/object.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "object.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void Object_destroy(void *self)
|
||||||
|
{
|
||||||
|
Object *obj = self;
|
||||||
|
|
||||||
|
if(obj) {
|
||||||
|
if(obj->description) free(obj->description);
|
||||||
|
free(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Object_describe(void *self)
|
||||||
|
{
|
||||||
|
Object *obj = self;
|
||||||
|
printf("%s.\n", obj->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Object_init(void *self)
|
||||||
|
{
|
||||||
|
// do nothing really
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Object_move(void *self, Direction direction)
|
||||||
|
{
|
||||||
|
printf("You can't go that direction.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Object_attack(void *self, int damage)
|
||||||
|
{
|
||||||
|
printf("You can't attack that.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Object_new(size_t size, Object proto, char *description)
|
||||||
|
{
|
||||||
|
// setup the default functions in case they aren't set
|
||||||
|
if(!proto.init) proto.init = Object_init;
|
||||||
|
if(!proto.describe) proto.describe = Object_describe;
|
||||||
|
if(!proto.destroy) proto.destroy = Object_destroy;
|
||||||
|
if(!proto.attack) proto.attack = Object_attack;
|
||||||
|
if(!proto.move) proto.move = Object_move;
|
||||||
|
|
||||||
|
// this seems weird, but we can make a struct of one size,
|
||||||
|
// then point a different pointer at it to "cast" it
|
||||||
|
Object *el = calloc(1, size);
|
||||||
|
*el = proto;
|
||||||
|
|
||||||
|
// copy the description over
|
||||||
|
el->description = strdup(description);
|
||||||
|
|
||||||
|
// initialize it with whatever init we were given
|
||||||
|
if(!el->init(el)) {
|
||||||
|
// looks like it didn't initialize properly
|
||||||
|
el->destroy(el);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
// all done, we made an object of any type
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
}
|
27
lcthw-remnants-2/object.h
Normal file
27
lcthw-remnants-2/object.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef _object_h
|
||||||
|
#define _object_h
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NORTH, SOUTH, EAST, WEST
|
||||||
|
} Direction;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *description;
|
||||||
|
int (*init)(void *self);
|
||||||
|
void (*describe)(void *self);
|
||||||
|
void (*destroy)(void *self);
|
||||||
|
void *(*move)(void *self, Direction direction);
|
||||||
|
int (*attack)(void *self, int damage);
|
||||||
|
} Object;
|
||||||
|
|
||||||
|
int Object_init(void *self);
|
||||||
|
void Object_destroy(void *self);
|
||||||
|
void Object_describe(void *self);
|
||||||
|
void *Object_move(void *self, Direction direction);
|
||||||
|
int Object_attack(void *self, int damage);
|
||||||
|
void *Object_new(size_t size, Object proto, char *description);
|
||||||
|
|
||||||
|
#define NEW(T, N) Object_new(sizeof(T), T##Proto, N)
|
||||||
|
#define _(N) proto.N
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user