home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 101_01 / xword.c < prev    next >
Text File  |  1985-11-14  |  15KB  |  532 lines

  1.  
  2. /**********************************************************
  3.  ***                            ***
  4.  ***    Copyright (c) 1981 by David M. Fogg        ***
  5.  ***                            ***
  6.  ***        2632 N.E. Fremont            ***
  7.  ***        Portland, OR 97212            ***
  8.  ***                            ***
  9.  ***        (503) 288-3502{HM} || 223-8033{WK}        ***
  10.  ***                            ***
  11.  ***    Permission is herewith granted for non-     ***
  12.  ***    commercial distribution through the BDS C    ***
  13.  ***    User's Group; any and all forms of commercial   ***
  14.  ***    redistribution are strenuously unwished-for.    ***
  15.  ***                            ***
  16.  **********************************************************/
  17.  
  18. /* ---> XWORD.C <--- : Crossword Puzzle Program : Z-19 version
  19.  
  20.    (C) Copyright 1980 by David M. Fogg @ New Day Computing - Portland, OR
  21.  
  22.    9 APR 80 - 1st pass
  23.    25 oct 80: convert to BDS C 1st pass
  24.    26 Oct: add final touches
  25.    28 Oct: convert to VG MT
  26.    29 Oct: chg to oclose() in WRITS:
  27.    31 Oct: fix VG shift arrow prob;
  28.        add dubchk() to READS: & WRITS:;
  29.        chg putadv(..) 2 only move 2 nxt legal loc
  30.    4 Nov: convert back to Z-19/DMF environment
  31.    25 Nov: re-comp w/coin() as BIOS, not BDOS, call (1.4X comp);
  32.        make clue display automagickall
  33.    27 Nov: fix ERASE & READS to disp clues after scrn regen
  34.    3 Dec: chg dubchk() 2 wrk w/ lc 'y'; add scrn regen func;
  35.       improve getext() & reloc query.
  36.  
  37.  * HINTS: answer files are FILNAM.ANS
  38.  *                ANSER array
  39.  *                <1st ACROSS clue
  40.  *                rest of ACROSS clues
  41.  *                <1st DOWN clue
  42.  *                rest of DOWN clues
  43.  *                EOF
  44.  *    Partially filled-out screens are FILNAM.EXT
  45.  *        (user specifies EXT)
  46.  *                SCREEN array current contents
  47.  *
  48.  *    All commands are single locase alfa chars;
  49.  *    ucase alfa are put on screen @ curr position,
  50.  *    & cursor is moved ACROSS or DOWN (current mode).
  51.  *
  52.  *    Any letters put on screen by cheating
  53.  *    ('peek' or 'giveup') are put in locase.
  54.  */
  55.  
  56. #include <std.h>
  57.  
  58. #define MAXIZ    21        /* maximum rows/cols in puzzle */
  59. #define AVLEN    35        /* avg clue length */
  60. #define MAXLEN    65        /* max    "     "    */
  61. #define MXCLUES MAXIZ*MAXIZ/2    /* max # ACROSS+DOWN clues */
  62. #define CLUBS    MXCLUES*AVLEN    /* size of clubuf[] */
  63.  
  64. #define DX    3        /* horiz dist btwn chars */
  65. #define DY    1        /* vert   "    "     "   */
  66. #define XORG    1        /* scrn X-ord of upleft char */
  67. #define YORG    0        /*  "   Y-ord "    "     "   */
  68.  
  69. /*
  70.     ---> command characters <---
  71. */
  72. #define ACROSS    'p'        /* set mode to ACROSS */
  73. #define DOWN    'q'        /*  "   "   "  DOWN */
  74. #define GOBAK    '4'        /* command to move cursor left */
  75. #define GOFWD    '6'        /*    "    "   "     "      right */
  76. #define GOUP    '8'        /*    "    "   "     "      up */
  77. #define GODN    '2'        /*    "    "   "     "      down */
  78. #define TOPLN    't'        /* goto top line in col */
  79. #define BOTLN    'v'        /*  "   bott "     "   "    */
  80. #define INITC    's'        /*  "   init col "  line */
  81. #define FINC    'w'        /*  "   final "  "   "     */
  82. #define PEEK    '7'        /* put anser letter on scrn */
  83. #define UNDO    '9'        /* erase a single letter */
  84. #define ERASE    '3'        /*** erase screen ***/
  85. #define GIVUP    '1'        /*** fill in whole screen ***/
  86. #define WRITS    'u'        /* write scrn to file */
  87. #define READS    'r'        /* read   "  from "   */
  88. #define REGEN    '\t'        /* regenerate screen */
  89. #define QUIT    '5'        /*** quit: exit program ***/
  90. /*
  91.     ---> misc ASCII &c <---
  92. */
  93. #define MT    '.'        /* empty cell on screen */
  94. #define WALL    ' '        /* wall cell */
  95. #define DELIM    '<'        /* delimit anser<ACROSS<DOWN in file */
  96. #define RUBIT     0        /* erase scrn arg to scrini() */
  97. #define RENUIT    -1        /* regen scrn arg to scrini() */
  98. /*
  99.     ---> screen positions <---
  100. */   
  101. #define ACY    22        /* ACROSS clue line */
  102. #define DCY    23        /* DOWN    "    "   */
  103. #define AHX    0        /* ACROSS hdr column */
  104. #define DHX    2        /* DOWN    "    "    */
  105. #define ACX    8        /* ACROSS clue    "    */
  106. #define DCX    8        /* DOWN    "    "    */
  107. #define FNY    0        /* filename line */
  108. #define FNX    68        /*    "     column */
  109. #define PRX    66        /* extension prompt col */
  110. #define PRY    20        /*     "       "    line */
  111. #define INX    65        /* Instructions column */
  112. #define INY    3        /* first Instructions line */
  113. #define L25X    5        /* funkey ID line X-ord */
  114. #define L25Y    24        /*   "    "   "   Y-ord */
  115.  
  116.  
  117. /*
  118.     * * * * * *  G L O B A L S  * * * * * *
  119. */
  120.  
  121. char iobuf[BUFSIZ];         /* file I/O buffer */
  122.  
  123. int rows, cols;        /* rows/cols in curr puzzle */
  124. int crow, ccol;        /* current (cursor) row/column */
  125. int nacc, ndown;       /* # of ACROSS/DOWN clues */
  126. char scrn[MAXIZ][MAXIZ];    /* screen array */
  127. char anser[MAXIZ][MAXIZ];   /* answer array */
  128. char *aclu[MAXIZ][MAXIZ];   /* pointo ACROSS clues in clubuf */
  129. char *dclu[MAXIZ][MAXIZ];   /*     "    DOWN     "   "    "    */
  130. char clubuf[CLUBS];          /* clues buffer */
  131.  
  132.  
  133. /* >>>------------->  M A I N    P R O G R A M  <-------------<<< */
  134.  
  135. main (ac, av)
  136. int ac;
  137. char *av[];
  138. {
  139.    char filnam[12], ansfil[15]; /* file names */
  140.    int ansfd, scrfd;        /* file descriptors */
  141.    char inch;            /* input char from kbd */
  142.    int savr, savc;        /* save crow,ccol */
  143.    char dir;            /* direction/clue flag: a/d */
  144.    int arow, acol, drow, dcol;    /* last ACROSS/DOWN clue cursor lox */
  145.    BOOL errms;
  146.  
  147.    rows = cols = crow = ccol = nacc = ndown = 0;
  148.    arow = acol = drow = dcol = -1;
  149.    errms = NO;
  150.  
  151.    if ((++av, --ac) != 1)
  152.       errxit("usage: xword ansfilnam");
  153.    strcpy(filnam, *av); strcpy(ansfil, *av);
  154.    strcat(ansfil, ".ANS");
  155.    if ((ansfd = fopen(ansfil, iobuf)) == ERROR)
  156.       errxit(".ANS file not found");
  157.  
  158.    getans();       /* read .ANS file & setup clue pointers */
  159.  
  160.    dir = scrini(filnam, NO);    /* initialize screen */
  161. /*
  162.     >>------> MAIN LOOP <------<<
  163. */
  164.    FOREVER {
  165.       cluput(arow, acol, drow, dcol);
  166.       arow = drow = crow;
  167.       acol = dcol = ccol;
  168.       inch = zchar();
  169.       if (errms) {
  170.      ereol(PRX, PRY);
  171.      errms = NO;
  172.       }
  173.       if (isupper(inch))
  174.      putadv(inch, dir);
  175.       else
  176.      switch (inch) {
  177.         case ACROSS:    /* set dir (& print clue) */
  178.            toxy(AHX, ACY); puts("ACROSS:");
  179.            msgat(DHX, DCY, "DOWN:");
  180.            dir = ACROSS;
  181.            break;
  182.         case DOWN:
  183.            toxy(DHX, DCY); puts("DOWN:");
  184.            msgat(AHX, ACY, "ACROSS:");
  185.            dir = DOWN;
  186.            break;
  187.         case GOBAK:     /* move one space left */
  188.            while (torc(crow, --ccol) == WALL);
  189.            break;
  190.         case GOFWD:      /* move one space right */
  191.            while (torc(crow, ++ccol) == WALL);
  192.            break;
  193.         case GODN:         /* move one space down */
  194.            while (torc(++crow, ccol) == WALL);
  195.            break;
  196.         case GOUP:         /* move one space up */
  197.            while (torc(--crow, ccol) == WALL);
  198.            break;
  199.         case TOPLN:     /* move to limit u/d/l/r */
  200.         case BOTLN:
  201.         case INITC:
  202.         case FINC:
  203.            crow = (inch == TOPLN) ? 0 : (inch == BOTLN) ? rows - 1: crow;
  204.            ccol = (inch == INITC) ? 0 : (inch == FINC) ? cols - 1 : ccol;
  205.            while (torc(crow, ccol) == WALL) {
  206.           crow += (inch == TOPLN) - (inch == BOTLN);
  207.           ccol += (inch == INITC) - (inch == FINC);
  208.            }
  209.            break;
  210.         case PEEK:        /* peek: put anser ltr up */
  211.            putadv(tolower(anser[crow][ccol]), dir);
  212.            break;
  213.         case UNDO:        /* erase a single letter */
  214.            putadv(MT, dir);
  215.            break;
  216.         case ERASE:     /* erase screen */
  217.            if (dubchk()) {
  218.           dir = scrini(filnam, RUBIT);
  219.           acol = dcol = arow = drow = -1;
  220.            }
  221.            break;
  222.         case GIVUP:     /* giveup: fillin screen */
  223.            savr = crow; savc = ccol;
  224.            if (dubchk()) {
  225.           for (crow = 0; crow < rows; ++crow)
  226.           for (ccol = 0; ccol < cols; ++ccol)
  227.              if (scrn[crow][ccol] == MT)
  228.             charon(scrn[crow][ccol] = tolower(anser[crow][ccol]));
  229.            }
  230.            torc(savr, savc);
  231.            break;
  232.         case WRITS:     /* write screen to file */
  233.            savr = crow; savc = ccol;
  234.            if (dubchk())
  235.           if ((scrfd = getext(filnam, WRITE)) < 0) {
  236.              msgat(PRX, PRY, "FILE ERR");
  237.              errms = YES;
  238.           }
  239.           else {
  240.              for (crow = 0; crow < rows; ++crow) {
  241.             for (ccol = 0; ccol < cols; ++ccol)
  242.                putc(scrn[crow][ccol], iobuf);
  243.             fputs("\r\n", iobuf);
  244.              }
  245.              oclose(iobuf);
  246.              ereol(PRX, PRY);
  247.           }
  248.            torc(savr, savc);
  249.            break;
  250.         case READS:     /* read screen from file */
  251.            savr = crow; savc = ccol;
  252.            if (dubchk())
  253.           if ((scrfd = getext(filnam, READ)) == ERROR) {
  254.              msgat(PRX, PRY, "NOT FOUND");
  255.              errms = YES;
  256.           }
  257.           else {
  258.              dir = scrini(filnam, scrfd);
  259.              acol = dcol = arow = drow = -1;
  260.              fclose(iobuf);
  261.           }
  262.            torc(savr, savc);
  263.            break;
  264.         case REGEN:
  265.            savr = crow; savc = ccol;
  266.            dir = scrini(filnam, RENUIT);
  267.            acol = dcol = arow = drow = -1;
  268.            torc(savr, savc);
  269.            break;
  270.         case QUIT:        /* quit: exit the program */
  271.            if (dubchk()) {
  272.           puts(POCRT);
  273.           sleep(13);
  274.           errxit("Bye");
  275.            }
  276.      } /* switch */
  277.    } /* FOREVER */
  278. } /* main */
  279.  
  280. /************* ---< S U B R O U T I N E S >--- *************/
  281.  
  282.  
  283. getans ()           /* --<READ .ANS FL & SETUP CLUES */
  284. {
  285.    char c;
  286.    int    colt;
  287.    char *lasacc, *firsdn;    /* -> last ACROSS/1st DOWN clubuf */
  288.    char **pacc, **pdown;    /* pointers into pclues */
  289.    char *pclues[MXCLUES];    /* initial clue pointers */
  290.  
  291.    colt = 0;
  292.  
  293.    while (((c = getc(iobuf)) != CEOF) && (c != DELIM))    /* first: anser[][] */
  294.       if (c == '\n') {
  295.      cols = colt; colt = 0;
  296.      if (++rows > MAXIZ)
  297.         errxit("too many rows");
  298.       }
  299.       else if (achar(c)) {
  300.      anser[rows][colt] = c;
  301.      if (++colt > MAXIZ)
  302.         errxit("Too many columns");
  303.       }
  304.  
  305.    nacc = getclu(pclues, &clubuf, MXCLUES, clubuf+CLUBS);    /* 2nd: ACROSS */
  306.    lasacc = pclues[nacc - 1];
  307.    firsdn = lasacc + strlen(lasacc) + 1;
  308.    ndown = getclu(&pclues[nacc], firsdn, MXCLUES-nacc, clubuf+CLUBS);    /* 3rd: DOWN */
  309.  
  310.    pdown = (pacc = pclues) + nacc;    /* setup clue pointers */
  311.    for (crow = 0; crow < rows; ++crow)
  312.    for (ccol = 0; ccol < cols; ++ccol)
  313.       if (anser[crow][ccol] != WALL) {
  314.      aclu[crow][ccol] =
  315.         (ccol == 0 || anser[crow][ccol-1] == WALL) ?
  316.            *(pacc++) : aclu[crow][ccol-1];
  317.      dclu[crow][ccol] =
  318.         (crow == 0 || anser[crow-1][ccol] == WALL) ?
  319.            *(pdown++) : dclu[crow-1][ccol];
  320.       }
  321.    fclose(iobuf);
  322. }
  323.  
  324.  
  325. getclu (pclu, cbuf, mxclu, clutop) /* --<READ A SET OF CLUES>-- */
  326. char **pclu;
  327. char *cbuf;
  328. int mxclu;
  329. char *clutop;
  330. {
  331.    char c;
  332.    int nc, len;
  333.    int nlins    ;
  334.  
  335.    nlins = 0;
  336.  
  337.    FOREVER {
  338.       len = 0;
  339.       while ((c = getc(iobuf)) != CEOF && c != '\n' && c != DELIM)
  340.      if (c >= ' ')
  341.         *(cbuf + len++) = c;
  342.       if (c == 0 || c == DELIM)
  343.      return(nlins);         /* ---> EGRESS ---> */
  344.       if (nlins > mxclu || cbuf + len > clutop)
  345.      errxit("Clue buffer overflow");
  346.       pclu[nlins++] = cbuf;
  347.       cbuf += ++len;
  348.       *(cbuf-1) = '\0';     /* zap \r w/ string terminator */
  349.    }
  350. }
  351.  
  352.  
  353. scrini (fnam, scrnfd)         /* --<SCREEN INITIALIZE>-- */
  354. char *fnam;
  355. int scrnfd;    /* <0: regen scrn; 0: startup init; >0: read save file */
  356. {
  357.    char c;
  358.  
  359.    puts(CLEAR); puts(VIDINV); puts(BLINON); puts(PADNOR);
  360.    toxy(L25X, L25Y);
  361.    puts(" LEFT   TOP   SAVE   BOTT   RIGHT        ACROSS   DOWN   GET ");
  362.    for (crow = 0; crow < rows; ++crow)
  363.    for (ccol = 0; ccol < cols; ++ccol) {
  364.       if (ccol == 0) {
  365.      torc(crow, ccol); puts(CURLEF);
  366.       }
  367.       if (scrnfd > 0)
  368.      do {
  369.         c = getc(iobuf); 
  370.      } while (!(isalpha(c) || c == WALL || c == MT));
  371.       else if (scrnfd == 0)
  372.      c = (anser[crow][ccol] == WALL) ? WALL : MT;
  373.       else
  374.      c = scrn[crow][ccol];
  375.  
  376.       if (c == WALL)
  377.      puts(VIDNOR);
  378.       scrn[crow][ccol] = c;
  379.       printf(" %c ", c);
  380.       if (c == WALL)
  381.      puts(VIDINV);
  382.    }
  383.    msgat(FNX, FNY, fnam);
  384.    toxy(AHX, ACY); puts("ACROSS:");
  385.    msgat(DHX, DCY, "DOWN:");
  386.  
  387.    toxy(INX, INY); puts(   "Arrow keys:    ");
  388.    toxy(INX, INY+1); puts( "   move cursor ");
  389.    toxy(INX, INY+2); puts( "               ");
  390.    toxy(INX, INY+3); puts( "IC: clue letter");
  391.    toxy(INX, INY+4); puts( "DC: delete ltr ");
  392.    toxy(INX, INY+5); puts( "DL: erase scrn ");
  393.    toxy(INX, INY+6); puts( "IL: fillin scrn");
  394.    toxy(INX, INY+7); puts( "TAB: regen scrn");
  395.    toxy(INX, INY+8); puts( "HOME: quit prog");
  396.    toxy(INX, INY+9); puts( "               ");
  397.    toxy(INX, INY+10); puts("A-Z or a-z:    ");
  398.    toxy(INX, INY+11); puts("fills in puzzle");
  399.  
  400.    crow = ccol = 0;
  401.    while (torc(crow, ccol) == WALL)
  402.       ++ccol;
  403.    return(ACROSS);
  404. }
  405.  
  406.  
  407. getext (fnam, mode)    /* --<GET EXT & OPEN SCRN READ|WRITE FILE>-- */
  408. char *fnam;
  409. char mode;
  410. {
  411.    char scrfil[15];
  412.    char fext[20];
  413.    int i;
  414.  
  415.    toxy(PRX, PRY); puts(VIDNOR); puts("Ext: "); gets(fext);
  416.    fext[3] = NULL;
  417.    if ((i = inset(fext, '\r')) > 0) fext[--i] = NULL;
  418.    puts(VIDINV);
  419.    strcpy(scrfil, fnam); strcat(scrfil, "."); strcat(scrfil, fext);
  420.    if (mode == READ)
  421.       return (fopen(scrfil, iobuf));
  422.    else
  423.       return (fcreat(scrfil, iobuf));
  424. }
  425.  
  426.  
  427. putadv (nuch, dir)    /* --<PUT nuch IN/ON Scrn & ADVANCE>-- */
  428. char nuch, dir;
  429. {
  430.    charon(scrn[crow][ccol] = nuch);
  431.  
  432.    if (dir == ACROSS) {
  433.       if (ccol < cols - 1 && scrn[crow][ccol+1] != WALL)
  434.      torc(crow, ++ccol);
  435.    }
  436.    else
  437.       if (crow < rows - 1 && scrn[crow+1][ccol] != WALL)
  438.      torc(++crow, ccol);
  439. }
  440.  
  441.  
  442. charon (ch)    /* --<PUT ch @ crow,ccol>-- */
  443. char ch;
  444. {
  445.    torc(crow, ccol);
  446.    putchar(ch);
  447.    torc(crow, ccol);    /* put cursor atop ch */
  448. }
  449.  
  450.  
  451. torc (row, col)     /* --<PUT CURSOR @ row,col>-- */
  452. int row, col;
  453.             /* update crow,ccol & ret scrn char */
  454. {
  455.    int xx, yy;
  456.  
  457.    crow = (row + rows) % rows;
  458.    ccol = (col + cols) % cols;
  459.    xx = (ccol * DX) + XORG; yy = crow;
  460.    toxy(xx, yy);
  461.  
  462.    return(scrn[crow][ccol]);
  463. }
  464.  
  465.  
  466. msgat (x, y, msg)    /* --<WRITE msg @ x,y ON SCREEN>-- */
  467. int x, y;
  468. char *msg;
  469. {
  470.    toxy(x, y); puts(VIDNOR);
  471.    puts(msg);
  472.    puts(VIDINV);
  473.    torc(crow, ccol);    /* put cursor back */
  474. }
  475.  
  476.  
  477. cluput (ar, ac, dr, dc) /* --<PUT NU CLUZE - MAYBE>-- */
  478. int ar, ac, dr, dc;
  479. {
  480.    BOOL samewd;
  481.  
  482.    samewd = YES;
  483.    if (ar == crow)
  484.       for (; ac != ccol && samewd; (ac < ccol) ? ++ac : --ac)
  485.      if (scrn[ar][ac] == WALL)
  486.         samewd = NO;
  487.    if (ar != crow || !samewd) {
  488.       ereol(ACX, ACY);
  489.       msgat(ACX, ACY, aclu[crow][ccol]);
  490. }
  491.  
  492.    samewd = YES;
  493.    if (dc == ccol)
  494.       for (; dr != crow && samewd; (dr < crow) ? ++dr : --dr)
  495.      if (scrn[dr][dc] == WALL)
  496.         samewd = NO;
  497.    if (dc != ccol || !samewd) {
  498.       ereol(DCX, DCY);
  499.       msgat(DCX, DCY, dclu[crow][ccol]);
  500.    }
  501. }
  502.  
  503.  
  504. BOOL dubchk ()         /* --<VERIFY DANGEROUS COMMAND>-- */
  505. {
  506.    char chkms[7];
  507.    char ans;
  508.  
  509.    strcpy(chkms, "SURE? ");
  510.  
  511.    toxy(PRX, PRY);
  512.    puts(chkms);
  513.    ans = toupper(getchar());
  514.    ereol(PRX, PRY);
  515.    torc(crow, ccol);
  516.    return ((ans == 'Y') ? YES : NO);
  517. }
  518.  
  519.  
  520. BOOL achar (c)        /* --<IS c A CHAR OR A WALL?>-- */
  521. char c;
  522. {
  523.    return (isupper(c) || c == WALL);
  524. }
  525.  
  526.  
  527. ereol (x, y)           /* --< POSITION TO x,y & ERASE TO EOL>-- */
  528. int x, y;
  529. {
  530.    toxy(x, y); puts(EREOL);
  531. }
  532.