|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T l
Length: 8260 (0x2044) Types: TextFile Names: »ltm.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Rog-O-Matic/ltm.c«
/* * ltm.c: Rog-O-Matic XIV (CMU) Fri Dec 28 20:37:04 1984 - mlm * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin * * This file contains functions for maintaining a database or "long * term memory" */ # include <curses.h> # include <math.h> # include "types.h" # include "globals.h" # include "install.h" static int nosave = 0; /* True ==> dont write ltm back out */ static char ltmnam[100]; /* Long term memory file name */ /* * mapcharacter: Read a character help message */ mapcharacter (ch, str) char ch, *str; { dwait (D_CONTROL, "mapcharacter called: '%c' ==> '%s'", ch, str); /* Ancient versions of Rogue had no wands or staves */ if (ch == '/' && stlmatch (str, "unknown")) version = RV36A; /* Dont map any unknown character */ else if (stlmatch (str, "unknown")) ; /* If it is a monster, set its array index */ else if (ch >= 'a' && ch <= 'z') { monindex[ch-'a'+ 1] = addmonhist (str); } } /* * addmonhist: Return the monster index of a given monster name in the * history array. Create an entry if none exists. */ int addmonhist (monster) char *monster; { register int m; /* Search for the monsters entry in the table */ for (m=0; m<nextmon; m++) if (streq (monster, monhist[m].m_name)) return (m); if (nextmon >= MAXMON) /* Check for overflow */ dwait (D_FATAL, "Overflowed monster array"); strcpy (monhist[nextmon].m_name, monster); /* Copy in the name */ return (nextmon++); /* Return the index */ } /* * findmonster: Return the monster index of a given monster name in the * history array. Return -1 if the monster is not in the table. */ int findmonster (monster) char *monster; { register int m; /* Search for the monsters entry in the table */ for (m=0; m<nextmon; m++) if (streq (monster, monhist[m].m_name)) return (m); return (-1); } /* * saveltm: Write the new monster information out to the long term memory * file for this version of Rogue. Be careful about serializing * access to the output file. */ saveltm (score) int score; { register int m; register FILE *ltmfil; if (nextmon < 1 || nosave) return; dwait (D_CONTROL, "Saveltm called, writing file '%s'", ltmnam); /* Disable interrupts and open the file for writing */ critical (); /* Only write out the new results if we can get write access */ if (lock_file (LOCKFILE, MAXLOCK)) { if ((ltmfil = wopen (ltmnam, "w")) == NULL) { dwait (D_WARNING, "Can't write long term memory file '%s'...", ltmnam); } else { /* Write the ltm file header */ fprintf (ltmfil, "Count %d, sum %d, start %d, saved %d\n", ltm.gamecnt+1, ltm.gamesum+score, ltm.inittime, ltm.timeswritten+1); /* Now write a line for each monster */ for (m = 0; m < nextmon; m++) { fprintf (ltmfil, "%s|", monhist[m].m_name); writeprob (ltmfil, &monhist[m].wehit); fprintf (ltmfil, "|"); writeprob (ltmfil, &monhist[m].theyhit); fprintf (ltmfil, "|"); writeprob (ltmfil, &monhist[m].arrowhit); fprintf (ltmfil, "|"); writestat (ltmfil, &monhist[m].htokill); fprintf (ltmfil, "|"); writestat (ltmfil, &monhist[m].damage); fprintf (ltmfil, "|"); writestat (ltmfil, &monhist[m].atokill); fprintf (ltmfil, "|\n"); } /* Close the file and unlock it */ fclose (ltmfil); } unlock_file (LOCKFILE); } /* Re-enable interrupts */ uncritical (); } /* * restoreltm: Read the long term memory file. */ restoreltm () { sprintf (ltmnam, "%s/ltm%d", RGMDIR, version); dwait (D_CONTROL, "Restoreltm called, reading file '%s'", ltmnam); clearltm (monhist); /* Clear the original sums */ nextmon = 0; /* Zero the list of monsters */ monindex[0] = addmonhist ("it"); /* Monster 0 is "it" */ /* Disable interrupts and open the file for reading */ critical (); /* Only read the long term memory if we can get access */ if (lock_file (LOCKFILE, MAXLOCK)) { if (fexists (ltmnam)) readltm (); else { dwait (D_CONTROL | D_SAY, "Starting long term memory file '%s'...", ltmnam); ltm.gamecnt = ltm.gamesum = ltm.timeswritten = 0; ltm.inittime = time (0); } unlock_file (LOCKFILE); } else { saynow ("Warning: could not lock long term memory file!"); nosave = 1; } uncritical (); } /* * readltm: Read in the long term memory file for this version of Rogue * into storage. Be careful about serializing access to the file. */ readltm () { char buf[BUFSIZ]; register FILE *ltmfil; if ((ltmfil = fopen (ltmnam, "r")) == NULL) { nosave = 1; dwait (D_WARNING | D_SAY, "Could not read long term memory file '%s'...", ltmnam); } else { /* Read the ltm file header */ if (fgets (buf, BUFSIZ, ltmfil)) sscanf (buf, "Count %d, sum %d, start %d, saved %d", <m.gamecnt, <m.gamesum, <m.inittime, <m.timeswritten); /* Read each monster line */ while (fgets (buf, BUFSIZ, ltmfil)) parsemonster (buf); fclose (ltmfil); } } /* * parsemonster: parse one line from the ltm file. */ parsemonster (monster) char *monster; { register char *attrs; char *index(); register int m; /* Separate the monster name from the attributes */ if ((attrs = index (monster, '|')) == NULL) return; *attrs++ = '\0'; /* Find the monsters entry in long term memory */ m = addmonhist (monster); /* Now parse the probabilities and statistics */ parseprob (attrs, &monhist[m].wehit); SKIPTO ('|', attrs); parseprob (attrs, &monhist[m].theyhit); SKIPTO ('|', attrs); parseprob (attrs, &monhist[m].arrowhit); SKIPTO ('|', attrs); parsestat (attrs, &monhist[m].htokill); SKIPTO ('|', attrs); parsestat (attrs, &monhist[m].damage); SKIPTO ('|', attrs); parsestat (attrs, &monhist[m].atokill); SKIPTO ('|', attrs); } /* * clearltm: Clear a whole long term memory array. */ clearltm (ltm) register ltmrec *ltm; { register int i; for (i=0; i<MAXMON; i++) { ltm[i].m_name[0] = '\0'; clearprob (<m[i].wehit); clearprob (<m[i].theyhit); clearprob (<m[i].arrowhit); clearstat (<m[i].htokill); clearstat (<m[i].damage); clearstat (<m[i].atokill); } } /* * dumpmonstertable: Format and print the monster table on the screen */ dumpmonstertable () { register int m; char monc; clear (); mvprintw (0,0,"Monster table:"); analyzeltm (); for (m=0, monc='A'; m<26; m++, monc++) { if (m < 13) at (m+2, 0); else at (m-11, 40); printw ("%c: %s", monc, monname (monc)); if (monhist[monindex[m+1]].damage.count > 0) printw (" (%d,%d)", monatt[m].expdam, monatt[m].maxdam); else printw (" <%d>", monatt[m].maxdam); if (monhist[monindex[m+1]].atokill.count > 0) printw (" [%d]", monatt[m].mtokill); } pauserogue (); } /* * analyzeltm: Set the monatt array based on current long term memory. */ analyzeltm () { register int m, i; double avg_dam = 0.6*Level+3, max_dam = 7.0+Level, avg_arr = 4.0; double phit, mean_dam, stdev_dam, three_dev; /* Loop through each monster in this game (not whole ltm file) */ for (i=0; i<26; i++) { m = monindex[i+1]; /* Calculate expected and maximum damage done by monster */ if (monhist[m].damage.count > 3) { mean_dam = mean (&monhist[m].damage); stdev_dam = stdev (&monhist[m].damage); max_dam = monhist[m].damage.high; avg_dam = mean_dam * prob (&monhist[m].theyhit); three_dev = mean_dam + 3 * stdev_dam; if (max_dam > three_dev && monhist[m].damage.count > 10) { max_dam = mean_dam + stdev_dam; monhist[m].damage.high = max_dam; } } else if (monhist[m].damage.high > 0.0) max_dam = monhist[m].damage.high; /* Calculate average arrows fired to killed monster */ if (monhist[m].atokill.count > 2) { phit = prob (&monhist[m].arrowhit); phit = max (phit, 0.1); avg_arr = mean (&monhist[m].atokill) / phit; } /* Now store the information in the monster tables */ monatt[i].expdam = ceil (avg_dam*10); monatt[i].maxdam = ceil (max_dam); monatt[i].mtokill = ceil (avg_arr); } }