|
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 s
Length: 13254 (0x33c6) Types: TextFile Names: »search.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Rog-O-Matic/search.c«
/* * search.c: Rog-O-Matic XIV (CMU) Mon Jan 28 18:28:07 1985 - mlm * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin * * This file contains the very basic search mechanisms for exploration etc. */ # include <stdio.h> # include <curses.h> # include "types.h" # include "globals.h" # define QSIZE (4000) # define QUEUEBREAK (111) # define FROM (20) # define UNREACHABLE (12) # define NOTTRIED (11) # define TARGET (10) static int moveavd[24][80], moveval[24][80], movecont[24][80], movedepth[24][80]; static char mvdir[24][80]; static int mvtype=0; static int didinit=0; /* * makemove: repeat move from here towards some sort of target. * Modified to use findmove. 5/13 MLM */ makemove (movetype, evalinit, evaluate, reevaluate) int movetype, (*evalinit)(), (*evaluate)(), reevaluate; { if (findmove (movetype, evalinit, evaluate, reevaluate)) return (followmap (movetype)); return (0); } /* * findmove: search for a move of type movetype. The move map is left in * the correct state for validatemap or followmap to work. MLM */ findmove (movetype, evalinit, evaluate, reevaluate) int movetype, (*evalinit)(), (*evaluate)(), reevaluate; { int result; didinit = ontarget = 0; if (!reevaluate) /* First try to reuse the movement map */ { result = validatemap (movetype, evalinit, evaluate); if (result == 1) return (1); /* Success */ if (result == 2) return (0); /* Evalinit failed, no move */ } /* Must rebuild the movement map */ mvtype = 0; /* Will become 'if (mvtype==movetype) movetype=0;' */ dwait (D_SEARCH, "Findmove: computing new search path."); /* currentrectangle(); */ /* always done after each move of the rogue */ searchstartr = atrow; searchstartc = atcol; if (!(*evalinit)()) /* Compute evalinit from current location */ { dwait (D_SEARCH, "Findmove: evalinit failed."); return (0); } if (!searchfrom (atrow, atcol, evaluate, mvdir, &targetrow, &targetcol)) { return (0); } /* move failed */ if (targetrow == atrow && targetcol == atcol) { ontarget = 1; return (0); } /* <<copy the newly created map to save*[][]>> */ mvtype = movetype; /* mvtype will be the type of saved map */ return (1); } /* * followmap: Assuming that the mvdir map is correct, send a movement * command following the map (possibly searching first). * * <<Must be changed to use the saved map, when that code is added>> * * May 13, MLM */ followmap (movetype) register int movetype; { register int dir, dr, dc, r, c; int timemode, searchit, count=1; dir=mvdir[atrow][atcol]-FROM; dr=deltr[dir]; dc=deltc[dir]; if (dir > 7 || dir < 0) { dwait (D_ERROR, "Followmap: direction invalid!"); return (0); /* Something Broke */ } r=atrow+dr; c=atcol+dc; /* Save next square in registers */ /* If exploring and are moving to a new hall square, use fmove */ if (movetype == EXPLORE && onrc (HALL|BEEN, targetrow, targetcol) != HALL|BEEN && onrc (HALL,r,c)) { fmove (dir); return (1); } /* Timemode tells why we are moving this way, T_RUNNING ==> no search */ timemode = (movetype == GOTOMOVE) ? T_MOVING : (movetype == EXPLORE) ? T_EXPLORING : (movetype == EXPLOREROOM) ? T_EXPLORING : (movetype == FINDROOM) ? T_EXPLORING : (movetype == EXPLORERUN) ? T_RUNNING : (movetype == RUNTODOOR) ? T_RUNNING : (movetype == RUNAWAY) ? T_RUNNING : (movetype == UNPIN) ? T_RUNNING : (movetype == UNPINEXP) ? T_RUNNING : (movetype == RUNAWAY) ? T_RUNNING : (movetype == RUNDOWN) ? T_RUNNING : (movetype == ATTACKSLEEP) ? T_FIGHTING : T_MOVING; /* How many times do we wish to search each square before moving? */ /* Search up to k times if 2 or more foods and deeper than level 6 */ searchit = max (0, min (k_srch/20, min (larder - 1, Level - 6))); /* Can we move more than one square at a time? */ if (compression) { while (mvdir[r][c]-FROM==dir && (onrc (SAFE, r+=dr, c+=dc) || !searchit)) count++; } /* Maybe search unsafe square before moving onto it */ if (timemode != T_RUNNING && !onrc (SAFE, atrow+dr, atcol+dc) && timessearched[atrow+dr][atcol+dc] < searchit) { command (T_SEARCHING, "s"); return (1); } /* Maybe take armor off before stepping on rust trap */ if (timemode != T_RUNNING && onrc (WATERAP, atrow+dr, atcol+dc) && currentarmor != NONE && willrust () && takeoff ()) { rmove (1, dir, timemode); return (1); } /* If we are about to step onto a scare monster scroll, use the 'm' cmd */ if (version >= RV53A && onrc (SCAREM, atrow+dr, atcol+dc)) { mmove (dir, timemode); return (1); } /* Send the movement command and return success */ rmove (count, dir, timemode); return (1); } /* * validatemap: If we have a stored move, make it and return true. * * <<Must be changed to use the saved map, when that code is added>> * * Called only by findmove. MLM */ validatemap (movetype, evalinit, evaluate) int movetype, (*evalinit)(), (*evaluate)(); { register int thedir, dir, r, c; int val, avd, cont; dwait (D_CONTROL | D_SEARCH, "Validatemap: type %d", movetype); if (mvtype != movetype) { dwait (D_SEARCH, "Validatemap: move type mismatch, map invalid."); return (0); } thedir = mvdir[atrow][atcol] - FROM; if (thedir > 7 || thedir < 0) { dwait (D_SEARCH, "Validatemap: direction in map invalid."); return (0); /* Something Broke */ } /* * Check that the planned path is still valid. This is done by * proceeding along it and checking that the value and avoidance * returned from the evaluation function are the same as * when the search was first performed. The initialisation function * is re-performed and then the evaluation function done. */ if (!didinit && !(*evalinit)()) { dwait (D_SEARCH, "Validatemap: evalinit failed."); return (2); /* evalinit failed */ } didinit=1; r=atrow; c=atcol; while (1) { val = avd = cont = 0; if (!(*evaluate)(r, c, movedepth[r][c], &val, &avd, &cont)) { dwait (D_SEARCH, "Validatemap: evaluate failed."); return (0); } if (!onrc (CANGO, r, c) || avd!=moveavd[r][c] || val!=moveval[r][c] || cont!=movecont[r][c]) { dwait (D_SEARCH, "Validatemap: map invalidated."); return (0); } if ((dir=mvdir[r][c]-FROM) == TARGET) { dwait (D_SEARCH, "Validatemap: existing map validated."); break; } if (dir < 0 || dir > 7) { dwait (D_SEARCH, "Validatemap: direction in map invalid."); return (0); } r += deltr[dir]; c += deltc[dir]; } return (1); } /* * cancelmove: Invalidate all stored moves of a particular type. */ cancelmove (movetype) int movetype; { if (movetype == mvtype) mvtype = 0; } /* * setnewgoal: Invalidate all stored moves. */ setnewgoal () { mvtype = 0; goalr = goalc = NONE; } /* * searchfrom: By means of breadth first search, find a path * from the given row and column to a target. This is done by using * searchto and then reversing the path to the row, col from the selected * target. Note that this means that the resultant direction map can * only be re-used if the new row, col is on the existing path. The * reversed path consists of directions offset by FROM. * arguments and results otherwise the same as searchto. LGCH */ searchfrom (row, col, evaluate, dir, trow, tcol) int row, col, *trow, *tcol; int (*evaluate)(); char dir[24][80]; { register int r, c, sdir, tempdir; if (!searchto (row, col, evaluate, dir, trow, tcol)) { return (0); } for (r = *trow, c = *tcol, sdir = FROM+TARGET; ; ) { tempdir = dir[r][c]; dir[r][c] = sdir; if (debug (D_SCREEN | D_INFORM | D_SEARCH)) { at (r, c); printw ("%c", ">/^\\</v\\ ~"[sdir-FROM]);} sdir = (tempdir + 4) % 8 + FROM; /* reverse direction and offset */ if (tempdir == TARGET) break; r += deltr[tempdir]; c += deltc[tempdir]; } dwait (D_SEARCH, "Searchfrom wins."); return (1); } /* * searchto: By means of a breadth first search, find a path to the * given row and column from a target. A target is defined as a * location which has +ve value returned by the evaluation function and * for which the avoidance value has been decremented to zero. The most * valuable target found in the first successful iteration of the * search, is selected. (i.e. the most valuable square at the lowest * level of the search). Returns dir the direction map of paths to * row,col from target Also returns trow, tcol the position of the * selected target (NOTE: To use this search directly, e.g. to find * paths to a single actual target such as the staircase, the * evaluation function should give zero value to everything except the * current Rog-O-Matic location To re-use the results of a search, * ensure that dir[row][col] is still set to TARGET and check that a * valid direction exists at the target position.) * * The search prefers horizontal movements to vertical movements, and * prefers moves onto SAFE squares to moves onto other squares. LGCH */ /* * Since this code is the single most time consuming subroutine, I am * attempting to hack it into a faster form. 11/6/82 MLM */ searchto (row, col, evaluate, dir, trow, tcol) int row, col, *trow, *tcol; int (*evaluate)(); char dir[24][80]; { int searchcontinue = 10000000, type, havetarget=0, depth=0; register int r, c, nr, nc; register int k; char begin[QSIZE], *end, *head, *tail; int saveavd[24][80], val, avd, cont; int any; static int sdirect[8] = {4, 6, 0, 2, 5, 7, 1, 3}, sdeltr[8] = {0,-1, 0, 1,-1,-1, 1, 1}, sdeltc[8] = {1, 0,-1, 0, 1,-1,-1, 1}; head = tail = begin; end = begin + QSIZE; for (c = 23*80; c--; ) dir[0][c] = NOTTRIED; /* MLM */ for (c = 80; c--; ) dir[0][c] = 0; /* MLM */ *(tail++) = row; *(tail++) = col; *(tail++) = QUEUEBREAK; *(tail++) = QUEUEBREAK; dir[row][col] = TARGET; moveval[row][col] = NONE; any = 1; while (1) { /* Process the next queued square. */ r = *(head++); c = *(head++); if (head == end) head = begin; /* wrap-around queue */ if (r==QUEUEBREAK) { /* If we have completed an evaluation loop */ if (searchcontinue <= 0 || !any) { if (havetarget) dwait (D_SEARCH, "Searchto wins."); else dwait (D_SEARCH, "Searchto fails."); return (havetarget); /* have found somewhere to go */ } searchcontinue--; depth++; /* ---------------------------------------------------------------- if (debug (D_SCREEN)) dwait (D_SEARCH, "Searchto: at queue break, cont=%d, havetarget=%d", searchcontinue, havetarget); ---------------------------------------------------------------- */ any = 0; /* None found in queue this time round */ *(tail++) = QUEUEBREAK; *(tail++) = QUEUEBREAK; if (tail == end) tail = begin; continue; } any = 1; /* Something in queue */ if (moveval[r][c] == NONE) { /* unevaluated: evaluate it */ val = avd = cont = 0; if ((*evaluate)(r,c,depth,&val,&avd,&cont)) /* Evaluate it. */ { movedepth[r][c] = depth; moveavd[r][c] = avd; moveval[r][c] = val; movecont[r][c] = cont; if (avd >= INFINITY) { /* Infinite avoidance */ dir[r][c]=UNREACHABLE; /* we cant get here */ continue; /* discard the square from consideration. */ } else { saveavd[r][c]=avd; } } else /* If evaluate fails, forget it for now. */ { dwait (D_SEARCH, "Searchto: evaluate failed."); continue; } } if (saveavd[r][c]) { /* If to be avoided, leave in queue for a while */ *(tail++) = r; *(tail++) = c; --(saveavd[r][c]); /* Dec avoidance */ if (tail == end) tail = begin; continue; } if (moveval[r][c] > havetarget) { /* It becomes the target if it has value bigger than the best found so far, and if it has a non-zero value. */ if (debug (D_SCREEN | D_SEARCH | D_INFORM)) { mvprintw (r, c, "="); dwait (D_SEARCH, "Searchto: target value %d.", moveval[r][c]); } searchcontinue = movecont[r][c]; *trow = r; *tcol = c; havetarget = moveval[r][c]; } type = SAFE; while (1) { for (k=0; k<8; k++) { register int S; /* examine adjacent squares. */ nr = r + sdeltr[k]; nc = c + sdeltc[k]; S = scrmap[nr][nc]; /* IF we have not considered stepping on the square yet */ /* and if it is accessible THEN: Put it on the queue */ if (dir[nr][nc] == NOTTRIED && (CANGO&S) && (type&S) == type && (k<4 || onrc (CANGO,r,nc) && onrc (CANGO,nr,c))) { moveval[nr][nc] = NONE; /* flag unevaluated */ *(tail++) = nr; *(tail++) = nc; if (tail == end) tail = begin; dir[nr][nc] = sdirect[k]; /* direction we used to get here */ if (debug (D_SCREEN | D_SEARCH | D_INFORM)) { at (nr, nc); printw ("%c", ">/^\\</v\\ ~"[dir[nr][nc]]);} } } if (type == 0) break; type = 0; } } }