static automap_path *automap_find_path(loc_node *location, loc_node *dest,
				       BOOL by_walking)
{
  automap_path *path = NULL;
  automap_path *rev;
  automap_path newnode;
  loc_node *p;

  /* Find the distances of all nodes from dest */
  n_hash_enumerate(&rooms, make_distant);
  automap_calc_distances(dest, 0, by_walking);

  /* If dest isn't reachable, location's distance will still be infinite */
  if(location->dist == INFINITY)
    return NULL;

  /* At each step, go toward a nearer node 'till we're there */
  p = location;
  while(p != dest) {
    unsigned i;
    unsigned best_dir;
    glui32 best_dist = INFINITY;
    loc_node *best_node = NULL;
    unsigned maxdir = by_walking ? NUM_EXITS : NUM_DIRS;
    for(i = 0; i < maxdir; i++) {
      loc_node *thisdest;
      if(by_walking)
	thisdest = p->exits[i];
      else
	thisdest = automap_edge_follow(p, i);
      
      if(thisdest && thisdest->dist < best_dist) {
	best_dir = i;
	best_dist = thisdest->dist;
	best_node = thisdest;
      }
    }
    if(!best_node) {
      n_show_error(E_SYSTEM, "couldn't find path there", 0);
      return NULL;
    }
    newnode.loc = p;
    newnode.dir = best_dir;
    LEadd(path, newnode);
    p = best_node;
  }

  rev = NULL;
  while(path) {
    LEadd(rev, *path);
    LEremove(path);
  }

  return rev;
}
static void automap_find_cycles(loc_node *location, automap_path *curpath)
{
  unsigned i;
  location->touched = TRUE;
  for(i = 0; i < NUM_DIRS; i++) {
    loc_node *thisdest = automap_edge_follow(location, i);
    if(thisdest && thisdest->found) {
      automap_path newnode;
      newnode.dir = i;
      newnode.loc = location;
      LEadd(curpath, newnode);

      if(thisdest->touched) {           /* Found a cycle! */
	int cyclelength = 0;
	automap_path *p;
	cycleequation *cycle = NULL;
	cycleequation newcycle;
	for(p = curpath; p; p=p->next) {
	  int dir = p->dir;
	  newcycle.var = &(p->loc->outgoing[dir]->guess_length);
	  newcycle.min = &(p->loc->outgoing[dir]->min_length);
	  newcycle.xcoefficient = dirways[dir].deltax;
	  newcycle.ycoefficient = dirways[dir].deltay;
	  LEadd(cycle, newcycle);
	  
	  cyclelength++;
	  if(p->loc == thisdest) {      /* Found the relevant endpoint */
	    if(cyclelength <= 2)     /* Ignore two nodes going to each other */
	      LEdestroy(cycle);
	    else
	      automap_add_cycle(cycle); /* automap_add_cycle gets ownership */
	    break;
	  }
	}
	if(!p) {                        /* The cycle had already been found */
	  LEdestroy(cycle);
	}
      } else {
	automap_find_cycles(thisdest, curpath);
      }
      LEremove(curpath);
    }
  }
}
static void automap_remember_interference(loc_node *a, loc_node *b)
{
  /*  interlist *p;
  LEsearch(interferences, p, (p->a==a && p->b==b) || (p->a==b && p->b==a));
  if(!p) {*/
    interlist newnode;
    newnode.a = a;
    newnode.b = b;
    LEadd(interferences, newnode);
    /*  }*/
}
static edge *automap_new_edge(loc_node *src, loc_node *dest, BOOL is_oneway)
{
  edgelist newedge;
  newedge.node = n_malloc(sizeof(edge));
  newedge.node->dest[0] = src;
  newedge.node->dest[1] = dest;
  newedge.node->is_oneway = is_oneway;
  newedge.node->touched = FALSE;
  newedge.node->min_length = is_oneway ? 4 : 2;
  newedge.node->guess_length = is_oneway ? 4 : 2;  
  LEadd(all_edges, newedge);
  return newedge.node;
}
Exemple #5
0
static zword smart_tokeniser(zword dictionarytable,
			     const char *text, unsigned length, BOOL is_begin)
{
  zword word_num = 0;
  unsigned tlength = (length < 12) ? length : 12;
  char tbuffer[13];

  /* Letter replacements are tried in this order - */
  const char fixmeletters[] = "abcdefghijklmnopqrstuvwxyz";
  /* char fixmeletters[] = "etaonrishdlfcmugpywbvkxjqz"; */

  
  word_num = find_word(dictionarytable, text, length);  

  /* Some game files don't contain abbreviations for common commands */
  if(!word_num && do_expand && length == 1 && is_begin) {
    const char * const abbrevs[26] = {
      "a",              "b",           "close",          "down",
      "east",           "f",           "again",          "h",
      "inventory",      "j",           "attack",         "look",
      "m",              "north",       "oops",           "open",
      "quit",           "drop",        "south",          "take",
      "up",             "v",           "west",           "examine",
      "yes",            "wait"
    };
    if('a' <= text[0] && text[0] <= 'z') {
      strcpy(tbuffer, abbrevs[text[0] - 'a']);
      tlength = strlen(tbuffer);
      word_num = find_word(dictionarytable, tbuffer, tlength);
    }
  }

  /* Check for various typing errors */

  /* Don't attempt typo correction in very short words */
  if(do_spell_correct && length >= 3) {

    if(!word_num) {  /* Check for transposes */
      /* To fix, try all possible transposes */
      unsigned position;
      for(position = 1; position < tlength; position++) {
	unsigned s;
	for(s = 0; s < tlength; s++)
	  tbuffer[s] = text[s];

	tbuffer[position - 1] = text[position];
	tbuffer[position]     = text[position - 1];

	word_num = find_word(dictionarytable, tbuffer, tlength);
	if(word_num)
	  break;
      }
    }

    if(!word_num) {  /* Check for deletions */
      /* To fix, try all possible insertions */
      unsigned position;
      for(position = 0; position <= tlength; position++) {
	unsigned s;
	for(s = 0; s < position; s++)    /* letters before the insertion */
	  tbuffer[s] = text[s];

	for(s = position; s < tlength; s++)       /* after the insertion */
	  tbuffer[s + 1] = text[s];

	/* try each letter */
	for(s = 0; s < sizeof(fixmeletters); s++) {
	  tbuffer[position] = fixmeletters[s];
	  word_num = find_word(dictionarytable, tbuffer, tlength + 1);
	  if(word_num)
	    break;
	}

	if(word_num) {
	  tlength++;
	  break;
	}
      }
    }

    if(!word_num) {  /* Check for insertions */
      /* To fix, try all possible deletions */
      unsigned position;
      for(position = 0; position < tlength; position++) {
	unsigned s;
	for(s = 0; s < position; s++)    /* letters before the deletion */
	  tbuffer[s] = text[s];

	for(s = position + 1; s < tlength; s++)   /* after the deletion */
	  tbuffer[s - 1] = text[s];

	word_num = find_word(dictionarytable, tbuffer, tlength - 1);

	if(word_num) {
	  tlength--;
	  break;
	}
      }
    }

    if(!word_num) {  /* Check for substitutions */
      /* To fix, try all possible substitutions */
      unsigned position;
      for(position = 0; position < tlength; position++) {
      unsigned s;
      for(s = 0; s < tlength; s++)
	tbuffer[s] = text[s];

      /* try each letter */
      for(s = 0; s < sizeof(fixmeletters); s++) {
	tbuffer[position] = fixmeletters[s];
	word_num = find_word(dictionarytable, tbuffer, tlength);
	if(word_num)
	  break;
      }

      if(word_num)
	break;
      }
    }
  }

  /* Report any corrections made */
  if(word_num) {
    struct Typocorrection *p;
    char original[13], changedto[13];
    n_strncpy(original, text, 13);
    n_strncpy(changedto, tbuffer, 13);
    if(length < 13)
      original[length] = 0;
    if(tlength < 13)
      changedto[tlength] = 0;

    LEsearch(recent_corrections, p, ((n_strncmp(p->original, original, 13) == 0) &&
				     (n_strncmp(p->changedto, changedto, 13) == 0)));

    /* Only print a correction if it hasn't yet been reported this turn */
    if(!p) {
      struct Typocorrection newcorrection;
      n_strncpy(newcorrection.original, original, 13);
      n_strncpy(newcorrection.changedto, changedto, 13);
      LEadd(recent_corrections, newcorrection);

      set_glk_stream_current();

      if(allow_output) {
	glk_put_char('[');
	w_glk_put_buffer(text, length);
	w_glk_put_string(" -> ");
	w_glk_put_buffer(tbuffer, tlength);
	glk_put_char(']');
	glk_put_char(10);
      }
    }
  }

  return word_num;
}
Exemple #6
0
BOOL saveundo(BOOL in_instruction)
{
  move_difference newdiff;
  strid_t stack;
  stream_result_t poo;

  if(!allow_saveundo)
    return TRUE;

  /* In games which provide @save_undo, we will have already issued a faked
     saveundo before the first @save_undo hits, since there hadn't been any
     @save_undo before the first read line.  So when this happens, wipe the
     fake saveundo in favor of the real one */
  if(in_instruction && movelist && !movelist->next
     && !movelist->PC_in_instruction)
    init_undo();

    
  if(!quetzal_diff(z_memory, prevstate, dynamic_size, &newdiff.delta,
		   &newdiff.deltalength, TRUE))
    return FALSE;

#ifdef PARANOID
  {
    char *newmem = (char *) n_malloc(dynamic_size);
    n_memcpy(newmem, prevstate, dynamic_size);
    quetzal_undiff(newmem, dynamic_size, newdiff.delta,
		   newdiff.deltalength, TRUE);
    if(n_memcmp(z_memory, newmem, dynamic_size)) {
      n_show_error(E_SAVE, "save doesn't match itself", 0);
    }
    n_free(newmem);
  }
#endif
  
  newdiff.PC = PC;
  newdiff.oldPC = oldPC;
  
  newdiff.PC_in_instruction = in_instruction;
  newdiff.stacklength = get_quetzal_stack_size();
  newdiff.stackchunk = (zbyte *) n_malloc(newdiff.stacklength);
  stack = glk_stream_open_memory((char *) newdiff.stackchunk,
				 newdiff.stacklength, filemode_Write, 0);
  if(!stack) {
    n_free(newdiff.delta);
    n_free(newdiff.stackchunk);
    return FALSE;
  }
  if(!quetzal_stack_save(stack)) {
    glk_stream_close(stack, NULL);
    n_free(newdiff.delta);
    n_free(newdiff.stackchunk);
    return FALSE;
  }
  glk_stream_close(stack, &poo);
  if(poo.writecount != newdiff.stacklength) {
    n_show_error(E_SAVE, "incorrect stack size assessment", poo.writecount);
    n_free(newdiff.delta);
    n_free(newdiff.stackchunk);
    return FALSE;
  }

  while(move_index-- > 0) {
    n_free(movelist->delta);
    n_free(movelist->stackchunk);
    LEremove(movelist);
  }
  LEadd(movelist, newdiff);
  move_index++;
  n_memcpy(prevstate, z_memory, dynamic_size);

  has_done_save_undo = TRUE;
  return TRUE;
}