Browse Source

Initial commit

Bob Mottram 3 years ago
commit
3007ad5269
8 changed files with 2332 additions and 0 deletions
  1. 26 0
      LICENSE
  2. 88 0
      Makefile
  3. 4 0
      README.md
  4. BIN
      man/libstrips.1.gz
  5. 1387 0
      src/strips.c
  6. 136 0
      src/strips.h
  7. 17 0
      unittests/Makefile
  8. 674 0
      unittests/maintest.c

+ 26 - 0
LICENSE

@@ -0,0 +1,26 @@
+ libdeep - a library for deep learning
+ Copyright (C) 2013  Bob Mottram <bob@robotics.uk.to>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. 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.
+ 3. Neither the name of the University 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 THE HOLDERS 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.

+ 88 - 0
Makefile

@@ -0,0 +1,88 @@
+APP=libstrips
+VERSION=1.00
+RELEASE=1
+SONAME=${APP}.so.0
+LIBNAME=${APP}-${VERSION}.so.0.0.${RELEASE}
+ARCH_TYPE=`uname -m`
+PREFIX?=/usr/local
+LIBDIR=lib
+ARCH_BUILD_DIR=${HOME}/abs/${APP}
+CURR_DIR=$(shell pwd)
+SELF_DIR=$(shell basename $(CURR_DIR))
+SOURCEFILE?=strips.c
+
+DATE_FMT = %Y-%m-%d
+ifdef SOURCE_DATE_EPOCH
+	BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)"  2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u "+$(DATE_FMT)")
+else
+	BUILD_DATE ?= $(shell date "+$(DATE_FMT)")
+endif
+
+ifeq ($(shell if [ -d /usr/lib64 ]; then echo "found"; fi;), "found")
+LIBDIR = lib64
+endif
+
+all:
+	rm -f src/flycheck*
+	gcc -shared -Wl,-soname,${SONAME} -std=c99 -pedantic -fPIC -O3 -o ${LIBNAME} src/*.c -Isrc -lm -fopenmp
+debug:
+	rm -f src/flycheck*
+	gcc -shared -Wl,-soname,${SONAME} -std=c99 -pedantic -fPIC -g -o ${LIBNAME} src/*.c -Isrc -lm -fopenmp
+debugstack:
+	rm -f src/flycheck*
+	gcc -shared -Wl,-soname,${SONAME} -std=c99 -pedantic -fsanitize=address -fPIC -g -o ${LIBNAME} src/*.c -Isrc -lm -fopenmp
+graph:
+	rm -f src/flycheck*
+	gcc -shared -Wl,-soname,${SONAME} -std=c99 -pedantic -fPIC -g -o ${LIBNAME} src/*.c -Isrc -lm -fopenmp -fdump-rtl-expand
+	egypt ${SOURCEFILE}.*.expand | xdot -
+	rm *.expand
+source:
+	tar -cvf ../${APP}_${VERSION}.orig.tar --exclude-vcs ../$(SELF_DIR)
+	gzip -f9n ../${APP}_${VERSION}.orig.tar
+arch:
+	rm -f ${APP} *.xz *.sig
+	@if [ ! -d ${ARCH_BUILD_DIR} ]; then\
+		mkdir -p ${ARCH_BUILD_DIR};\
+	fi
+	rm -rf ${ARCH_BUILD_DIR}/*
+	tar cvf ${ARCH_BUILD_DIR}/${APP}-${VERSION}.tar --exclude-vcs .
+	gzip -f9n ${ARCH_BUILD_DIR}/${APP}-${VERSION}.tar
+	cp PKGBUILD ${ARCH_BUILD_DIR}
+	gpg -ba ${ARCH_BUILD_DIR}/${APP}-${VERSION}.tar.gz
+	sed -i "s|arch=()|arch=('${ARCH_TYPE}')|g" ${ARCH_BUILD_DIR}/PKGBUILD
+	cd ${ARCH_BUILD_DIR}; updpkgsums; makepkg -f -c -s; makepkg --printsrcinfo > .SRCINFO
+	unxz ${ARCH_BUILD_DIR}/${APP}-${VERSION}-${RELEASE}-${ARCH_TYPE}.pkg.tar.xz
+	tar vf ${ARCH_BUILD_DIR}/${APP}-${VERSION}-${RELEASE}-${ARCH_TYPE}.pkg.tar --delete .BUILDINFO
+	xz ${ARCH_BUILD_DIR}/${APP}-${VERSION}-${RELEASE}-${ARCH_TYPE}.pkg.tar
+	gpg -ba ${ARCH_BUILD_DIR}/${APP}-${VERSION}-${RELEASE}-${ARCH_TYPE}.pkg.tar.xz
+install:
+	mkdir -p ${DESTDIR}/usr
+	mkdir -p ${DESTDIR}${PREFIX}/${LIBDIR}/${APP}
+	mkdir -p ${DESTDIR}${PREFIX}/include/${APP}
+	cp src/*.h ${DESTDIR}${PREFIX}/include/${APP}
+	install -m 755 ${LIBNAME} ${DESTDIR}${PREFIX}/${LIBDIR}
+	ln -sf ${DESTDIR}${PREFIX}/${LIBDIR}/${LIBNAME} ${DESTDIR}${PREFIX}/${LIBDIR}/${SONAME}
+	ln -sf ${DESTDIR}${PREFIX}/${LIBDIR}/${LIBNAME} ${DESTDIR}/${LIBDIR}/${SONAME}
+	ln -sf ${DESTDIR}${PREFIX}/${LIBDIR}/${LIBNAME} ${DESTDIR}${PREFIX}/${LIBDIR}/${APP}.so
+	ldconfig
+	mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/man/man1
+	install -m 644 man/${APP}.1.gz ${DESTDIR}${PREFIX}/share/man/man1
+uninstall:
+	rm -f ${PREFIX}/share/man/man1/${APP}.1.gz
+	rm -f ${PREFIX}/${LIBDIR}/${LIBNAME}
+	rm -f ${PREFIX}/${LIBDIR}/${APP}.so
+	rm -f ${PREFIX}/${LIBDIR}/${SONAME}
+	rm -f /${LIBDIR}/${SONAME}
+	rm -rf ${PREFIX}/include/${APP}
+	ldconfig
+instlib:
+	mkdir -p ${DESTDIR}/usr
+	mkdir -p ${DESTDIR}${PREFIX}/${LIBDIR}/${APP}
+	mkdir -p ${DESTDIR}${PREFIX}/include/${APP}
+	cp src/*.h ${DESTDIR}${PREFIX}/include/${APP}
+	install -m 755 ${LIBNAME} ${DESTDIR}${PREFIX}/${LIBDIR}
+	mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/man/man1
+	install -m 644 man/${APP}.1.gz ${DESTDIR}${PREFIX}/share/man/man1
+clean:
+	rm -f ${LIBNAME} \#* \.#* gnuplot* *.png src/*.plist *.expand
+	rm -f unittests/*.plist unittests/tests

+ 4 - 0
README.md

@@ -0,0 +1,4 @@
+libstrips
+=========
+
+A C/C++ library implementing the STRIPS planner algorithm.

BIN
man/libstrips.1.gz


+ 1387 - 0
src/strips.c

@@ -0,0 +1,1387 @@
+/*
+  libstrips -  predicate based planner
+  Copyright (C) 2017  Bob Mottram <bob@freedombone.net>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  2. 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.
+  3. Neither the name of the University 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 THE HOLDERS 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 "strips.h"
+
+/**
+ * @brief Ensures that only whitelisted characters are parsed from text files
+ * @param c The character to be tested
+ * @returns True if the character is valid
+ */
+static int strips_permitted_char(char c)
+{
+    if (((c >= 'a') && (c <= 'z')) ||
+        ((c >= 'A') && (c <= 'Z')) ||
+        ((c >= '0') && (c <= '9')) ||
+        (c == '(') || (c == ')') ||
+        (c == ',') || (c == '.') || (c == '!'))
+        return STRIPS_TRUE;
+    return STRIPS_FALSE;
+}
+
+/**
+ * @brief Shows mappings between variables and grounded values
+ * @param fp Stream to output to
+ * @param literals Array containing literals
+ * @param no_of_literals The number of literals
+ */
+static void strips_show_literals(FILE * fp, strips_literal literal[],
+                                 int no_of_literals)
+{
+    for (int i = 0; i < no_of_literals; i++) {
+        fprintf(fp, "%s -> %s\n", literal[i].variable, literal[i].grounded);
+    }
+}
+
+/**
+ * @brief Shows an array of conditions
+ * @param fp Stream to output to
+ * @param conditions Array containing conditions
+ * @param The number of conditions
+ */
+static void strips_show_conditions(FILE * fp, strips_condition conditions[],
+                                   int no_of_conditions)
+{
+    for (int i = 0; i < no_of_conditions; i++) {
+        if (!conditions[i].truth)
+            fprintf(fp, "!");
+        fprintf(fp, "%s(", conditions[i].predicate);
+        for (int j = 0; j < conditions[i].no_of_params; j++) {
+            fprintf(fp, "%s", conditions[i].params[j]);
+            if (j < conditions[i].no_of_params-1) {
+                fprintf(fp, ",");
+            }
+        }
+        fprintf(fp, ")");
+        if (i < no_of_conditions-1) {
+            fprintf(fp, ", ");
+        }
+    }
+    fprintf(fp, "\n");
+}
+
+/**
+ * @brief Shows an action
+ * @param fp Stream to output to
+ * @param action The action to show
+ */
+static void strips_show_action(FILE * fp, strips_action * action)
+{
+    fprintf(fp, "    %s(", action->declaration.predicate);
+    for (int i = 0; i < action->declaration.no_of_params; i++) {
+        fprintf(fp, "%s", action->declaration.params[i]);
+        if (i < action->declaration.no_of_params-1) {
+            fprintf(fp, ",");
+        }
+    }
+    fprintf(fp, ")\n");
+
+    fprintf(fp, "    Preconditions: ");
+    strips_show_conditions(fp, action->pre, action->no_of_pre);
+    fprintf(fp, "    Postconditions: ");
+    strips_show_conditions(fp, action->post, action->no_of_post);
+}
+
+/**
+ * @brief Shows a world system
+ * @param fp Stream to output to
+ * @param w World system
+ */
+void strips_show_world(FILE * fp, strips_world * w)
+{
+    fprintf(fp, "Initial state: ");
+    strips_show_conditions(fp, w->initial, w->no_of_initial);
+    fprintf(fp, "Goal state: ");
+    strips_show_conditions(fp, w->goals, w->no_of_goals);
+    fprintf(fp, "\nActions:\n\n");
+
+    for (int i = 0; i < w->no_of_actions; i++) {
+        strips_show_action(fp, &w->actions[i]);
+
+        if (i < w->no_of_actions-1)
+            fprintf(fp, "\n");
+    }
+}
+
+/**
+ * @brief Returns the file section type from the given line of text
+ * @param line Line of text
+ * @param section Returned section name
+ * @returns Section index as defined by strips_file_section, or -1 if not found
+ */
+int strips_extract_file_section(char line[], char section[])
+{
+    int i, n = 0, section_index = FILE_SECTION_ACTION_DECLARATION;
+    char * pos = strchr(line,':');
+
+    section[0] = 0;
+    if (pos == NULL) {
+        if (strchr(line, '(') != NULL)
+            return FILE_SECTION_ACTION_DECLARATION;
+        return -1;
+    }
+
+    for (i = 0; i < strlen(line); i++) {
+        if (line[i] == ':')
+            break;
+        if (n >= STRIPS_STRING_BLOCK-1)
+            break;
+        if (strips_permitted_char(line[i]))
+            section[n++] = tolower(line[i]);
+    }
+    section[n] = 0;
+
+    if (strncmp("initial", section, strlen("initial")) == 0)
+        section_index = FILE_SECTION_INITIAL;
+
+    if (strncmp("goal", section, strlen("goal")) == 0)
+        section_index = FILE_SECTION_GOAL;
+
+    if (strncmp("actions", section, strlen("actions")) == 0)
+        section_index = FILE_SECTION_ACTIONS;
+
+    if (strncmp("pre", section, strlen("pre")) == 0)
+        section_index = FILE_SECTION_ACTION_PRE;
+
+    if (strncmp("post", section, strlen("post")) == 0)
+        section_index = FILE_SECTION_ACTION_POST;
+
+    return section_index;
+}
+
+/**
+ * @brief Extracts multiple predicates from a line of text
+ * @param line Line of text
+ * @param predicate_str Returned array containing predicate strings
+ * @returns The number of predicates extracted from the line
+ */
+int strips_extract_file_predicates(char line[],
+                                   char predicate_str[STRIPS_MAX_PREDICATES_PER_LINE][STRIPS_STRING_BLOCK])
+{
+    int i = 0, j, started = 0, depth = -1, firstparen;
+    int start_pos = 0, no_of_predicates = 0, n;
+    char * pos = strchr(line,':');
+    if (pos == NULL) {
+        if (strchr(line,'(') != NULL) {
+            started = 1;
+        }
+        else {
+            return 0;
+        }
+    }
+
+    while (i < strlen(line)) {
+        if (started == 0) {
+            if (line[i] == ':') {
+                started = 1;
+                depth = -1;
+                start_pos = i+1;
+            }
+        }
+        else {
+            if (line[i] == '(') {
+                if (depth == -1)
+                    depth = 1;
+                else
+                    depth++;
+            }
+            if (line[i] == ')') {
+                depth--;
+                if (depth == 0) {
+                    n = 0;
+                    firstparen = 0;
+                    for (j = start_pos; j<= i; j++) {
+                        if (n >= STRIPS_STRING_BLOCK-1)
+                            break;
+
+                        if (line[j] == '(')
+                            firstparen = 1;
+
+                        if ((line[j] != ' ') &&
+                            (!((firstparen == 0) && (line[j] == ','))))
+                            if (strips_permitted_char(line[j]))
+                                predicate_str[no_of_predicates][n++] = line[j];
+                    }
+                    predicate_str[no_of_predicates][n] = 0;
+                    if (n < STRIPS_STRING_BLOCK-1)
+                        no_of_predicates++;
+                    start_pos = i+1;
+                    if (no_of_predicates >= STRIPS_MAX_PREDICATES_PER_LINE)
+                        return no_of_predicates;
+                }
+            }
+        }
+        i++;
+    }
+
+    return no_of_predicates;
+}
+
+/**
+ * @brief Parses the given predicate text and returns an equivalent condition
+ * @param predicate_str Predicate text, eg. MyPredicate(Symbol1, Symbol2)
+ * @param result The returned predicate as a condition structure
+ * @returns Zero on success
+ */
+int strips_parse_predicate(char predicate_str[],
+                           strips_condition * result)
+{
+    int n = 0, state = 0;
+
+    result->no_of_params = 0;
+    result->grounded = STRIPS_FALSE;
+    result->truth = STRIPS_TRUE;
+
+    for (int i = 0; i < strlen(predicate_str); i++) {
+        if (!strips_permitted_char(predicate_str[i]))
+            continue;
+        switch(state) {
+        case 0: {
+            if (predicate_str[i] != '(') {
+                if (predicate_str[i] != '!') {
+                    result->predicate[n++] = predicate_str[i];
+                }
+                else {
+                    result->truth = STRIPS_FALSE;
+                }
+            }
+            else {
+                result->predicate[n] = 0;
+                n = 0;
+                state++;
+            }
+            break;
+        }
+        case 1: {
+            if ((predicate_str[i] != ',') && (predicate_str[i] != ')')) {
+                result->params[result->no_of_params][n++] = predicate_str[i];
+            }
+            else {
+                if (n > 0) {
+                    result->params[result->no_of_params][n] = 0;
+                    result->no_of_params++;
+                    n = 0;
+                }
+            }
+            break;
+        }
+        }
+    }
+    if (result->no_of_params == 0)
+        return 1;
+    return 0;
+}
+
+/**
+ * @brief Checks if a given condition exists in an array
+ * @param conditions Array containing conditions
+ * @param length Length of the array
+ * @param search The condition to search for
+ * @returns Array index of the matching condition, or -1 if not found
+ */
+int strips_condition_exists(strips_condition conditions[], int length,
+                            strips_condition * search)
+{
+    /* for every condition in the array */
+    for (int i = 0; i < length; i++) {
+
+        /* check same number of parameters */
+        if (conditions[i].no_of_params == search->no_of_params) {
+
+            /* check same predicate name */
+            if (strcmp(search->predicate, conditions[i].predicate) == 0) {
+
+                /* check that all of the parameters match */
+                int matched = 1;
+                if (strcmp(conditions[i].params[0], search->params[0]) != 0)
+                    matched = 0;
+                else
+                    if ((search->no_of_params > 1) &&
+                        (conditions[i].truth != search->truth))
+                        matched = 0;
+
+                /* if matched return the array index */
+                if (matched == 1)
+                    return i;
+            }
+        }
+    }
+
+    /* no matches found */
+    return -1;
+}
+
+/**
+ * @brief If an action exists return its array index
+ * @param w World system
+ * @param action The action to search for
+ * @returns Array index of the action or -1 if not found
+ */
+int strips_action_exists(strips_world * w, char action[])
+{
+    if (action[0] == 0)
+        return -1;
+
+    for (int i = 0; i < w->no_of_actions; i++) {
+        if (strcmp(action, w->actions[i].declaration.predicate) == 0)
+            return i;
+    }
+    return -1;
+}
+
+/**
+ * @brief Adds a condition to an array, ensuring no duplicates
+ * @param condistions Array containing conditions
+ * @param length Length of the array
+ * @param new_condition The condition to be added
+ * @returns Zero on success, 1 if the condition is already in the array
+ */
+int strips_add_condition(strips_condition conditions[], int length,
+                         strips_condition * new_condition)
+{
+    int index =
+        strips_condition_exists(conditions, length, new_condition);
+
+    if (index >= 0) {
+        memcpy((void*)&conditions[index], (void*)new_condition,
+               sizeof(strips_condition));
+        return 1;
+    }
+
+    memcpy((void*)&conditions[length], (void*)new_condition,
+           sizeof(strips_condition));
+
+    return 0;
+}
+
+/**
+ * @brief removes a condition from an array
+ * @param condistions Array containing conditions
+ * @param length Length of the array
+ * @param remove_condition The condition to be removed
+ * @returns Zero on success, 1 if the condition is not in the array
+ */
+int strips_remove_condition(strips_condition conditions[], int length,
+                            strips_condition * remove_condition)
+{
+    int index =
+        strips_condition_exists(conditions, length, remove_condition);
+
+    if (index < 0)
+        return 1;
+
+    for (int i = index; i < length-1; i++) {
+        memcpy((void*)&conditions[i], (void*)&conditions[i+1],
+               sizeof(strips_condition));
+    }
+
+    return 0;
+}
+
+/**
+ * @brief Copies the given condition and replaces any variables with grounded values
+ * @param source The condition to be copied
+ * @param literals Array containing mappings between variables and grounded values
+ * @param no_of_literals The number of literals
+ * @returns Copied condition
+ */
+static strips_condition * strips_copy_condition(strips_condition * source,
+                                                strips_literal literals[],
+                                                int no_of_literals)
+{
+    int i, j;
+    strips_condition * destination =
+        (strips_condition*)malloc(sizeof(strips_condition));
+    if (!destination)
+        return NULL;
+
+    memcpy((void*)destination, (void*)source, sizeof(strips_condition));
+
+    /* replace any variables with grounded values */
+    destination->grounded = STRIPS_TRUE;
+    for (i = 0; i < destination->no_of_params; i++) {
+        for (j = 0; j < no_of_literals; j++) {
+            if (strcmp(literals[j].variable, destination->params[i]) == 0) {
+                sprintf(destination->params[i], "%s", literals[j].grounded);
+                break;
+            }
+        }
+        if (j == no_of_literals)
+            destination->grounded = STRIPS_FALSE;
+    }
+
+    return destination;
+}
+
+/**
+ * @brief Adds a number of conditions to the given state array
+ * @param state Array containing states
+ * @param no_of_states Number of states in the array
+ * @param max_states The maximum number of states
+ * @param literals Array containing literals
+ * @param no_of_literals The number of literals
+ * @param additions Array containing conditions to be added
+ * @param no_of_additions Number of conditions to be added
+ * @returns Number of states after additions
+ */
+int strips_add_conditions_to_state(strips_condition state[],
+                                   int no_of_states, int max_states,
+                                   strips_literal literals[],
+                                   int no_of_literals,
+                                   strips_condition additions[],
+                                   int no_of_additions)
+{
+    for (int i = 0; i < no_of_additions; i++) {
+        if (no_of_states >= max_states)
+            break;
+
+        strips_condition * addition =
+            strips_copy_condition(&additions[i], literals, no_of_literals);
+
+        if (addition != NULL) {
+            if (strips_add_condition(state, no_of_states, addition) == 0)
+                no_of_states++;
+
+            free(addition);
+        }
+    }
+    return no_of_states;
+}
+
+/**
+ * @brief Removes a number of conditions from the given state array
+ * @param state Array containing states
+ * @param no_of_states Number of states in the array
+ * @param literals Array containing literals
+ * @param no_of_literals The number of literals
+ * @param removes Array containing conditions to be removed
+ * @param no_of_removes Number of conditions to be removed
+ * @returns Number of states after removals
+ */
+int strips_remove_conditions_from_state(strips_condition state[],
+                                        int no_of_states,
+                                        strips_literal literals[],
+                                        int no_of_literals,
+                                        strips_condition removes[],
+                                        int no_of_removes)
+{
+    for (int i = 0; i < no_of_removes; i++) {
+        strips_condition * remove =
+            strips_copy_condition(&removes[i], literals, no_of_literals);
+
+        if (remove != NULL) {
+            if (strips_remove_condition(state, no_of_states, remove) == 0)
+                no_of_states--;
+
+            free(remove);
+        }
+    }
+    return no_of_states;
+}
+
+/**
+ * @brief Adds a new predicate to the given world system
+ * @param w World system
+ * @param section_index The section to add the predicate to,
+ *        as defined by the strips_file_section enumeration
+ * @param predicate_str The predicate to be added, as a string
+ *        such as MyPredicate(Symbol)
+ * @param current_action If appropriate, the action to add the predicate to
+ * @returns Zero on success
+ */
+int strips_add_predicate(strips_world * w,
+                         int section_index, char predicate_str[],
+                         char current_action[])
+{
+    strips_condition pred;
+
+    if (strips_parse_predicate(predicate_str, &pred) != 0)
+        return 1;
+
+    switch(section_index) {
+    case FILE_SECTION_INITIAL: {
+        if (w->no_of_initial < STRIPS_MAX_STATES) {
+            pred.grounded = STRIPS_TRUE;
+            if (strips_add_condition(w->initial, w->no_of_initial, &pred) == 0)
+                w->no_of_initial++;
+        }
+        break;
+    }
+    case FILE_SECTION_GOAL: {
+        if (w->no_of_goals < STRIPS_MAX_GOALS) {
+            pred.grounded = STRIPS_TRUE;
+            if (strips_add_condition(w->goals, w->no_of_goals, &pred) == 0)
+                w->no_of_goals++;
+        }
+        break;
+    }
+    case FILE_SECTION_ACTIONS: {
+        break;
+    }
+    case FILE_SECTION_ACTION_DECLARATION: {
+        sprintf(current_action, "%s", pred.predicate);
+        int action_index = strips_action_exists(w, current_action);
+        if (action_index == -1)
+            action_index = w->no_of_actions;
+        memcpy((void*)&w->actions[action_index],
+               &pred, sizeof(strips_condition));
+        if ((action_index == w->no_of_actions) &&
+            (w->no_of_actions < STRIPS_MAX_ACTIONS)) {
+            w->actions[action_index].no_of_pre = 0;
+            w->actions[action_index].no_of_post = 0;
+            w->no_of_actions++;
+        }
+
+        break;
+    }
+    case FILE_SECTION_ACTION_PRE: {
+        int action_index = strips_action_exists(w, current_action);
+        if (action_index > -1) {
+            if (w->actions[action_index].no_of_pre < STRIPS_MAX_CONDITIONS) {
+                if (strips_add_condition(w->actions[action_index].pre,
+                                         w->actions[action_index].no_of_pre,
+                                         &pred) == 0) {
+                    w->actions[action_index].no_of_pre++;
+                }
+            }
+        }
+        break;
+    }
+    case FILE_SECTION_ACTION_POST: {
+        int action_index = strips_action_exists(w, current_action);
+        if (action_index > -1) {
+            if (w->actions[action_index].no_of_post < STRIPS_MAX_CONDITIONS) {
+                if (strips_add_condition(w->actions[action_index].post,
+                                         w->actions[action_index].no_of_post,
+                                         &pred) == 0) {
+                    w->actions[action_index].no_of_post++;
+                }
+            }
+        }
+        break;
+    }
+    }
+
+    return 0;
+}
+
+/**
+ * @brief The number of matches of the current state to the post
+ *        conditions of the given action
+ * @param state Current world state
+ * @param no_of_states Number of states in the world
+ * @param action The possible previous action to be evaluated
+ * @returns Number of matches for the given action
+ */
+int strips_possible_previous_action(strips_condition state[],
+                                    int no_of_states,
+                                    strips_action * action)
+{
+    int i, j, hits = 0;
+
+    for (i = 0; i < action->no_of_post; i++) {
+        for (j = 0; j < no_of_states; j++) {
+            if (action->post[i].no_of_params != state[j].no_of_params)
+                continue;
+
+            if (action->post[i].truth != state[j].truth)
+                continue;
+
+            if (strcmp(action->post[i].predicate, state[j].predicate) != 0)
+                continue;
+
+            hits++;
+            break;
+        }
+
+        if ((!action->post[i].truth) && (j == no_of_states)) {
+            hits++;
+        }
+    }
+
+    return hits;
+}
+
+/**
+ * @brief Indicates to what extent the initial conditions are satisfied
+ * @param w World system
+ * @param state Array containing conditions to be check against initial
+ * @param no_of_states The number of conditions
+ * @returns Number of matched conditions
+ */
+static int strips_match_initial(strips_world * w,
+                                strips_condition state[],
+                                int no_of_states)
+{
+    int i, j, k, hits = 0;
+
+    for (i = 0; i < w->no_of_initial; i++) {
+        if (!w->initial[i].truth)
+            continue;
+
+        for (j = 0; j < no_of_states; j++) {
+            if (w->initial[i].no_of_params != state[j].no_of_params)
+                continue;
+
+            if (w->initial[i].truth != state[j].truth)
+                continue;
+
+            if (strcmp(w->initial[i].predicate, state[j].predicate) != 0)
+                continue;
+
+            for (k = 0; k < w->initial[i].no_of_params; k++) {
+                if (strcmp(w->initial[i].params[k], state[j].params[k]) != 0)
+                    break;
+            }
+            if (k < w->initial[i].no_of_params)
+                continue;
+
+            hits++;
+            break;
+        }
+    }
+
+    return hits;
+}
+
+/**
+ * @brief If a given mapping between variable and grounded value exists then
+ *        retun its array index
+ * @param literals Array containing literals mappings
+ * @param no_of_literals The number of literals
+ * @param variable The variable to be checked
+ * @param grounded The grounded value to be checked
+ * @returns Array index of the literal or -1 if not found
+ */
+static int strips_literal_exists(strips_literal literals[], int no_of_literals,
+                                 char variable[], char grounded[])
+{
+    for (int i = 0; i < no_of_literals; i++) {
+        if (strcmp(literals[i].variable, variable) == 0)
+            return i;
+    }
+
+    return -1;
+}
+
+/**
+ * @brief Adds a mapping beteen a variable and grounded value
+ * @param literals Array containing literals mappings
+ * @param no_of_literals The number of literals
+ * @param max_literals The maximum number of mappings
+ * @param variable The variable to be checked
+ * @param grounded The grounded value to be checked
+ * @returns Zero on success
+ */
+static int strips_add_literal(strips_literal literals[], int no_of_literals,
+                              int max_literals,
+                              char variable[], char grounded[])
+{
+    if (no_of_literals >= max_literals)
+        return -1;
+
+    if (strips_literal_exists(literals, no_of_literals,
+                              variable, grounded) > -1)
+        return -2;
+
+    if (strcmp(variable, grounded) == 0)
+        return -3;
+
+    sprintf(literals[no_of_literals].variable, "%s", variable);
+    sprintf(literals[no_of_literals].grounded, "%s", grounded);
+
+    return 0;
+}
+
+/**
+ * @brief Attempts to ground the given conditions based upon existing groundings
+ * @param grounded Array of existing grounded conditions
+ * @param no_of_grounded The number of existing grounded conditions
+ * @param conditions Array containing the conditions to be grounded
+ * @param no_of_conditions The number of conditions to be grounded
+ * @returns The number of literals
+ */
+int strips_map_variables(strips_condition grounded[], int no_of_grounded,
+                         strips_condition conditions[], int no_of_conditions,
+                         strips_literal literals[], int no_of_literals)
+{
+    for (int i = 0; i < no_of_grounded; i++) {
+        if (!grounded[i].grounded)
+            continue;
+
+        for (int j = 0; j < no_of_conditions; j++) {
+            if (conditions[j].grounded)
+                continue;
+
+            if (grounded[i].truth == conditions[j].truth) {
+
+                /* check same number of parameters */
+                if (grounded[i].no_of_params == conditions[j].no_of_params) {
+
+
+                    /* check same predicate name */
+                    if (strcmp(conditions[j].predicate, grounded[i].predicate) == 0) {
+
+                        /* check that all of the parameters match */
+                        for (int k = 0; k < grounded[i].no_of_params; k++) {
+                            if (strips_add_literal(literals, no_of_literals,
+                                                   STRIPS_MAX_LITERALS,
+                                                   conditions[j].params[k],
+                                                   grounded[i].params[k]) == 0)
+                                no_of_literals++;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return no_of_literals;
+}
+
+/**
+ * @brief Creates an array containing matching scores for each action
+ * @param w World system
+ * @param goals Array containing goals to be matched
+ * @param no_of_goals The number of goals
+ * @returns Array containing matching scores, or NULL
+ */
+int * strips_match_actions(strips_world * w,
+                           strips_condition goals[], int no_of_goals)
+{
+    int * action_matches = (int*)malloc(STRIPS_MAX_ACTIONS * sizeof(int));
+    if (!action_matches)
+        return NULL;
+
+    /* match each action and store the scores in an array */
+    for (int a = 0; a < w->no_of_actions; a++) {
+        action_matches[a] =
+            strips_possible_previous_action(goals, no_of_goals,
+                                            &w->actions[a]);
+    }
+
+    return action_matches;
+}
+
+/**
+ * @brief Appends an action declaration to a plan
+ * @param action The declaration for an action
+ * @param plan String containing the plan
+ * @param literals Array containing literals
+ * @param no_of_literals The number of literals
+ */
+void strips_update_plan(strips_condition * action, char plan[],
+                        strips_literal literals[], int no_of_literals)
+{
+    char new_plan[STRIPS_STRING_PLAN];
+    char pred[STRIPS_STRING];
+    int i, j, k, n;
+
+    for (i = 0; i < strlen(action->predicate); i++) {
+        pred[i] = action->predicate[i];
+        if (i >= STRIPS_STRING-4)
+            break;
+    }
+    pred[i++] = '(';
+    for (j = 0; j < action->no_of_params; j++) {
+        for (k = 0; k < no_of_literals; k++) {
+            if (strcmp(action->params[j], literals[k].variable) == 0) {
+                break;
+            }
+        }
+        if (k < no_of_literals) {
+            for (n = 0; n < strlen(literals[k].grounded); n++) {
+                pred[i++] = literals[k].grounded[n];
+                if (i >= STRIPS_STRING-4)
+                    break;
+            }
+        }
+        else {
+            for (n = 0; n < strlen(action->params[j]); n++) {
+                pred[i++] = action->params[j][n];
+                if (i >= STRIPS_STRING-4)
+                    break;
+            }
+        }
+        if (j < action->no_of_params-1) {
+            pred[i++] = ',';
+        }
+    }
+    pred[i++] = ')';
+    pred[i] = 0;
+
+    sprintf(new_plan, "%s%s\n", plan, pred);
+    sprintf(plan, "%s", new_plan);
+}
+
+/**
+ * @brief Frees an array containing a number of strings
+ * @param s The array to be freed
+ * @param max_length The number of strings in the array
+ */
+static void strips_free_string_array(char ** s, int max_length)
+{
+    for (int i = 0; i < max_length; i++) {
+        if (s[i] != NULL)
+            free(s[i]);
+        else
+            break;
+    }
+    free(s);
+}
+
+/**
+ * @brief Given a predicate which indicates the type of a variable
+ *        return the possible grounded values of the variable from
+ *        the initial state
+ * @param w World system
+ * @param type_predicate The type to search for
+ * @patam max_values The maximum number of grounded values to return
+ * @returns Array containing possible grounded values
+ */
+char ** strips_get_initial_type_values(strips_world * w,
+                                       char type_predicate[],
+                                       int max_values)
+{
+    char ** possible_values = NULL;
+    int j, no_of_values = 0;
+
+    /* create the array for returning values */
+    possible_values = (char**)malloc(max_values*sizeof(char*));
+    if (!possible_values)
+        return NULL;
+    for (int i = 0; i < max_values; i++)
+        possible_values[i] = NULL;
+
+    for (int i = 0; i < w->no_of_initial; i++) {
+        if (w->initial[i].no_of_params != 1)
+            continue;
+
+        if (strcmp(w->initial[i].predicate, type_predicate) != 0)
+            continue;
+
+        /* check that the value isn't already in the array */
+        for (j = 0; j < no_of_values; j++) {
+            if (strcmp(possible_values[j], w->initial[i].params[0]) == 0)
+                break;
+        }
+        if (j < no_of_values)
+            continue;
+
+        /* create the new string */
+        possible_values[no_of_values] =
+            (char*)malloc(STRIPS_STRING*sizeof(char));
+        if (!possible_values[no_of_values]) {
+            strips_free_string_array(possible_values, i);
+            return NULL;
+        }
+
+        /* store the value */
+        sprintf(possible_values[no_of_values], "%s", w->initial[i].params[0]);
+        no_of_values++;
+        if (no_of_values >= max_values)
+            break;
+    }
+
+    return possible_values;
+}
+
+/**
+ * @brief Given a variable return its possible types
+ * @param variable Name of the variable
+ * @param conditions Array containing conditions to search through
+ * @param no_of_conditions The number of conditions to search
+ * @param max_types The maximum number of returned types
+ * @returns Array containing possible types
+ */
+char ** strips_get_possible_variable_types(char variable[],
+                                           strips_condition conditions[],
+                                           int no_of_conditions,
+                                           int max_types)
+{
+    int i, j;
+    char ** possible_types = NULL;
+    int no_of_types = 0;
+
+    /* create the array for returning types */
+    possible_types = (char**)malloc(max_types*sizeof(char*));
+    if (!possible_types)
+        return NULL;
+    for (i = 0; i < max_types; i++)
+        possible_types[i] = NULL;
+
+    for (i = 0; i < no_of_conditions; i++) {
+        if (conditions[i].no_of_params != 1)
+            continue;
+
+        if (strcmp(conditions[i].params[0], variable) != 0)
+            continue;
+
+        /* Check that the type isn't already in the array */
+        for (j = 0; j < no_of_types; j++) {
+            if (strcmp(possible_types[j], conditions[i].predicate) == 0)
+                break;
+        }
+        if (j < no_of_types)
+            continue;
+
+        /* Allocate memory for the predicate type string */
+        possible_types[no_of_types] =
+            (char*)malloc(STRIPS_STRING*sizeof(char));
+        if (!possible_types[no_of_types]) {
+            strips_free_string_array(possible_types, i);
+            return NULL;
+        }
+
+        /* Store the predicate type string */
+        sprintf(possible_types[no_of_types], "%s", conditions[i].predicate);
+        no_of_types++;
+        if (no_of_types >= max_types)
+            break;
+    }
+
+    return possible_types;
+}
+
+/**
+ * @brief Replaces a variable with a grounded value in the given goals
+ * @param variable The variable name to search for
+ * @param grounded The grounded value to replace with
+ * @param goals Array containing goals to be searched
+ * @param no_of_goals The number of goals
+ */
+static void strips_replace_variable(char variable[], char grounded[],
+                                    strips_condition goals[], int no_of_goals)
+{
+    for (int i = 0; i < no_of_goals; i++) {
+        for (int j = 0; j < goals[i].no_of_params; j++) {
+            if (strcmp(goals[i].params[j], variable) == 0) {
+                sprintf(goals[i].params[j], "%s", grounded);
+                break;
+            }
+        }
+    }
+}
+
+/**
+ * @brief Does the given grounded value exist within the goals?
+ * @param grounded String containing the grounded value
+ * @param goals Array containing goals to be searched
+ * @param no_of_goals The number of goals
+ * @returns True if the grounded value exists in the array
+ */
+static int strips_grounded_exists(char grounded[],
+                                  strips_condition goals[], int no_of_goals)
+{
+    for (int i = 0; i < no_of_goals; i++) {
+        for (int j = 0; j < goals[i].no_of_params; j++) {
+            if (strcmp(goals[i].params[j], grounded) == 0) {
+                return STRIPS_TRUE;
+            }
+        }
+    }
+    return STRIPS_FALSE;
+}
+
+/**
+ * @brief Attempts to find the values of ungrounded variables in the current goals
+ * @param w World system
+ * @param goals Array containing current goals
+ * @param no_of_goals The number of goals
+ * @param literals Mappings between variables and grounded values
+ * @param no_of_literals The number of literals
+ * @param search_complete Whether the search is complete
+ * @param steps The current search depth or number of steps in the plan
+ * @param max_steps The maximum search depth or steps in the plan
+ * @param plan Returned plan as a string
+ * @param action_index Index of the current action being searched
+ * @returns True if a valid plan is found
+ */
+int strips_search_ungrounded_variables(strips_world * w,
+                                       strips_condition goals[], int no_of_goals,
+                                       strips_literal literals[], int no_of_literals,
+                                       unsigned char * search_complete,
+                                       int steps, int max_steps,
+                                       char plan[], int action_index)
+{
+    int i, j, k, n;
+    char ** curr_possible_types = NULL;
+    char ** possible_types;
+    char ** possible_values;
+    const int max_types = 8;
+    const int max_values = 8;
+
+    for (i = 0; i < no_of_goals; i++) {
+        if (goals[i].grounded)
+            continue;
+
+        for (j = 0; j < goals[i].no_of_params; j++) {
+            /* check if it is a known grounded value */
+            for (k = 0; k < no_of_literals; k++) {
+                if (strcmp(literals[k].grounded, goals[i].params[j]) == 0)
+                    break;
+            }
+
+            if (k < no_of_literals)
+                continue;
+
+            possible_types =
+                strips_get_possible_variable_types(goals[i].params[j],
+                                                   goals, no_of_goals,
+                                                   max_types);
+            if (!possible_types)
+                continue;
+
+            if (curr_possible_types == NULL) {
+                curr_possible_types = (char**)malloc(max_types*sizeof(char*));
+                if (!curr_possible_types) {
+                    strips_free_string_array(possible_types, max_types);
+                    return STRIPS_FALSE;
+                }
+
+                for (k = 0; k < max_types; k++)
+                    curr_possible_types[k] = NULL;
+            }
+
+            for (n = 0; n < max_types; n++) {
+                if (curr_possible_types[n] == NULL)
+                    break;
+            }
+            for (k = 0; k < max_types; k++) {
+                if ((possible_types[k] == NULL) || (n >= max_types))
+                    break;
+                curr_possible_types[n] = (char*)malloc(STRIPS_STRING*sizeof(char));
+                if (curr_possible_types[n]) {
+                    sprintf(curr_possible_types[n++], "%s,%s", goals[i].params[j], possible_types[k]);
+                }
+            }
+
+            strips_free_string_array(possible_types, max_types);
+        }
+    }
+
+    if (curr_possible_types == NULL)
+        return STRIPS_FALSE;
+
+    for (n = 0; n < max_types; n++) {
+        if (curr_possible_types[n] == NULL)
+            break;
+
+        char * pos = strchr(curr_possible_types[n], ',') + 1;
+        possible_values =
+            strips_get_initial_type_values(w, pos, max_values);
+
+        for (j = 0; j < strlen(curr_possible_types[n]); j++) {
+            if (curr_possible_types[n][j] == ',') {
+                curr_possible_types[n][j] = 0;
+                break;
+            }
+        }
+
+        for (k = 0; k < max_values; k++) {
+            if (possible_values[k] == NULL)
+                break;
+
+            if (strips_grounded_exists(possible_values[k],
+                                       goals, no_of_goals))
+                continue;
+
+            int no_of_new_goals = no_of_goals;
+            strips_condition * new_goals =
+                (strips_condition*)malloc(STRIPS_MAX_GOALS *
+                                          sizeof(strips_condition));
+            if (!new_goals)
+                break;
+
+            memcpy((void*)new_goals,
+                   (void*)&goals[0],
+                   no_of_goals*sizeof(strips_condition));
+
+            strips_replace_variable(curr_possible_types[n], possible_values[k],
+                                    new_goals, no_of_new_goals);
+
+            /* next level search */
+            if (strips_solve_for_goals(w, new_goals, no_of_new_goals,
+                                       literals, no_of_literals,
+                                       search_complete, steps+1, max_steps,
+                                       plan)) {
+
+                if (no_of_literals < STRIPS_MAX_LITERALS) {
+                    sprintf(literals[no_of_literals].variable, "%s", curr_possible_types[n]);
+                    sprintf(literals[no_of_literals].grounded, "%s", possible_values[k]);
+                    no_of_literals++;
+                }
+
+                strips_update_plan(&w->actions[action_index].declaration, plan,
+                                   literals, no_of_literals);
+                free(new_goals);
+                strips_free_string_array(possible_values, max_values);
+                strips_free_string_array(curr_possible_types, max_types);
+                return STRIPS_TRUE;
+            }
+
+            free(new_goals);
+        }
+
+        strips_free_string_array(possible_values, max_values);
+    }
+
+    strips_free_string_array(curr_possible_types, max_types);
+    return STRIPS_FALSE;
+}
+
+/**
+ * @brief The main recursive function to locate a plan
+ * @param w World system
+ * @param goals Array containing current goals
+ * @param no_of_goals The number of goals
+ * @param literals Array containing mappings between variables and grounded values
+ * @param no_of_literals The number of literals
+ * @param search_complete Whether the search is complete
+ * @param steps Current depth of the search, corresponding to steps in the plan
+ * @param max_steps The maximum steps in the plan (max search depth)
+ * @param plan String containing the returned plan
+ * @returns True if a valid plan is found
+ */
+int strips_solve_for_goals(strips_world * w,
+                           strips_condition goals[], int no_of_goals,
+                           strips_literal literals[], int no_of_literals,
+                           unsigned char * search_complete,
+                           int steps, int max_steps,
+                           char plan[])
+{
+    if ((*search_complete) || (steps >= max_steps))
+        return STRIPS_FALSE;
+
+    /* are we there yet ? */
+    int matched_initial =
+        strips_match_initial(w, goals, no_of_goals);
+    if (matched_initial > 0) {
+        *search_complete = STRIPS_TRUE;
+        return STRIPS_TRUE;
+    }
+
+    /* get possible actions */
+    int * action_matches = strips_match_actions(w, goals, no_of_goals);
+    if (action_matches == NULL)
+        return STRIPS_FALSE;
+
+    /* greedy recursive search through the actions */
+    int index = 0;
+    while (index >= 0) {
+
+        /* get the array index of the action with the highest matching score */
+        index = -1;
+        int max_matches = 0;
+        for (int a = 0; a < w->no_of_actions; a++) {
+            if (action_matches[a] > max_matches) {
+                max_matches = action_matches[a];
+                index = a;
+            }
+        }
+
+        if ((index < 0) || (max_matches < no_of_goals))
+            break;
+
+        /* create a new goals state */
+        int no_of_new_goals = no_of_goals;
+        strips_condition * new_goals =
+            (strips_condition*)malloc(STRIPS_MAX_GOALS *
+                                      sizeof(strips_condition));
+        if (!new_goals)
+            break;
+
+        int no_of_new_literals = no_of_literals;
+        strips_literal * new_literals =
+            (strips_literal*)malloc(STRIPS_MAX_LITERALS *
+                                    sizeof(strips_literal));
+        if (!new_literals) {
+            free(new_goals);
+            break;
+        }
+
+        /* copy over the existing state */
+        memcpy((void*)new_goals,
+               (void*)&goals[0],
+               no_of_goals*sizeof(strips_condition));
+
+        /* copy over the existing literals */
+        memcpy((void*)new_literals,
+               (void*)&literals[0],
+               no_of_literals*sizeof(strips_literal));
+
+        /* update the mappings between variables and grounded values */
+        no_of_new_literals =
+            strips_map_variables(new_goals,  no_of_new_goals,
+                                 w->actions[index].post,
+                                 w->actions[index].no_of_post,
+                                 new_literals, no_of_new_literals);
+
+        if (no_of_new_literals > 0) {
+
+            /* remove the post conditions for the action */
+            no_of_new_goals =
+                strips_remove_conditions_from_state(new_goals,
+                                                    no_of_new_goals,
+                                                    new_literals, no_of_new_literals,
+                                                    w->actions[index].post,
+                                                    w->actions[index].no_of_post);
+
+            /* add the preceding states for the action */
+            no_of_new_goals =
+                strips_add_conditions_to_state(new_goals,
+                                               no_of_new_goals, STRIPS_MAX_GOALS,
+                                               new_literals, no_of_new_literals,
+                                               w->actions[index].pre,
+                                               w->actions[index].no_of_pre);
+
+            if (strips_search_ungrounded_variables(w, new_goals, no_of_new_goals,
+                                                   new_literals, no_of_new_literals,
+                                                   search_complete,
+                                                   steps, max_steps,
+                                                   plan, index)) {
+                free(new_literals);
+                free(new_goals);
+                free(action_matches);
+                return STRIPS_TRUE;
+            }
+
+            /* solve for the next level of goal states */
+            if (strips_solve_for_goals(w, new_goals, no_of_new_goals,
+                                       new_literals, no_of_new_literals,
+                                       search_complete, steps+1, max_steps,
+                                       plan)) {
+
+                strips_show_conditions(stdout, new_goals, no_of_new_goals);
+
+                strips_update_plan(&w->actions[index].declaration, plan,
+                                   new_literals, no_of_new_literals);
+                free(new_literals);
+                free(new_goals);
+                free(action_matches);
+                return STRIPS_TRUE;
+            }
+
+        }
+
+        free(new_literals);
+        free(new_goals);
+
+        action_matches[index] = 0;
+
+    }
+    free(action_matches);
+
+    return STRIPS_FALSE;
+}
+
+/**
+ * @brief Finds a valid plan
+ * @param w World system
+ * @returns True is a successful plan exists
+ */
+int strips_solve(strips_world * w)
+{
+    strips_condition goals[1];
+    int no_of_goals = 1;
+    strips_literal literals[STRIPS_MAX_LITERALS];
+    int no_of_literals = 0;
+    unsigned char search_complete = STRIPS_FALSE;
+    int max_steps = 10;
+
+    w->plan[0] = 0;
+
+    for (int g = 0; g < w->no_of_goals; g++) {
+        search_complete = STRIPS_FALSE;
+
+        memcpy((void*)&goals[0], (void*)&w->goals[g], sizeof(strips_condition));
+
+        if (!strips_solve_for_goals(w, goals, no_of_goals,
+                                   literals, no_of_literals,
+                                   &search_complete,
+                                   0, max_steps,
+                                    w->plan)) {
+            return STRIPS_FALSE;
+        }
+    }
+
+    return STRIPS_TRUE;
+}
+
+/**
+ * @brief Generates a world system from a given file
+ * @param w World system
+ * @param filename The file to read from
+ * @returns The number of predicates from the file which were added
+ */
+int strips_create_world(strips_world * w, char * filename)
+{
+    FILE * fp;
+    int curr_section = 0;
+    char current_action[STRIPS_STRING_BLOCK];
+    char section[STRIPS_STRING_BLOCK];
+    char line[STRIPS_STRING_BLOCK];
+    char predicate_str[STRIPS_MAX_PREDICATES_PER_LINE][STRIPS_STRING_BLOCK];
+    int no_of_predicates, i, predicates_added = 0;
+
+    w->no_of_initial = 0;
+    w->no_of_goals = 0;
+    w->no_of_literals = 0;
+    w->no_of_actions = 0;
+    current_action[0] = 0;
+    section[0] = 0;
+
+    fp = fopen(filename, "r");
+    if (!fp)
+        return -1;
+
+    while (!feof(fp)) {
+        if (fgets(line, STRIPS_STRING_BLOCK-1, fp) != NULL) {
+            if (line != NULL) {
+                curr_section =
+                    strips_extract_file_section(line, section);
+
+                no_of_predicates =
+                    strips_extract_file_predicates(line,
+                                                   predicate_str);
+
+                for (i = 0; i < no_of_predicates; i++) {
+                    if (strips_add_predicate(w, curr_section,
+                                             predicate_str[i],
+                                             current_action) == 0)
+                        predicates_added++;
+                }
+            }
+        }
+    }
+
+    fclose(fp);
+
+    return predicates_added;
+}

+ 136 - 0
src/strips.h

@@ -0,0 +1,136 @@
+/*
+ libstrips - predicate based planner
+ Copyright (C) 2017  Bob Mottram <bob@freedombone.net>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. 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.
+ 3. Neither the name of the University 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 THE HOLDERS 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.
+*/
+
+#ifndef STRIPS_H
+#define STRIPS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+
+#define STRIPS_MAX_ACTIONS             32
+#define STRIPS_MAX_GOALS               32
+#define STRIPS_MAX_STATES              32
+#define STRIPS_MAX_LITERALS            32
+#define STRIPS_MAX_PARAMS              3
+#define STRIPS_STRING                  32
+#define STRIPS_MAX_CONDITIONS          32
+#define STRIPS_MAX_PREDICATES_PER_LINE 128
+#define STRIPS_STRING_BLOCK            256
+#define STRIPS_STRING_PLAN             512
+
+#define STRIPS_TRUE  (1 == 1)
+#define STRIPS_FALSE (1 == 0)
+
+enum strips_file_section {
+    FILE_SECTION_INITIAL=1,
+    FILE_SECTION_GOAL,
+    FILE_SECTION_ACTIONS,
+    FILE_SECTION_ACTION_DECLARATION,
+    FILE_SECTION_ACTION_PRE,
+    FILE_SECTION_ACTION_POST
+};
+
+struct stripsliteral {
+    char variable[STRIPS_STRING];
+    char grounded[STRIPS_STRING];
+};
+typedef struct stripsliteral strips_literal;
+
+struct stripscondition {
+    char predicate[STRIPS_STRING];
+    int no_of_params;
+    char params[STRIPS_MAX_PARAMS][STRIPS_STRING];
+    unsigned char grounded;
+    unsigned char truth;
+};
+typedef struct stripscondition strips_condition;
+
+struct stripsaction {
+    strips_condition declaration;
+    int no_of_pre, no_of_post;
+    strips_condition pre[STRIPS_MAX_CONDITIONS];
+    strips_condition post[STRIPS_MAX_CONDITIONS];
+};
+typedef struct stripsaction strips_action;
+
+struct stripsworld {
+    int no_of_initial, no_of_goals, no_of_literals, no_of_actions;
+    strips_condition initial[STRIPS_MAX_STATES];
+    strips_condition goals[STRIPS_MAX_GOALS];
+    strips_literal known_literals[STRIPS_MAX_LITERALS];
+    strips_action actions[STRIPS_MAX_ACTIONS];
+    char plan[STRIPS_STRING_PLAN];
+};
+typedef struct stripsworld strips_world;
+
+int strips_add_condition(strips_condition conditions[], int length,
+                         strips_condition * new_condition);
+int strips_parse_predicate(char predicate_str[],
+                           strips_condition * result);
+int strips_extract_file_section(char line[], char section[]);
+int strips_extract_file_predicates(char line[],
+                                   char predicate_str[STRIPS_MAX_PREDICATES_PER_LINE][STRIPS_STRING_BLOCK]);
+int strips_create_world(strips_world * w, char * filename);
+int strips_add_conditions_to_state(strips_condition state[],
+                                   int no_of_states, int max_states,
+                                   strips_literal literals[],
+                                   int no_of_literals,
+                                   strips_condition additions[],
+                                   int no_of_additions);
+int strips_remove_conditions_from_state(strips_condition state[],
+                                        int no_of_states,
+                                        strips_literal literals[],
+                                        int no_of_literals,
+                                        strips_condition removes[],
+                                        int no_of_removes);
+int strips_map_variables(strips_condition grounded[], int no_of_grounded,
+                         strips_condition conditions[], int no_of_conditions,
+                         strips_literal literals[], int no_of_literals);
+void strips_update_plan(strips_condition * action, char plan[],
+                        strips_literal literals[], int no_of_literals);
+int strips_solve(strips_world * w);
+void strips_show_world(FILE * fp, strips_world * w);
+char ** strips_get_possible_variable_types(char variable[],
+                                           strips_condition conditions[],
+                                           int no_of_conditions,
+                                           int max_types);
+char ** strips_get_initial_type_values(strips_world * w,
+                                       char type_predicate[],
+                                       int max_values);
+int strips_solve_for_goals(strips_world * w,
+                           strips_condition goals[], int no_of_goals,
+                           strips_literal literals[], int no_of_literals,
+                           unsigned char * search_complete,
+                           int steps, int max_steps,
+                           char plan[]);
+
+#endif

+ 17 - 0
unittests/Makefile

@@ -0,0 +1,17 @@
+APP=tests
+
+.PHONY: check-syntax
+
+all:
+	rm -f src/flycheck*
+	gcc -Wall -std=c99 -pedantic -g -o $(APP) *.c ../src/*.c -I../src -lm -fopenmp
+check-syntax:
+	gcc -Wall -std=c99 -pedantic -fsanitize=address -g -o $(APP) *.c ../src/*.c -I../src -lm -fsyntax-only
+debug:
+	rm -f src/flycheck*
+	gcc -Wall -std=c99 -pedantic -g -o $(APP) *.c ../src/*.c -I../src -lm -fopenmp
+debugstack:
+	rm -f src/flycheck*
+	gcc -Wall -std=c99 -pedantic -fsanitize=address -g -o $(APP) *.c ../src/*.c -I../src -lm -fopenmp
+clean:
+	rm -f ${APP} *.plist src/flycheck*

+ 674 - 0
unittests/maintest.c

@@ -0,0 +1,674 @@
+/*
+ libstrips - predicate based planner
+ Copyright (C) 2017  Bob Mottram <bob@freedombone.net>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. 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.
+ 3. Neither the name of the University 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 THE HOLDERS 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../src/strips.h"
+
+static void run_test_get_initial_type_values()
+{
+    strips_world w;
+    char type_predicate[STRIPS_STRING];
+    char ** possible_values = NULL;
+    int max_values = 8;
+
+    printf("test_get_initial_type_values...");
+
+    sprintf(type_predicate, "%s", "Location");
+
+    strips_condition new_state;
+
+    /*  */
+
+    sprintf(new_state.predicate, "%s", "On");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "A");
+    sprintf(new_state.params[0], "%s", "B");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(w.initial, w.no_of_initial,
+                                &new_state) == 0);
+    w.no_of_initial++;
+
+    sprintf(new_state.predicate, "%s", "Location");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "London");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(w.initial, w.no_of_initial,
+                                &new_state) == 0);
+    w.no_of_initial++;
+
+    sprintf(new_state.predicate, "%s", "Location");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "Berlin");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(w.initial, w.no_of_initial,
+                                &new_state) == 0);
+    w.no_of_initial++;
+
+    sprintf(new_state.predicate, "%s", "Location");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "Paris");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(w.initial, w.no_of_initial,
+                                &new_state) == 0);
+    w.no_of_initial++;
+
+    assert(w.no_of_initial == 4);
+
+    possible_values =
+        strips_get_initial_type_values(&w,
+                                       type_predicate,
+                                       max_values);
+
+    assert(possible_values != NULL);
+
+    int ctr = 0;
+    for (int i = 0; i < max_values; i++) {
+        if (possible_values[i] != NULL) {
+            ctr++;
+        }
+    }
+    assert(ctr == 3);
+    assert(strcmp(possible_values[0], "London") == 0);
+    assert(strcmp(possible_values[1], "Berlin") == 0);
+    assert(strcmp(possible_values[2], "Paris") == 0);
+
+    /* free memory used for values */
+    for (int i = 0; i < max_values; i++) {
+        if (possible_values[i] != NULL)
+            free(possible_values[i]);
+    }
+    free(possible_values);
+
+    printf("Ok\n");
+}
+
+static void run_test_get_possible_variable_types()
+{
+    char variable[STRIPS_STRING];
+    strips_condition conditions[5];
+    int no_of_conditions = 0;
+    char ** possible_types = NULL;
+    int max_types = 8;
+
+    printf("test_get_possible_variable_types...");
+
+    sprintf(variable, "%s", "From");
+
+    strips_condition new_state;
+
+    /* Location(From), Location(TableY), On(A,From), !On(A,TableY) */
+
+    sprintf(new_state.predicate, "%s", "Location");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "From");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    sprintf(new_state.predicate, "%s", "Location");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "TableY");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    sprintf(new_state.predicate, "%s", "On");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "A");
+    sprintf(new_state.params[1], "%s", "From");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    assert(no_of_conditions == 3);
+
+    sprintf(new_state.predicate, "%s", "On");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "A");
+    sprintf(new_state.params[1], "%s", "TableY");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_FALSE;
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    assert(no_of_conditions == 4);
+
+    possible_types =
+        strips_get_possible_variable_types(variable,
+                                           conditions,
+                                           no_of_conditions,
+                                           max_types);
+    assert(possible_types != NULL);
+
+    int ctr = 0;
+    for (int i = 0; i < max_types; i++) {
+        if (possible_types[i] != NULL) {
+            ctr++;
+        }
+    }
+    assert(ctr == 1);
+    assert(strcmp(possible_types[0], "Location") == 0);
+
+    /* free memory used for types */
+    for (int i = 0; i < max_types; i++) {
+        if (possible_types[i] != NULL)
+            free(possible_types[i]);
+    }
+    free(possible_types);
+
+    printf("Ok\n");
+}
+
+
+static void run_tests_ground_params()
+{
+    printf("tests_ground_params...");
+
+    const int max_states = 10;
+    strips_condition grounded[max_states], conditions[max_states];
+    strips_condition new_state;
+    strips_literal literals[STRIPS_MAX_LITERALS];
+    int no_of_literals = 0;
+    int no_of_grounded = 0;
+    int no_of_conditions = 0;
+
+    sprintf(new_state.predicate, "%s", "BlockAt");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "A");
+    sprintf(new_state.params[1], "%s", "Tower2");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(grounded, no_of_grounded,
+                                &new_state) == 0);
+    no_of_grounded++;
+
+    sprintf(new_state.predicate, "%s", "On");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "A");
+    sprintf(new_state.params[1], "%s", "B");
+    new_state.grounded = STRIPS_TRUE;
+    new_state.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(grounded, no_of_grounded,
+                                &new_state) == 0);
+    no_of_grounded++;
+
+    sprintf(new_state.predicate, "%s", "Holding");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "Block1");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_FALSE;
+
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    sprintf(new_state.predicate, "%s", "OnTop");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "Block2");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_FALSE;
+
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    sprintf(new_state.predicate, "%s", "BlockAt");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "Block1");
+    sprintf(new_state.params[1], "%s", "Tower");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    sprintf(new_state.predicate, "%s", "OnTop");
+    new_state.no_of_params = 1;
+    sprintf(new_state.params[0], "%s", "Block1");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    sprintf(new_state.predicate, "%s", "On");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "Block1");
+    sprintf(new_state.params[1], "%s", "Block2");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(conditions, no_of_conditions,
+                                &new_state) == 0);
+    no_of_conditions++;
+
+    no_of_literals = strips_map_variables(grounded, no_of_grounded,
+                                          conditions, no_of_conditions,
+                                          literals, no_of_literals);
+
+    assert(no_of_literals == 3);
+    assert(strcmp(literals[0].variable,"Block1") == 0);
+    assert(strcmp(literals[0].grounded,"A") == 0);
+    assert(strcmp(literals[1].variable,"Tower") == 0);
+    assert(strcmp(literals[1].grounded,"Tower2") == 0);
+    assert(strcmp(literals[2].variable,"Block2") == 0);
+    assert(strcmp(literals[2].grounded,"B") == 0);
+
+    printf("Ok\n");
+}
+
+static void run_tests_add_conditions_to_state()
+{
+    printf("tests_add_conditions_to_state...");
+
+    const int max_states = 10;
+    strips_condition state[max_states], additions[2];
+    int no_of_states = 0, no_of_additions = 0, new_no_of_states;
+    strips_condition new_state, new_state2, new_state3, new_state4;
+    strips_literal literals[3];
+    int no_of_literals = 2;
+
+    sprintf(literals[0].variable, "%s", "Param624");
+    sprintf(literals[0].grounded, "%s", "foo");
+    sprintf(literals[1].variable, "%s", "Param528");
+    sprintf(literals[1].grounded, "%s", "bar");
+
+    sprintf(new_state.predicate, "%s", "Test2");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "Param1");
+    sprintf(new_state.params[1], "%s", "Param2");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+
+    sprintf(new_state2.predicate, "%s", "Test4");
+    new_state2.no_of_params = 3;
+    sprintf(new_state2.params[0], "%s", "Param7");
+    sprintf(new_state2.params[1], "%s", "Param3");
+    sprintf(new_state2.params[2], "%s", "Param12");
+    new_state2.grounded = STRIPS_TRUE;
+    new_state2.truth = STRIPS_FALSE;
+
+    sprintf(new_state3.predicate, "%s", "Test33");
+    new_state3.no_of_params = 1;
+    sprintf(new_state3.params[0], "%s", "Param7");
+    new_state3.grounded = STRIPS_FALSE;
+    new_state3.truth = STRIPS_FALSE;
+
+    sprintf(new_state4.predicate, "%s", "Test87");
+    new_state4.no_of_params = 2;
+    sprintf(new_state4.params[0], "%s", "Param62");
+    sprintf(new_state4.params[1], "%s", "Param91");
+    new_state4.grounded = STRIPS_FALSE;
+    new_state4.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state) == 0);
+    no_of_states++;
+
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state2) == 0);
+    no_of_states++;
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state3) == 0);
+    no_of_states++;
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state4) == 0);
+    no_of_states++;
+
+
+    sprintf(new_state.predicate, "%s", "Test282");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "Param357");
+    sprintf(new_state.params[1], "%s", "Param734");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+
+    sprintf(new_state2.predicate, "%s", "Test418");
+    new_state2.no_of_params = 3;
+    sprintf(new_state2.params[0], "%s", "Param526");
+    sprintf(new_state2.params[1], "%s", "Param624");
+    sprintf(new_state2.params[2], "%s", "Param528");
+    new_state2.grounded = STRIPS_TRUE;
+    new_state2.truth = STRIPS_FALSE;
+
+    assert(strips_add_condition(additions, no_of_additions,
+                                &new_state) == 0);
+    no_of_additions++;
+
+    assert(strips_add_condition(additions, no_of_additions,
+                                &new_state2) == 0);
+    no_of_additions++;
+
+    new_no_of_states =
+        strips_add_conditions_to_state(state, no_of_states,
+                                       max_states,
+                                       literals, no_of_literals,
+                                       additions, no_of_additions);
+    assert(no_of_states == 4);
+    assert(new_no_of_states == 6);
+
+    assert(strcmp(state[5].predicate, "Test418") == 0);
+    assert(state[5].no_of_params == 3);
+    assert(strcmp(state[5].params[0], "Param526") == 0);
+    assert(strcmp(state[5].params[1], "foo") == 0);
+    assert(strcmp(state[5].params[2], "bar") == 0);
+    assert(!state[5].grounded);
+    assert(!state[5].truth);
+
+    printf("Ok\n");
+}
+
+static void run_tests_remove_conditions_from_state()
+{
+    printf("tests_remove_conditions_from_state...");
+
+    const int max_states = 10;
+    strips_condition state[max_states], removals[2];
+    int no_of_states = 0, no_of_removals = 0, new_no_of_states;
+    strips_condition new_state, new_state2, new_state3, new_state4;
+    strips_literal literals[3];
+    int no_of_literals = 2;
+
+    sprintf(literals[0].variable, "%s", "Param2");
+    sprintf(literals[0].grounded, "%s", "foo");
+    sprintf(literals[1].variable, "%s", "Param777");
+    sprintf(literals[1].grounded, "%s", "bar");
+
+    sprintf(new_state.predicate, "%s", "Test2");
+    new_state.no_of_params = 2;
+    sprintf(new_state.params[0], "%s", "Param1");
+    sprintf(new_state.params[1], "%s", "foo");
+    new_state.grounded = STRIPS_FALSE;
+    new_state.truth = STRIPS_TRUE;
+
+    sprintf(new_state2.predicate, "%s", "Test4");
+    new_state2.no_of_params = 3;
+    sprintf(new_state2.params[0], "%s", "Param7");
+    sprintf(new_state2.params[1], "%s", "Param3");
+    sprintf(new_state2.params[2], "%s", "Param12");
+    new_state2.grounded = STRIPS_TRUE;
+    new_state2.truth = STRIPS_FALSE;
+
+    sprintf(new_state3.predicate, "%s", "Test33");
+    new_state3.no_of_params = 1;
+    sprintf(new_state3.params[0], "%s", "bar");
+    new_state3.grounded = STRIPS_FALSE;
+    new_state3.truth = STRIPS_FALSE;
+
+    sprintf(new_state4.predicate, "%s", "Test87");
+    new_state4.no_of_params = 2;
+    sprintf(new_state4.params[0], "%s", "Param62");
+    sprintf(new_state4.params[1], "%s", "Param91");
+    new_state4.grounded = STRIPS_FALSE;
+    new_state4.truth = STRIPS_TRUE;
+
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state) == 0);
+    no_of_states++;
+
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state2) == 0);
+    no_of_states++;
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state3) == 0);
+    no_of_states++;
+    assert(strips_add_condition(state, no_of_states,
+                                &new_state4) == 0);
+    no_of_states++;
+
+
+    sprintf(new_state.params[1], "%s", "Param2");
+    sprintf(new_state3.params[0], "%s", "Param777");
+
+    assert(strips_add_condition(removals, no_of_removals,
+                                &new_state) == 0);
+    no_of_removals++;
+
+    assert(strips_add_condition(removals, no_of_removals,
+                                &new_state3) == 0);
+    no_of_removals++;
+
+    new_no_of_states =
+        strips_remove_conditions_from_state(state, no_of_states,
+                                            literals, no_of_literals,
+                                            removals, no_of_removals);
+    assert(no_of_states == 4);
+    assert(new_no_of_states == 2);
+
+    assert(strcmp(state[0].predicate, "Test4") == 0);
+    assert(state[0].no_of_params == 3);
+    assert(strcmp(state[0].params[0], "Param7") == 0);
+    assert(strcmp(state[0].params[1], "Param3") == 0);
+    assert(strcmp(state[0].params[2], "Param12") == 0);
+    assert(state[0].grounded);
+    assert(!state[0].truth);
+
+    printf("Ok\n");
+}
+
+static void run_tests_blocks()
+{
+    FILE * fp;
+    strips_world w;
+
+    printf("tests_blocks...");
+
+    fp = fopen("/tmp/strips_blocks", "w");
+    assert(fp);
+
+    fprintf(fp, "%s", "Initial state: IsBlock(A), IsBlock(B), Location(TableX), Location(TableY), On(A, TableX), On(B, TableX)\n");
+    fprintf(fp, "%s", "Goal state:    On(A, TableY), On(B, TableY)\n\n");
+
+    fprintf(fp, "%s", "Actions:\n\n");
+
+    fprintf(fp, "%s", "    Move(Block, From, To)\n");
+    fprintf(fp, "%s", "    Preconditions: Location(From), Location(To), On(Block, From), !On(Block, To)\n");
+    fprintf(fp, "%s", "    Postconditions: !On(Block, From), On(Block, To)\n\n");
+
+    fclose(fp);
+
+    int predicates_added = strips_create_world(&w, "/tmp/strips_blocks");
+    system("rm -f /tmp/strips_blocks");
+
+    assert(predicates_added == 15);
+    assert(w.no_of_actions == 1);
+
+    assert(strcmp(w.actions[0].declaration.predicate, "Move") == 0);
+    assert(w.actions[0].declaration.no_of_params == 3);
+    assert(strcmp(w.actions[0].declaration.params[0], "Block") == 0);
+    assert(strcmp(w.actions[0].declaration.params[1], "From") == 0);
+    assert(strcmp(w.actions[0].declaration.params[2], "To") == 0);
+
+    assert(w.actions[0].pre[0].truth);
+    assert(w.actions[0].pre[1].truth);
+    assert(!w.actions[0].post[0].truth);
+    assert(w.actions[0].post[1].truth);
+
+    assert(strips_solve(&w));
+    assert(strlen(w.plan) > 0);
+    assert(strstr(w.plan,"Move(A,TableX,TableY)") != NULL);
+    assert(strstr(w.plan,"Move(B,TableX,TableY)") != NULL);
+
+    printf("Ok\n");
+}
+
+static void run_tests_add_condition()
+{
+    printf("tests_add_condition...");
+
+    strips_condition conditions[3];
+    int length = 0;
+    strips_condition new_condition, new_condition2;
+
+    sprintf(new_condition.predicate, "%s", "Test2");
+    new_condition.no_of_params = 2;
+    sprintf(new_condition.params[0], "%s", "Param1");
+    sprintf(new_condition.params[1], "%s", "Param2");
+    new_condition.grounded = STRIPS_FALSE;
+    new_condition.truth = STRIPS_TRUE;
+
+    sprintf(new_condition2.predicate, "%s", "Test4");
+    new_condition2.no_of_params = 3;
+    sprintf(new_condition2.params[0], "%s", "Param7");
+    sprintf(new_condition2.params[1], "%s", "Param3");
+    sprintf(new_condition2.params[2], "%s", "Param12");
+    new_condition2.grounded = STRIPS_TRUE;
+    new_condition2.truth = STRIPS_FALSE;
+
+    assert(strips_add_condition(conditions, length,
+                                &new_condition) == 0);
+    length++;
+
+    assert(strips_add_condition(conditions, length,
+                                &new_condition2) == 0);
+    length++;
+
+    assert(strcmp(conditions[0].predicate, "Test2") == 0);
+    assert(conditions[0].no_of_params == 2);
+    assert(strcmp(conditions[0].params[0], "Param1") == 0);
+    assert(strcmp(conditions[0].params[1], "Param2") == 0);
+    assert(!conditions[0].grounded);
+    assert(conditions[0].truth);
+
+    assert(strcmp(conditions[1].predicate, "Test4") == 0);
+    assert(conditions[1].no_of_params == 3);
+    assert(strcmp(conditions[1].params[0], "Param7") == 0);
+    assert(strcmp(conditions[1].params[1], "Param3") == 0);
+    assert(strcmp(conditions[1].params[2], "Param12") == 0);
+    assert(conditions[1].grounded);
+    assert(!conditions[1].truth);
+
+    printf("Ok\n");
+}
+
+static void run_tests_parse_predicate()
+{
+    strips_condition result;
+
+    printf("tests_parse_predicate...");
+
+    assert(strips_parse_predicate("BlockAt()", &result) != 0);
+
+    assert(strips_parse_predicate("BlockAt(Block2, Tower)", &result) == 0);
+    assert(result.no_of_params == 2);
+    assert(!result.grounded);
+    assert(result.truth);
+    assert(strcmp(result.predicate, "BlockAt")==0);
+    assert(strcmp(result.params[0], "Block2")==0);
+    assert(strcmp(result.params[1], "Tower")==0);
+
+    assert(strips_parse_predicate("OnTop(Block3)", &result) == 0);
+    assert(result.no_of_params == 1);
+    assert(!result.grounded);
+    assert(result.truth);
+    assert(strcmp(result.predicate, "OnTop")==0);
+    assert(strcmp(result.params[0], "Block3")==0);
+
+    assert(strips_parse_predicate("!OnTop(Block4)", &result) == 0);
+    assert(result.no_of_params == 1);
+    assert(!result.grounded);
+    assert(!result.truth);
+    assert(strcmp(result.predicate, "OnTop")==0);
+    assert(strcmp(result.params[0], "Block4")==0);
+
+    printf("Ok\n");
+}
+
+static void run_tests_extract_sections()
+{
+    char section[STRIPS_STRING_BLOCK];
+
+    printf("tests_extract_sections...");
+
+    assert(strips_extract_file_section("", section) == -1);
+    assert(strips_extract_file_section("    ", section) == -1);
+    assert(strips_extract_file_section("Preconditions: At(Tower), Holding(Block1), BlockAt(Block2, Tower), OnTop(Block2)", section) == FILE_SECTION_ACTION_PRE);
+    assert(strips_extract_file_section("Postconditions: !Holding(Block1), !OnTop(Block2), BlockAt(Block1, Tower), OnTop(Block1), On(Block1, Block2)", section) == FILE_SECTION_ACTION_POST);
+    assert(strips_extract_file_section("Initial state: At(Tower1), BlockAt(A, Tower1), OnBottom(A), OnTop(A), BlockAt(B, Tower2), BlockAt(C, Tower2), On(B, C), OnBottom(C), OnTop(B), Empty(Tower3)", section) == FILE_SECTION_INITIAL);
+    assert(strips_extract_file_section("Goal state: BlockAt(A, Tower2), On(A, B)", section) == FILE_SECTION_GOAL);
+    assert(strips_extract_file_section("PlaceOn(Block1, Block2, Tower)", section) == FILE_SECTION_ACTION_DECLARATION);
+
+    printf("Ok\n");
+}
+
+static void run_tests_extract_predicates()
+{
+    char * line = "Preconditions: At(Tower), Holding(Block1), BlockAt(Block2, Tower), OnTop(Block2)";
+    char predicate_str[STRIPS_MAX_PREDICATES_PER_LINE][STRIPS_STRING_BLOCK];
+    int no_of_predicates;
+
+    printf("tests_extract_predicates...");
+
+    no_of_predicates =
+        strips_extract_file_predicates(line, predicate_str);
+    assert(no_of_predicates == 4);
+
+    assert(strcmp(predicate_str[0], "At(Tower)") == 0);
+    assert(strcmp(predicate_str[1], "Holding(Block1)") == 0);
+    assert(strcmp(predicate_str[2], "BlockAt(Block2,Tower)") == 0);
+    assert(strcmp(predicate_str[3], "OnTop(Block2)") == 0);
+
+    printf("Ok\n");
+}
+
+int main(int argc, char* argv[])
+{
+    run_tests_add_conditions_to_state();
+    run_tests_remove_conditions_from_state();
+    run_tests_add_condition();
+    run_tests_parse_predicate();
+    run_tests_extract_sections();
+    run_tests_extract_predicates();
+    run_tests_ground_params();
+    run_test_get_possible_variable_types();
+    run_test_get_initial_type_values();
+    run_tests_blocks();
+
+    printf("\nAll tests completed\n");
+
+    return 0;
+}