summaryrefslogtreecommitdiff
path: root/games/snake/move.c
diff options
context:
space:
mode:
authorPaul Janzen <pjanzen@cvs.openbsd.org>1999-03-13 02:08:21 +0000
committerPaul Janzen <pjanzen@cvs.openbsd.org>1999-03-13 02:08:21 +0000
commit606df7dfe35de43c6dad31da7b4a55bbab43c0e0 (patch)
tree2cdb636e7396f5677faebc5ec4635f1ec56c4e8e /games/snake/move.c
parent82e562898d3caaa66b6c64b435bd0bb619faa450 (diff)
Fix a few bugs (e.g. snake used to miss turns); use usleep() so display
speed is correct on xterms; put snscore functionality inside snake and make snscore a symbolic link (to be phased out); clean up formatting; install score file properly; disable the log file by default (logging should be done through dm).
Diffstat (limited to 'games/snake/move.c')
-rw-r--r--games/snake/move.c703
1 files changed, 703 insertions, 0 deletions
diff --git a/games/snake/move.c b/games/snake/move.c
new file mode 100644
index 00000000000..df8d50e1706
--- /dev/null
+++ b/games/snake/move.c
@@ -0,0 +1,703 @@
+/* $OpenBSD: move.c,v 1.1 1999/03/13 02:08:09 pjanzen Exp $ */
+/* $NetBSD: move.c,v 1.12 1996/05/19 20:22:09 pk Exp $ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 7/19/93";
+#else
+static char rcsid[] = "$OpenBSD: move.c,v 1.1 1999/03/13 02:08:09 pjanzen Exp $";
+#endif
+#endif /* not lint */
+
+/*************************************************************************
+ *
+ * MOVE LIBRARY
+ *
+ * This set of subroutines moves a cursor to a predefined
+ * location, independent of the terminal type. If the
+ * terminal has an addressable cursor, it uses it. If
+ * not, it optimizes for tabs (currently) even if you don't
+ * have them.
+ *
+ * At all times the current address of the cursor must be maintained,
+ * and that is available as structure cursor.
+ *
+ * The following calls are allowed:
+ * move(sp) move to point sp.
+ * up() move up one line.
+ * down() move down one line.
+ * bs() move left one space (except column 0).
+ * nd() move right one space(no write).
+ * clear() clear screen.
+ * home() home.
+ * ll() move to lower left corner of screen.
+ * cr() carriage return (no line feed).
+ * pr() just like standard printf, but keeps track
+ * of cursor position. (Uses pstring).
+ * apr() same as printf, but first argument is &point.
+ * (Uses pstring).
+ * pstring(s) output the string of printing characters.
+ * However, '\r' is interpreted to mean return
+ * to column of origination AND do linefeed.
+ * '\n' causes <cr><lf>.
+ * putpad(str) calls tputs to output character with proper
+ * padding.
+ * outch() the output routine for a character used by
+ * tputs. It just calls putchar.
+ * pch(ch) output character to screen and update
+ * cursor address (must be a standard
+ * printing character). WILL SCROLL.
+ * pchar(ps,ch) prints one character if it is on the
+ * screen at the specified location;
+ * otherwise, dumps it.(no wrap-around).
+ *
+ * getcap() initializes strings for later calls.
+ * cap(string) outputs the string designated in the termcap
+ * data base. (Should not move the cursor.)
+ *
+ * cook() returns the terminal to initial state.
+ *
+ * point(&p,x,y) return point set to x,y.
+ *
+ * delay(t) causes an approximately constant delay
+ * independent of baudrate.
+ * Duration is ~ t/20 seconds.
+ *
+ ******************************************************************************/
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <err.h>
+#include <stdlib.h>
+#include <term.h>
+#include <unistd.h>
+#include "snake.h"
+
+int CMlength;
+int NDlength;
+int BSlength;
+int delaystr[10];
+speed_t ospeed;
+
+static char str[80];
+
+void
+move(sp)
+ struct point *sp;
+{
+ int distance;
+ int tabcol, ct;
+ struct point z;
+
+ if (sp->line < 0 || sp->col < 0 || sp->col > COLUMNS) {
+ pr("move to [%d,%d]?", sp->line, sp->col);
+ return;
+ }
+ if (sp->line >= LINES) {
+ move(point(&z, sp->col, LINES - 1));
+ while (sp->line-- >= LINES)
+ putchar('\n');
+ return;
+ }
+
+ if (CM != 0) {
+ char *cmstr = tgoto(CM, sp->col, sp->line);
+
+ CMlength = strlen(cmstr);
+ if (cursor.line == sp->line) {
+ distance = sp->col - cursor.col;
+ if (distance == 0)
+ return; /* Already there! */
+ if (distance > 0) { /* Moving to the right */
+ if (distance * NDlength < CMlength) {
+ right(sp);
+ return;
+ }
+ if (TA) {
+ ct = sp->col & 7;
+ tabcol = (cursor.col | 7) + 1;
+ do {
+ ct++;
+ tabcol = (tabcol | 7) + 1;
+ }
+ while (tabcol < sp->col);
+ if (ct<CMlength) {
+ right(sp);
+ return;
+ }
+ }
+ } else { /* Moving to the left */
+ if (-distance * BSlength < CMlength) {
+ gto(sp);
+ return;
+ }
+ }
+ if (sp->col < CMlength) {
+ cr();
+ right(sp);
+ return;
+ }
+ /* No more optimizations on same row. */
+ }
+ distance = sp->col - cursor.col;
+ distance = distance > 0 ?
+ distance * NDlength : -distance * BSlength;
+ if (distance < 0)
+ pr("ERROR: distance is negative: %d", distance);
+ distance += abs(sp->line - cursor.line);
+ if (distance >= CMlength) {
+ putpad(cmstr);
+ cursor.line = sp->line;
+ cursor.col = sp->col;
+ return;
+ }
+ }
+ /*
+ * If we get here we have a terminal that can't cursor
+ * address but has local motions or one which can cursor
+ * address but can get there quicker with local motions.
+ */
+ gto(sp);
+}
+
+void
+gto(sp)
+ struct point *sp;
+{
+ int distance, f, tfield;
+
+ if (cursor.line > LINES || cursor.line <0 ||
+ cursor.col <0 || cursor.col > COLUMNS)
+ pr("ERROR: cursor is at %d,%d\n", cursor.line, cursor.col);
+ if (sp->line > LINES || sp->line < 0 || sp->col < 0 || sp->col > COLUMNS)
+ pr("ERROR: target is %d,%d\n", sp->line, sp->col);
+ tfield = (sp->col) >> 3;
+ if (sp->line == cursor.line) {
+ if (sp->col > cursor.col)
+ right(sp);
+ else {
+ distance = (cursor.col - sp->col) * BSlength;
+ if (((TA) && (distance > tfield + ((sp->col) & 7) * NDlength)) ||
+ (((cursor.col)*NDlength) < distance)) {
+ cr();
+ right(sp);
+ } else {
+ while(cursor.col > sp->col)
+ bs();
+ }
+ }
+ return;
+ }
+ /*must change row */
+ if (cursor.col - sp->col > (cursor.col >> 3)) {
+ if (cursor.col == 0)
+ f = 0;
+ else
+ f = -1;
+ }
+ else f = cursor.col >> 3;
+ if (((sp->line << 1) + 1 < cursor.line - f) && (HO != 0)) {
+ /*
+ * home quicker than rlf:
+ * (sp->line + f > cursor.line - sp->line)
+ */
+ putpad(HO);
+ cursor.col = cursor.line = 0;
+ gto(sp);
+ return;
+ }
+ if (((sp->line << 1) > cursor.line + LINES + 1 + f) && (LL != 0)) {
+ /* home,rlf quicker than lf
+ * (LINES+1 - sp->line + f < sp->line - cursor.line)
+ */
+ if (cursor.line > f + 1) {
+ /* is home faster than wraparound lf?
+ * (cursor.line + 20 - sp->line > 21 - sp->line + f)
+ */
+ ll();
+ gto(sp);
+ return;
+ }
+ }
+ if ((LL != 0) && (sp->line > cursor.line + (LINES >> 1) - 1))
+ cursor.line += LINES;
+ while(sp->line > cursor.line)
+ down();
+ while(sp->line < cursor.line)
+ up();
+ gto(sp); /*can recurse since cursor.line = sp->line */
+}
+
+void
+right(sp)
+ struct point *sp;
+{
+ int field, tfield;
+ int tabcol, strlength;
+
+ if (sp->col < cursor.col)
+ pr("ERROR:right() can't move left\n");
+ if (TA) { /* If No Tabs: can't send tabs because ttydrive
+ * loses count with control characters.
+ */
+ field = cursor.col >> 3;
+/*
+ * This code is useful for a terminal which wraps around on backspaces.
+ * (Mine does.) Unfortunately, this is not specified in termcap, and
+ * most terminals don't work that way. (Of course, most terminals
+ * have addressible cursors, too).
+ */
+ if (BW && (CM == 0) &&
+ ((sp->col << 1) - field > (COLUMNS - 8) << 1 )) {
+ if (cursor.line == 0)
+ outch('\n');
+ outch('\r');
+ cursor.col = COLUMNS + 1;
+ while (cursor.col > sp->col)
+ bs();
+ if (cursor.line != 0)
+ outch('\n');
+ return;
+ }
+ tfield = sp->col >> 3;
+
+ while (field < tfield) {
+ putpad(TA);
+ cursor.col = ++field << 3;
+ }
+ tabcol = (cursor.col | 7) + 1;
+ strlength = (tabcol - sp->col) * BSlength + 1;
+ /* length of sequence to overshoot */
+ if (((sp->col - cursor.col) * NDlength > strlength) &&
+ (tabcol < COLUMNS)
+ ){
+ /* Tab past and backup */
+ putpad(TA);
+ cursor.col = (cursor.col | 7) + 1;
+ while(cursor.col > sp->col)
+ bs();
+ }
+ }
+ while (sp->col > cursor.col) {
+ nd();
+ }
+}
+
+void
+cr()
+{
+ outch('\r');
+ cursor.col = 0;
+}
+
+void
+clear()
+{
+ int i;
+
+ if (CL){
+ putpad(CL);
+ cursor.col = cursor.line = 0;
+ } else {
+ for(i=0; i<LINES; i++) {
+ putchar('\n');
+ }
+ cursor.line = LINES - 1;
+ home();
+ }
+}
+
+void
+home()
+{
+ struct point z;
+
+ if (HO != 0) {
+ putpad(HO);
+ cursor.col = cursor.line = 0;
+ return;
+ }
+ z.col = z.line = 0;
+ move(&z);
+}
+
+void
+ll()
+{
+ int l;
+ struct point z;
+
+ l = lcnt + 2;
+ if (LL != NULL && LINES == l) {
+ putpad(LL);
+ cursor.line = LINES - 1;
+ cursor.col = 0;
+ return;
+ }
+ z.col = 0;
+ z.line = l - 1;
+ move(&z);
+}
+
+void
+up()
+{
+ putpad(UP);
+ cursor.line--;
+}
+
+void
+down()
+{
+ putpad(DO);
+ cursor.line++;
+ if (cursor.line >= LINES)
+ cursor.line = LINES - 1;
+}
+
+void
+bs()
+{
+ if (cursor.col > 0) {
+ putpad(BS);
+ cursor.col--;
+ }
+}
+
+void
+nd()
+{
+ putpad(ND);
+ cursor.col++;
+ if (cursor.col == COLUMNS + 1) {
+ cursor.line++;
+ cursor.col = 0;
+ if (cursor.line >= LINES)
+ cursor.line = LINES - 1;
+ }
+}
+
+void
+pch(c)
+ int c;
+{
+ outch(c);
+ if(++cursor.col >= COLUMNS && AM) {
+ cursor.col = 0;
+ ++cursor.line;
+ }
+}
+
+void
+#ifdef __STDC__
+apr(struct point *ps, const char *fmt, ...)
+#else
+apr(ps, fmt, va_alist)
+ struct point *ps;
+ char *fmt;
+ va_dcl
+#endif
+{
+ struct point p;
+ va_list ap;
+
+ p.line = ps->line + 1;
+ p.col = ps->col + 1;
+ move(&p);
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vsprintf(str, fmt, ap);
+ va_end(ap);
+ pstring(str);
+}
+
+void
+#ifdef __STDC__
+pr(const char *fmt, ...)
+#else
+pr(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vsprintf(str, fmt, ap);
+ va_end(ap);
+ pstring(str);
+}
+
+void
+pstring(s)
+ const char *s;
+{
+ struct point z;
+ int stcol;
+
+ stcol = cursor.col;
+ while (s[0] != '\0') {
+ switch (s[0]) {
+ case '\n':
+ move(point(&z, 0, cursor.line + 1));
+ break;
+ case '\r':
+ move(point(&z, stcol, cursor.line + 1));
+ break;
+ case '\t':
+ z.col = (((cursor.col + 8) >> 3) << 3);
+ z.line = cursor.line;
+ move(&z);
+ break;
+ case '\b':
+ bs();
+ break;
+ case CTRL('g'):
+ outch(CTRL('g'));
+ break;
+ default:
+ if (s[0] < ' ')
+ break;
+ pch(s[0]);
+ }
+ s++;
+ }
+}
+
+void
+pchar(ps,ch)
+ struct point *ps;
+ char ch;
+{
+ struct point p;
+
+ p.col = ps->col + 1;
+ p.line = ps->line + 1;
+ if ((p.col >= 0) && (p.line >= 0) &&
+ (((p.line < LINES) && (p.col < COLUMNS)) ||
+ ((p.col == COLUMNS) && (p.line < LINES-1)))) {
+ move(&p);
+ pch(ch);
+ }
+}
+
+int
+outch(c)
+ int c;
+{
+ putchar(c);
+ return(0);
+}
+
+void
+putpad(str)
+ char *str;
+{
+ if (str)
+ tputs(str, 1, outch);
+}
+
+void
+delay(t)
+ int t;
+{
+ useconds_t us;
+ /* This can't depend on terminal timing in light of X */
+
+ us = t * 50000; /* From units of 1/20 s */
+ usleep(us);
+}
+
+void
+cook()
+{
+ delay(1);
+ putpad(TE);
+ putpad(KE);
+ putpad(VE);
+ fflush(stdout);
+ tcsetattr(0, TCSADRAIN, &orig);
+}
+
+void
+raw()
+{
+ tcsetattr(0, TCSADRAIN, &new);
+ putpad(VI);
+}
+
+struct point *
+point(ps, x, y)
+ struct point *ps;
+ int x, y;
+{
+ ps->col = x;
+ ps->line = y;
+ return(ps);
+}
+
+void
+getcap()
+{
+ char *ap;
+ char *term;
+ char *xPC;
+#ifdef TIOCGWINSZ
+ struct winsize win;
+#endif
+
+ term = getenv("TERM");
+ if (term == 0)
+ errx(1, "No TERM in environment");
+ switch (tgetent(tbuf, term)) {
+ case -1:
+ errx(2, "Cannot open termcap file");
+ case 0:
+ errx(3, "unknown terminal `%s'", term);
+ }
+
+ ap = tcapbuf;
+
+#ifdef TIOCGWINSZ
+ if (ioctl(0, TIOCGWINSZ, (char *) &win) < 0 ||
+ (LINES = win.ws_row) == 0 || (COLUMNS = win.ws_col) == 0) {
+#endif
+ LINES = tgetnum("li");
+ COLUMNS = tgetnum("co");
+#ifdef TIOCGWINSZ
+ }
+#endif
+ if (!lcnt)
+ lcnt = LINES - 2;
+ if (!ccnt)
+ ccnt = COLUMNS - 3;
+ /* make sure user didn't specify a screen larger than he has */
+ if (lcnt > LINES - 2)
+ lcnt = LINES - 2;
+ if (ccnt > COLUMNS - 3)
+ ccnt = COLUMNS - 3;
+
+ AM = tgetflag("am");
+ BW = tgetflag("bw");
+
+ ND = tgetstr("nd", &ap);
+ UP = tgetstr("up", &ap);
+
+ DO = tgetstr("do", &ap);
+ if (DO == 0)
+ DO = "\n";
+
+ BS = tgetstr("le", &ap);
+ if (BS == 0) {
+ /* try using obsolete capabilities */
+ BS = tgetstr("bc", &ap);
+ if (BS == 0 && tgetflag("bs"))
+ BS = "\b";
+ }
+ TA = tgetstr("ta", &ap);
+ if (TA == 0 && tgetflag("pt"))
+ TA = "\t";
+
+ HO = tgetstr("ho", &ap);
+ CL = tgetstr("cl", &ap);
+ CM = tgetstr("cm", &ap);
+ LL = tgetstr("ll", &ap);
+
+ KL = tgetstr("kl", &ap);
+ KR = tgetstr("kr", &ap);
+ KU = tgetstr("ku", &ap);
+ KD = tgetstr("kd", &ap);
+ if (KL && KR && KU && KD)
+ Klength = strlen(KL);
+ else
+ Klength = 0;
+ /* NOTE: If KL, KR, KU, and KD are not
+ * all the same length, some problems
+ * may arise, since tests are made on
+ * all of them together.
+ */
+
+ TI = tgetstr("ti", &ap);
+ TE = tgetstr("te", &ap);
+ KS = tgetstr("ks", &ap);
+ KE = tgetstr("ke", &ap);
+ VE = tgetstr("ve", &ap);
+ VI = tgetstr("vi", &ap);
+
+ xPC = tgetstr("pc", &ap);
+ if (xPC)
+ PC = *xPC;
+
+ if ((CM == 0) &&
+ (HO == 0 || UP == 0 || BS == 0 || ND == 0))
+ errx(5, "Terminal must have addressable cursor or home + 4 local motions");
+ if (ND == 0)
+ errx(5, "Terminal must have `nd' capability");
+ NDlength = strlen(ND);
+ if (BS == 0)
+ errx(5, "Terminal must have `le' or `bs' or `bc' capability");
+ BSlength = strlen(BS);
+ if (tgetflag("os"))
+ errx(5, "Terminal must not overstrike");
+ if (LINES <= 0 || COLUMNS <= 0)
+ errx(5, "Must know the screen size");
+
+ tcgetattr(0, &orig);
+ new = orig;
+ new.c_lflag &= ~(ECHO | ICANON);
+ new.c_oflag &= ~(ONLCR | OXTABS);
+ signal(SIGINT, stop);
+ ospeed = cfgetospeed(&orig);
+ new.c_cc[VSUSP] = _POSIX_VDISABLE;
+ new.c_cc[VDSUSP] = _POSIX_VDISABLE;
+ raw();
+
+ if (orig.c_oflag & OXTABS)
+ TA=0;
+ putpad(KS);
+ putpad(TI);
+ point(&cursor, 0, LINES - 1);
+}