Logo Search packages:      
Sourcecode: kdrill version File versions  Download package

badguess.c

/*
 * This file keeps track of the user's bad guesses.
 *
 * Why is this in a separate file? 'cause I'm going to attempt to make
 * a clean OO API for this functionality.
 *
 * The PURPOSE of this API, is to attempt to make "try this again"
 * repeating, be more appropriately distributed, favouring much-missed ones.
 *
 *
 * The nasty part of this code is that currently it implements
 * a "priority queue", with a static array.
 * Maybe I should have made this a linked list. ug.
 *
 * Since this is finicky, I put in a -DDEBUG main() routine
 */

#include <stdio.h>

#define BADCACHESIZE 100
#include "defs.h"

/* Here's the queue */
static TRANSLATION badcache[BADCACHESIZE];
static int maxbad=0;


/* delete item at position 'delpos'.
 * move items from start+1, to end-1, to cover up
 * You'll probably want to call with
 *  deletepos(position, maxbad)
 *
 * We do NOT adjust maxbad. Caller has to do that.
 */
static void deletepos(int delpos, int end){
      int ndx;
      for(ndx=delpos; ndx<end;ndx++){
            badcache[ndx]=badcache[ndx+1];
      }
}

static void insert(int, int, TRANSLATION);


/* This doesn't actually resort the entire array.
 * Just the item at the given start index
 *
 * The TRANSLATIONstruct referenced at the startpoint, could have
 * EITHER increased or decreased its count
 * And in theory, it might not move. 
 */
static void resort(int start)
{
      int newpos;
      TRANSLATION moveme=badcache[start];

      if(maxbad<2)
            return;

      /* increase?*/
      if(start>0){
            newpos=start-1;
            while(newpos>=0){
                  if(badcache[newpos]->incorrect < moveme->incorrect){
                        newpos-=1;
                  } else break;
            }
            if(newpos < start-1){
                  insert(newpos+1, start, badcache[start]);
                  maxbad--;
                  return;
            }
      }
      /* no? check for decrease */

      newpos=start+1;
      while(newpos<maxbad){
            if(badcache[newpos]->incorrect >= moveme->incorrect){
                  newpos++;
            } else break;
      }
      if(newpos>start+1){
            deletepos(start, newpos);
            newpos-=1;
            badcache[newpos]=moveme;
      }
}

/* Subroutines are up here. Global routines are further down below */

/* pass in a TRANSLATIONS ptr, and a range of 
 * the cache we should play with.
 * For pure insert, internal functions should use
 *   insert(0, maxbad, whatever)
 * Except you should probably just want to use insertupdate() instead
 *
 * We allow the other syntax, for use with resort().
 *
 * We dont have to optimize this right now, cause the
 * cache is relatively tiny.
 *
 * We assume that there is one "empty" space at
 *  badcache[endndx]
 *
 * If tnum already exists, we will update existing slot, reguardless
 * of startndx and endndx
 *
 * We update maxbad here!!
 *
 */
static void insert(int startndx, int endndx, TRANSLATION trans)
{
      /* find place it SHOULD go, between startndx and endndx*/
      int idx,shuffleidx;

      if(endndx>=BADCACHESIZE){
            /* cache full */
            return;
      }
      idx=startndx;

      while(idx<endndx){
            if((badcache[idx]->incorrect) < (trans->incorrect)){
                  break;
            }
            idx++;
      }

      /* Now make a "space" in middle of array, if needed */
      if(idx<endndx){
            shuffleidx=endndx;
      } else {
            shuffleidx=idx;
      }
      while(shuffleidx>idx){
            badcache[shuffleidx]=badcache[shuffleidx-1];
            shuffleidx--;
      }
      badcache[idx]=trans;

      maxbad++;
}

/* insert at right place, or update existing one and resort*/
static void insertupdate(TRANSLATION trans)
{
      int idx;

      /* first search for pre-exist, in ENTIRE CACHE*/
      for(idx=0;idx<maxbad;idx++){
            if(badcache[idx]==trans){
                  resort(idx);
                  return;
            }
      }
      insert(0,maxbad,trans);
}


/************************************************************/

/* return -1 if not in cache */
static int findindex(TRANSLATION trans){
      int idx=0;
      while(idx<maxbad){
            if(badcache[idx]==trans)
                  return idx;
            idx++;
      }
      return -1;
}

static void deletebad(TRANSLATION trans){
      int pos=findindex(trans);
      if(pos==-1){
            return;
      }
      deletepos(pos,maxbad);
      maxbad--;
}

#ifdef DEBUG
/* debug */
static void print(){
      int idx;
      puts("Dumping badcache");
      for(idx=0;idx<maxbad;idx++){
            printf("Translation #%d, badcount=%d\n",(int)badcache[idx],
                   badcache[idx]->incorrect);
      }
}
#endif

/**********************************************************************/
 /*  Here are the globally visible thingies    */
 /**********************************************/

/* If you like an explicit "remove" call, here it is. But normally,
 * this is not used directly by outsiders
 */
void RemoveBadCache(TRANSLATION trans){
      deletebad(trans);
}

/* This tells us to insert or update or REMOVE a translation, from
 * our cache of missed translations. We assume the caller has
 * just changed the trans->incorrect value
 *
 */
void AdjustBadCache(TRANSLATION trans){
            if(trans->incorrect==0){
                  RemoveBadCache(trans);
                  return;
            }
            insertupdate(trans);
}

/* basically, just returns first missed one, or a random one */
TRANSLATION GetRepeat(){
      if(maxbad==0){
            return NULL;
      }
      return badcache[0];
}


#ifdef DEBUGMAIN
TRANSLATION translations[6];
main(){
      int tc;

      for(tc=0;tc<6;tc++){
            translations[tc]=(TRANSLATION)malloc(sizeof (struct translationstruct));
      }
      translations[0]->incorrect=0;
      translations[1]->incorrect=1;
      translations[2]->incorrect=2;
      translations[3]->incorrect=3;
      translations[4]->incorrect=4;
      translations[5]->incorrect=5;
      
      AdjustBadCache(translations[3]);
      print();
      AdjustBadCache(translations[5]);
      print();
      AdjustBadCache(translations[2]);
      print();
      AdjustBadCache(translations[3]);
      print();
      AdjustBadCache(translations[4]);
      print();
      AdjustBadCache(translations[1]);
      print();

      printf("updating tnum5, %d\n", translations[5]);
      translations[5]->incorrect-=2;
      AdjustBadCache(translations[5]);
      print();

      printf("updating tnum3, %d\n", translations[5]);
      translations[5]->incorrect+=2;
      AdjustBadCache(translations[5]);
      print();

      printf("deleting tnum2, %d\n", translations[2]);
      RemoveBadCache(translations[2]);
      print();
      
}

#endif /* DEBUG */


Generated by  Doxygen 1.6.0   Back to index