From 9569ff1805c73d71994aa4a706f1fcbf3393d984 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 13 Apr 2016 18:28:47 -0400 Subject: [PATCH] ex18 extra credit + ex19 --- lcthw-remnants-2/Makefile | 6 +- lcthw-remnants-2/ex18-ec.c | 119 ++++++++++++++++++++ lcthw-remnants-2/ex19.c | 215 +++++++++++++++++++++++++++++++++++++ lcthw-remnants-2/object.c | 67 ++++++++++++ lcthw-remnants-2/object.h | 27 +++++ 5 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 lcthw-remnants-2/ex18-ec.c create mode 100644 lcthw-remnants-2/ex19.c create mode 100644 lcthw-remnants-2/object.c create mode 100644 lcthw-remnants-2/object.h diff --git a/lcthw-remnants-2/Makefile b/lcthw-remnants-2/Makefile index 1ccad02..a082257 100644 --- a/lcthw-remnants-2/Makefile +++ b/lcthw-remnants-2/Makefile @@ -1,11 +1,15 @@ +SHELL=/bin/bash CFLAGS=-Wall -g EXERCISES := $(shell ./list-exercises) all: $(EXERCISES) +ex19: object.o + clean: - $(RM) $(EXERCISES) + shopt -s nullglob ; \ + $(RM) $(EXERCISES) *.o *.a test: @./runtests diff --git a/lcthw-remnants-2/ex18-ec.c b/lcthw-remnants-2/ex18-ec.c new file mode 100644 index 0000000..75e8f6f --- /dev/null +++ b/lcthw-remnants-2/ex18-ec.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +/** 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; +} + diff --git a/lcthw-remnants-2/ex19.c b/lcthw-remnants-2/ex19.c new file mode 100644 index 0000000..682f8a1 --- /dev/null +++ b/lcthw-remnants-2/ex19.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#include +#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; +} diff --git a/lcthw-remnants-2/object.c b/lcthw-remnants-2/object.c new file mode 100644 index 0000000..6f5df17 --- /dev/null +++ b/lcthw-remnants-2/object.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include "object.h" +#include + +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; + } +} diff --git a/lcthw-remnants-2/object.h b/lcthw-remnants-2/object.h new file mode 100644 index 0000000..8862d2c --- /dev/null +++ b/lcthw-remnants-2/object.h @@ -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