#include "Python.h" #include <stdio.h> #undef NDEBUG #include <assert.h> #define BoardObject_Check(v) ((v)->ob_type == &PyBoard_Type) #define VALID_PAIR(m, x, y) (x > 0 && y > 0 && x <= m->width && y <= m->height) #define E_NEIGH 0x0001 #define W_NEIGH 0x0002 #define N_NEIGH 0x0004 #define S_NEIGH 0x0008 #define WARN_H2O 0x0010 #define DANGER_H2O 0x0020 #define GOOD_T 0x0040 #define BAD_T 0x0080 #define PLAYER_MASK 0xFF00 #define XPLAYER_MASK 0x00FF #define ONE_IF_SET(bits, mask) ((bits & mask) ? 1 : 0) staticforward PyTypeObject PyBoard_Type; typedef struct { PyObject_HEAD int width; int height; PyObject *wall; PyObject *plain; unsigned short **map; // Y Major, x = 3, y = 1 self->map[1][3] } BoardObject; static void Board_dealloc(BoardObject *self) { int i; for (i = 0; i < self->height; i++) { free(self->map[i]); self->map[i] = NULL; } free(self->map); self->map = NULL; self->wall = NULL; self->plain = NULL; PyObject_Del(self); return; } static PyObject * Board_set_row(BoardObject *self, PyObject *args) { PyObject *list; int row = 0; int list_len = 0; int i; long val; if (!PyArg_ParseTuple(args, "iO!:icfgBoard", &row, &PyList_Type, &list)) { return NULL; } list_len = PyList_GET_SIZE(list); assert(row < self->height - 1 && row > 0); assert(list_len < self->width - 1&& list_len > 0); for (i = 1; i < list_len + 1; i++) { val = PyInt_AsLong(PyList_GET_ITEM(list, i-1)); // 1 == plain, 2 === wall, 3 == home, 4 == water if (val == 1 || val == 3) { self->map[row][i] = GOOD_T; // good terrain } else if (val == 2) { self->map[row][i] = BAD_T; // bad terrain } else if (val == 4) { self->map[row][i] = BAD_T | PLAYER_MASK; // cleared later } else { assert(0 && "Bad value"); } } Py_INCREF((PyObject *)self); return (PyObject *)self; // return ourself as an lvalue } void print_board(BoardObject *self) { int i,j; printf("W %d H %d\n", self->width - 2, self->height -2); for(i = self->height - 2; i > 0; i--) { for (j = 1; j < self->width - 1; j++) { if (self->map[i][j] & GOOD_T) printf("."); else printf("#"); } printf("\n"); } return; } static int validate_args(BoardObject *self, PyObject *args, int *w, int *h) { PyObject *tup; if (!PyArg_ParseTuple(args, "O:icfgBoard", &tup)) { if (!PyTuple_Check(tup) && !PyList_Check(tup)) return 0; } if (PySequence_Fast_GET_SIZE(tup) != 2) { return 0; } *w = (int) PyLong_AsLong(PySequence_Fast_GET_ITEM(tup, 0)); *h = (int) PyLong_AsLong(PySequence_Fast_GET_ITEM(tup, 1)); if (*w < 0 || *h < 0 || *w >= (self->width) || *h >= (self->height)) { PyErr_SetString(PyExc_IndexError, "Width or Height is out of range"); return 0; } return 1; //success } static PyObject * Board_peek(BoardObject *self, PyObject *args) { int w, h; PyObject *ret; if (!validate_args(self, args, &w, &h)) { return NULL; } if (self->map[h][w] & GOOD_T) ret = self->plain; else ret = self->wall; Py_INCREF(ret); return ret; } static PyObject * Board_finalize(BoardObject *self, PyObject *args) { int i, j; unsigned short **map; // alias to save some typing map = self->map; for (i = 0; i < self->height; i++) { for (j = 0; j < self->width; j++) { // locate valid neighbors if (i > 0) { // look south if (map[i-1][j] & GOOD_T) map[i][j] |= S_NEIGH; if (map[i-1][j] & PLAYER_MASK) map[i][j] |= DANGER_H2O; } if (i < self->height - 1) { // look north if (map[i+1][j] & GOOD_T) map[i][j] |= N_NEIGH; if (map[i+1][j] & PLAYER_MASK) map[i][j] |= DANGER_H2O; } if (j > 0) { // look west if (map[i][j-1] & GOOD_T) map[i][j] |= W_NEIGH; if (map[i][j-1] & PLAYER_MASK) map[i][j] |= DANGER_H2O; } if (j < self->width - 1) { // look east if (map[i][j+1] & GOOD_T) map[i][j] |= E_NEIGH; if (map[i][j+1] & PLAYER_MASK) map[i][j] |= DANGER_H2O; } } } // mark everything next to DANGER_H2O as WARN_H2O // clear the player mask while we are at it for (i = 0; i < self->height; i++) { for (j = 0; j < self->width; j++) { map[i][j] &= XPLAYER_MASK; // clear some bits if (i > 0) { // look south if (map[i-1][j] & DANGER_H2O) map[i][j] |= WARN_H2O; } if (i < self->height - 1) { // look north if (map[i+1][j] & DANGER_H2O) map[i][j] |= WARN_H2O; } if (j > 0) { // look west if (map[i][j-1] & DANGER_H2O) map[i][j] |= WARN_H2O; } if (j < self->width - 1) { // look east if (map[i][j+1] & DANGER_H2O) map[i][j] |= WARN_H2O; } } } Py_INCREF(self); return (PyObject *)self; } static PyObject * Board_neighbors(BoardObject *self, PyObject *args) { PyObject *ret; PyObject *tmp; int w, h; unsigned short bits; int tuple_len = 0; int i = 0; if (!validate_args(self, args, &w, &h)) { return NULL; } bits = self->map[h][w]; tuple_len = ONE_IF_SET(bits, N_NEIGH) + ONE_IF_SET(bits, S_NEIGH) + ONE_IF_SET(bits, E_NEIGH) + ONE_IF_SET(bits, W_NEIGH); // tuple len is in the range 0..4 ret = (PyObject *)PyTuple_New(tuple_len); if (bits & N_NEIGH) { tmp = (PyObject *)PyTuple_New(2); PyTuple_SET_ITEM(tmp, 0, PyInt_FromLong((long)w)); PyTuple_SET_ITEM(tmp, 1, PyInt_FromLong((long)h+1)); PyTuple_SET_ITEM(ret, i++, tmp); } if (bits & S_NEIGH) { tmp = (PyObject *)PyTuple_New(2); PyTuple_SET_ITEM(tmp, 0, PyInt_FromLong((long)w)); PyTuple_SET_ITEM(tmp, 1, PyInt_FromLong((long)h-1)); PyTuple_SET_ITEM(ret, i++, tmp); } if (bits & W_NEIGH) { tmp = (PyObject *)PyTuple_New(2); PyTuple_SET_ITEM(tmp, 0, PyInt_FromLong((long)w-1)); PyTuple_SET_ITEM(tmp, 1, PyInt_FromLong((long)h)); PyTuple_SET_ITEM(ret, i++, tmp); } if (bits & E_NEIGH) { tmp = (PyObject *)PyTuple_New(2); PyTuple_SET_ITEM(tmp, 0, PyInt_FromLong((long)w+1)); PyTuple_SET_ITEM(tmp, 1, PyInt_FromLong((long)h)); PyTuple_SET_ITEM(ret, i++, tmp); } return ret; } static PyObject * Board_print(BoardObject *self, PyObject *args) { print_board(self); Py_INCREF(self); return (PyObject *)self; } static PyObject * Board_get_danger(BoardObject *self, PyObject *args) { int w, h; int danger; unsigned short foo; if (!validate_args(self, args, &w, &h)) { return NULL; } foo = self->map[h][w]; danger = (int)((foo & PLAYER_MASK) >> 8) + (int)((foo & (DANGER_H2O | WARN_H2O)) >> 3); return PyLong_FromLong(danger); } static PyObject * Board_mv_player(BoardObject *self, PyObject *args) { print_board(self); Py_INCREF(self); return (PyObject *)self; } static PyObject * Board_rm_player(BoardObject *self, PyObject *args) { int w, h; unsigned short bits; if (!validate_args(self, args, &w, &h)) { return NULL; } bits = self->map[h][w]; if (bits & N_NEIGH) { self->map[h+1][w] &= XPLAYER_MASK; } if (bits & S_NEIGH) { self->map[h+1][w] &= XPLAYER_MASK; } if (bits & W_NEIGH) { self->map[h+1][w] &= XPLAYER_MASK; } if (bits & E_NEIGH) { self->map[h+1][w] &= XPLAYER_MASK; } Py_INCREF(self); return (PyObject *)self; } static PyObject * Board_add_player(BoardObject *self, PyObject *args) { int w, h; unsigned short bits; if (!validate_args(self, args, &w, &h)) { return NULL; } bits = self->map[h][w]; self->map[h][w] |= PLAYER_MASK & 0x0F00; if (bits & N_NEIGH) { self->map[h+1][w] |= PLAYER_MASK & 0x0800; } if (bits & S_NEIGH) { self->map[h+1][w] |= PLAYER_MASK & 0x0800; } if (bits & W_NEIGH) { self->map[h+1][w] |= PLAYER_MASK & 0x0800; } if (bits & E_NEIGH) { self->map[h+1][w] |= PLAYER_MASK & 0x0800; } Py_INCREF(self); return (PyObject *)self; } static PyMethodDef Board_methods[] = { {"peek", (PyCFunction)Board_peek, METH_VARARGS}, {"neighbors", (PyCFunction)Board_neighbors, METH_VARARGS}, {"set_row", (PyCFunction)Board_set_row, METH_VARARGS}, {"finalize", (PyCFunction)Board_finalize, METH_NOARGS}, {"print_board", (PyCFunction)Board_print, METH_NOARGS}, {"add_player", (PyCFunction)Board_add_player, METH_VARARGS}, {"rm_player", (PyCFunction)Board_rm_player, METH_VARARGS}, {"move_player", (PyCFunction)Board_mv_player, METH_VARARGS}, {"get_danger", (PyCFunction)Board_get_danger, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; static PyObject * Board_getattr(BoardObject *self, char *name) { return Py_FindMethod(Board_methods, (PyObject *)self, name); } statichere PyTypeObject PyBoard_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "icfpBoard", /*tp_name*/ sizeof(BoardObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)Board_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc)Board_getattr, /*tp_getattr*/ 0, //(setattrfunc)Permute_setattr, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ Board_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; static BoardObject * newBoardObject(int width, int height) { BoardObject *self; const char *myplain = "."; int i, j; self = PyObject_New(BoardObject, &PyBoard_Type); if (self == NULL) return NULL; self->wall = NULL; self->plain = NULL; self->map = NULL; // create two PyStrngs, one for '#' and one for '.' self->wall = PyString_FromString("#"); if (self->wall == NULL) return NULL; self->plain = PyString_FromString(myplain); if (self->plain == NULL) return NULL; self->width = width + 2; self->height = height + 2; self->map = (unsigned short **) malloc(sizeof(unsigned short *) * (self->height)); if (self->map == NULL) { return NULL; } for (i = 0; i < self->height; i++) { self->map[i] = (unsigned short *) malloc(sizeof(unsigned short) * self->width); if (self->map[i] == NULL) { fprintf(stderr, "The pooch is screeeewed\n"); return NULL; } } for (i = 0; i < self->height; i++) { for (j = 0; j < self->width; j++) { self->map[i][j] = BAD_T | PLAYER_MASK; } } return self; } /* not static so stats_module.c can see it */ PyObject * icfp_board(PyObject *self, PyObject *args) { BoardObject *rv; int width = 0; int height = 0; if (!PyArg_ParseTuple(args, "ii", &width, &height)) return NULL; assert(width > 0 && height > 0 && width < 1100 && height < 1100); // call object create function and return rv = newBoardObject(width, height); if ( rv == NULL ) { return NULL; } return (PyObject *)rv; }