[plt-scheme] Help with extending mzscheme.

From: dragal V2.0.3 (dragal23 at gmail.com)
Date: Fri Sep 14 14:42:37 EDT 2007


I have been working on a roguelike game in scheme. Due to being unable to
find an implementation of scheme with support for ncurses, and after a
somewhat disappointing (but informative) attempt using chicken scheme, I
eventually decided that extending mzscheme was the way forward.

The extension has gone fairly well and provides most of the functionality I
desire (including much of the number crunching for line of sight). However
the following problems are unresolved.

I am using mzscheme v370, and emacs.

1. the scheme_malloc_* family of functions segfault if the requested memory
is unavailable.

2. Is it possible to register a function which is called when a object is
garbage collected?

3. I have found it desirable to create scheme objects which act as a wrapper
for the actual game data. It is undesirable to have to use (map-width *
map-height * sizeof(Scheme_Object)) bytes when only a few map elements are
accessed at any one time. Secondly when handling map elements it is often
desirable to know its coordinates, which can be stored in the wrapper.
This would be simple, except that i would prefer for there to never be two
objects which are a wrapper for the same map element. Not only is this
unintuitive, but it prevents the possibility of testing for equality using
the  eqv?.
The best idea I have had is to use a hash map to keep a record of currently
available wrapper objects and return the appropriate wrapper. However,
question 2 would have to be possible in order to keep the table updated.
Also there is the issue of how long to keep unreferenced wrappers around (a
round robbin system similar to that used in the caching of some operating
systems could be profitable).

As the source is around 2000 lines, I will not post it all here. However the
functions involving memory allocation follow. Please note that I have not
yet started altering the code to use a wrapper for the scheme type

/* A structure representing indevidual tiles (map elements) of a dungeon.
   Notice the data field. This allows game specific data to be stored on the
   while keeping all the engine relevent data visible to the engine.*/
typedef struct {
  Scheme_Object so ;
  unsigned char seen : 1 ;              /* has this map element ever been
seen? */
  unsigned char visible : 1 ;           /* can this map element be seen
right now? */
  unsigned char opaque_to_visible : 1 ; /* is this map element opaque to
normal light? */
  unsigned char opaque_to_uv : 1 ;      /* is this map element opaque to uv
light? */
  unsigned char opaque_to_ir : 1 ;      /* is this map element opaque to ir
light? */
  unsigned char solid : 1 ;
  unsigned char changed : 1 ;           /* Not really shure about the
advisibility of this, however it avoids
                       repeatedly inserting the same coordinates into the
changed list. */
  unsigned char residual_heat ;
  unsigned char lit_visible ;           /* is this map element lit by normal
  unsigned char lit_uv ;                /* is this map element lit by uv
light? */
  char print_char ;
  char display_print_char ;
  Scheme_Object *data ;
}  Map_element ;

/* The structure representing the actual dungeon. */
typedef struct {
  Scheme_Object so ;
  unsigned int w ;
  unsigned int h ;
  unsigned int l ;
  unsigned char ambient_visible_light ;
  unsigned char ambient_uv_light ;
  unsigned char ambient_heat ;
  Map_element *map;
  struct changed *changed_list ;
} Dungeon ;

Scheme_Object *make_dungeon(int argc, Scheme_Object **argv) {
  unsigned long w, h, l, i ;
  Map_element *map ;
  Dungeon *dn ;

  if (!SCHEME_INTP(argv[0]) || negative(argv[0]))
    scheme_wrong_type("make-dungeon", "positive integer", 0, argc, argv);
  if (!SCHEME_INTP(argv[1]) || (negative(argv[1])))
    scheme_wrong_type("make-dungeon", "positive integer", 1, argc, argv);

  w = SCHEME_INT_VAL(argv[0]);
  h = SCHEME_INT_VAL(argv[1]);
  l = w * h ;

  /* Malloc the dungeon */
  dn = (Dungeon *)scheme_malloc_tagged(sizeof(Dungeon)) ;
  dn->so.type = dungeon_type;

  /*map = (Map_element *)scheme_malloc_fail_ok(scheme_malloc,
sizeof(Map_element) * l);*/
  map = (Map_element *)scheme_malloc_tagged(sizeof(Map_element) * l) ;
  if (!map) {
    scheme_raise_exn(MZEXN_FAIL, "make-dungeon: out of memory") ;

  dn->w            = w ;
  dn->h            = h ;
  dn->l            = l ;
  dn->map          = map ;
  dn->changed_list = NULL ;

  /* Init dungeon to safe vals : */
  for (i = 0 ; i < l ; i++) {
    dn->map[i].so.type = map_element_type ;
    dn->map[i].seen = 0 ;
    dn->map[i].visible = 0 ;
    dn->map[i].changed = 0 ;
    dn->map[i].residual_heat = 0 ;
    dn->map[i].lit_visible = 0 ;
    dn->map[i].lit_uv = 0 ;
    dn->map[i].opaque_to_visible = 0 ;
    dn->map[i].opaque_to_uv = 0 ;
    dn->map[i].opaque_to_ir = 0 ;
    dn->map[i].print_char = ' ' ;
    dn->map[i].display_print_char = ' ' ;
    dn->map[i].data = scheme_false ;

  return (Scheme_Object *)dn ;


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20070914/6e736ac9/attachment.html>

Posted on the users mailing list.