date and time created 87/10/22 11:37:41 by bostic
[unix-history] / usr / src / games / snake / snake / move.c
CommitLineData
b6f0a7e4
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
c44a1e93 7#ifndef lint
b6f0a7e4
DF
8static char sccsid[] = "@(#)move.c 5.1 (Berkeley) %G%";
9#endif not lint
c44a1e93
SL
10
11/*************************************************************************
12 *
13 * MOVE LIBRARY
14 *
15 * This set of subroutines moves a cursor to a predefined
16 * location, independent of the terminal type. If the
17 * terminal has an addressable cursor, it uses it. If
18 * not, it optimizes for tabs (currently) even if you don't
19 * have them.
20 *
21 * At all times the current address of the cursor must be maintained,
22 * and that is available as structure cursor.
23 *
24 * The following calls are allowed:
25 * move(sp) move to point sp.
26 * up() move up one line.
27 * down() move down one line.
28 * bs() move left one space (except column 0).
29 * nd() move right one space(no write).
30 * clear() clear screen.
31 * home() home.
32 * ll() move to lower left corner of screen.
33 * cr() carriage return (no line feed).
34 * printf() just like standard printf, but keeps track
35 * of cursor position. (Uses pstring).
36 * aprintf() same as printf, but first argument is &point.
37 * (Uses pstring).
38 * pstring(s) output the string of printing characters.
39 * However, '\r' is interpreted to mean return
40 * to column of origination AND do linefeed.
41 * '\n' causes <cr><lf>.
42 * putpad(str) calls tputs to output character with proper
43 * padding.
44 * outch() the output routine for a character used by
45 * tputs. It just calls putchar.
46 * pch(ch) output character to screen and update
47 * cursor address (must be a standard
48 * printing character). WILL SCROLL.
49 * pchar(ps,ch) prints one character if it is on the
50 * screen at the specified location;
51 * otherwise, dumps it.(no wrap-around).
52 *
53 * getcap() initializes strings for later calls.
54 * cap(string) outputs the string designated in the termcap
55 * data base. (Should not move the cursor.)
56 * done(int) returns the terminal to intial state. If int
57 * is not 0, it exits.
58 *
59 * same(&p1,&p2) returns 1 if p1 and p2 are the same point.
60 * point(&p,x,y) return point set to x,y.
61 *
62 * baudrate(x) returns the baudrate of the terminal.
63 * delay(t) causes an approximately constant delay
64 * independent of baudrate.
65 * Duration is ~ t/20 seconds.
66 *
67 ******************************************************************************/
68
69#include "snake.h"
70
71int CMlength;
72int NDlength;
73int BSlength;
74int delaystr[10];
75short ospeed;
76
77static char str[80];
78
79move(sp)
80struct point *sp;
81{
82 int distance;
83 int tabcol,ct;
84 struct point z;
85
86 if (sp->line <0 || sp->col <0 || sp->col > COLUMNS){
87 printf("move to [%d,%d]?",sp->line,sp->col);
88 return;
89 }
90 if (sp->line >= LINES){
91 move(point(&z,sp->col,LINES-1));
92 while(sp->line-- >= LINES)putchar('\n');
93 return;
94 }
95
96 if (CM != 0) {
97 char *cmstr = tgoto(CM, sp->col, sp->line);
98
99 CMlength = strlen(cmstr);
100 if(cursor.line == sp->line){
101 distance = sp->col - cursor.col;
102 if(distance == 0)return; /* Already there! */
103 if(distance > 0){ /* Moving to the right */
104 if(distance*NDlength < CMlength){
105 right(sp);
106 return;
107 }
108 if(TA){
109 ct=sp->col&7;
110 tabcol=(cursor.col|7)+1;
111 do{
112 ct++;
113 tabcol=(tabcol|7)+1;
114 }
115 while(tabcol<sp->col);
116 if(ct<CMlength){
117 right(sp);
118 return;
119 }
120 }
121 } else { /* Moving to the left */
122 if (-distance*BSlength < CMlength){
123 gto(sp);
124 return;
125 }
126 }
127 if(sp->col < CMlength){
128 cr();
129 right(sp);
130 return;
131 }
132 /* No more optimizations on same row. */
133 }
134 distance = sp->col - cursor.col;
135 distance = distance > 0 ?
136 distance*NDlength : -distance * BSlength;
137if(distance < 0)printf("ERROR: distance is negative: %d",distance);
138 distance += abs(sp->line - cursor.line);
139 if(distance >= CMlength){
140 putpad(cmstr);
141 cursor.line = sp->line;
142 cursor.col = sp->col;
143 return;
144 }
145 }
146
147 /*
148 * If we get here we have a terminal that can't cursor
149 * address but has local motions or one which can cursor
150 * address but can get there quicker with local motions.
151 */
152 gto(sp);
153}
154gto(sp)
155struct point *sp;
156{
157
158 int distance,f,tfield,j;
159
160 if (cursor.line > LINES || cursor.line <0 ||
161 cursor.col <0 || cursor.col > COLUMNS)
162 printf("ERROR: cursor is at %d,%d\n",
163 cursor.line,cursor.col);
164 if (sp->line > LINES || sp->line <0 ||
165 sp->col <0 || sp->col > COLUMNS)
166 printf("ERROR: target is %d,%d\n",sp->line,sp->col);
167 tfield = (sp->col) >> 3;
168 if (sp->line == cursor.line){
169 if (sp->col > cursor.col)right(sp);
170 else{
171 distance = (cursor.col -sp->col)*BSlength;
172 if (((TA) &&
173 (distance > tfield+((sp->col)&7)*NDlength)
174 ) ||
175 (((cursor.col)*NDlength) < distance)
176 ){
177 cr();
178 right(sp);
179 }
180 else{
181 while(cursor.col > sp->col) bs();
182 }
183 }
184 return;
185 }
186 /*must change row */
187 if (cursor.col - sp->col > (cursor.col >> 3)){
188 if (cursor.col == 0)f = 0;
189 else f = -1;
190 }
191 else f = cursor.col >> 3;
192 if (((sp->line << 1) + 1 < cursor.line - f) && (HO != 0)){
193 /*
194 * home quicker than rlf:
195 * (sp->line + f > cursor.line - sp->line)
196 */
197 putpad(HO);
198 cursor.col = cursor.line = 0;
199 gto(sp);
200 return;
201 }
202 if (((sp->line << 1) > cursor.line + LINES+1 + f) && (LL != 0)){
203 /* home,rlf quicker than lf
204 * (LINES+1 - sp->line + f < sp->line - cursor.line)
205 */
206 if (cursor.line > f + 1){
207 /* is home faster than wraparound lf?
208 * (cursor.line + 20 - sp->line > 21 - sp->line + f)
209 */
210 ll();
211 gto(sp);
212 return;
213 }
214 }
215 if ((LL != 0) && (sp->line > cursor.line + (LINES >> 1) - 1))
216 cursor.line += LINES;
217 while(sp->line > cursor.line)down();
218 while(sp->line < cursor.line)up();
219 gto(sp); /*can recurse since cursor.line = sp->line */
220}
221
222right(sp)
223struct point *sp;
224{
225 int field,tfield;
226 int tabcol,strlength;
227
228 if (sp->col < cursor.col)
229 printf("ERROR:right() can't move left\n");
230 if(TA){ /* If No Tabs: can't send tabs because ttydrive
231 * loses count with control characters.
232 */
233 field = cursor.col >> 3;
234/*
235 * This code is useful for a terminal which wraps around on backspaces.
236 * (Mine does.) Unfortunately, this is not specified in termcap, and
237 * most terminals don't work that way. (Of course, most terminals
238 * have addressible cursors, too).
239 */
240 if (BW && (CM == 0) &&
241 ((sp->col << 1) - field > (COLUMNS - 8) << 1 )
242 ){
243 if (cursor.line == 0){
244 outch('\n');
245 }
246 outch('\r');
247 cursor.col = COLUMNS + 1;
248 while(cursor.col > sp->col)bs();
249 if (cursor.line != 0) outch('\n');
250 return;
251 }
252
253 tfield = sp->col >> 3;
254
255 while (field < tfield){
256 putpad(TA);
257 cursor.col = ++field << 3;
258 }
259 tabcol = (cursor.col|7) + 1;
260 strlength = (tabcol - sp->col)*BSlength + 1;
261 /* length of sequence to overshoot */
262 if (((sp->col - cursor.col)*NDlength > strlength) &&
263 (tabcol < COLUMNS)
264 ){
265 /*
266 * Tab past and backup
267 */
268 putpad(TA);
269 cursor.col = (cursor.col | 7) + 1;
270 while(cursor.col > sp->col)bs();
271 }
272 }
273 while (sp->col > cursor.col){
274 nd();
275 }
276}
277
278cr(){
279 outch('\r');
280 cursor.col = 0;
281}
282
283clear(){
284 int i;
285
286 if (CL){
287 putpad(CL);
288 cursor.col=cursor.line=0;
289 } else {
290 for(i=0; i<LINES; i++) {
291 putchar('\n');
292 }
293 cursor.line = LINES - 1;
294 home();
295 }
296}
297
298home(){
299 struct point z;
300
301 if(HO != 0){
302 putpad(HO);
303 cursor.col = cursor.line = 0;
304 return;
305 }
306 z.col = z.line = 0;
307 move(&z);
308}
309
310ll(){
311 int j,l;
312 struct point z;
313
314 l = lcnt + 2;
315 if(LL != NULL && LINES==l){
316 putpad(LL);
317 cursor.line = LINES-1;
318 cursor.col = 0;
319 return;
320 }
321 z.col = 0;
322 z.line = l-1;
323 move(&z);
324}
325
326up(){
327 putpad(UP);
328 cursor.line--;
329}
330
331down(){
332 putpad(DO);
333 cursor.line++;
334 if (cursor.line >= LINES)cursor.line=LINES-1;
335}
336bs(){
337 if (cursor.col > 0){
338 putpad(BS);
339 cursor.col--;
340 }
341}
342
343nd(){
344 putpad(ND);
345 cursor.col++;
346 if (cursor.col == COLUMNS+1){
347 cursor.line++;
348 cursor.col = 0;
349 if (cursor.line >= LINES)cursor.line=LINES-1;
350 }
351}
352
353pch(c)
354{
355 outch(c);
356 if(++cursor.col >= COLUMNS && AM) {
357 cursor.col = 0;
358 ++cursor.line;
359 }
360}
361
362aprintf(ps,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9)
363struct point *ps;
364char *st;
365int v0,v1,v2,v3,v4,v5,v6,v7,v8,v9;
366
367{
368 struct point p;
369
370 p.line = ps->line+1; p.col = ps->col+1;
371 move(&p);
372 sprintf(str,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9);
373 pstring(str);
374}
375
376printf(st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9)
377char *st;
378int v0,v1,v2,v3,v4,v5,v6,v7,v8,v9;
379{
380 sprintf(str,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9);
381 pstring(str);
382}
383
384pstring(s)
385char *s;{
386 struct point z;
387 int stcol;
388
389 stcol = cursor.col;
390 while (s[0] != '\0'){
391 switch (s[0]){
392 case '\n':
393 move(point(&z,0,cursor.line+1));
394 break;
395 case '\r':
396 move(point(&z,stcol,cursor.line+1));
397 break;
398 case '\t':
399 z.col = (((cursor.col + 8) >> 3) << 3);
400 z.line = cursor.line;
401 move(&z);
402 break;
403 case '\b':
404 bs();
405 break;
406 case CTRL(g):
407 outch(CTRL(g));
408 break;
409 default:
410 if (s[0] < ' ')break;
411 pch(s[0]);
412 }
413 s++;
414 }
415}
416
417pchar(ps,ch)
418struct point *ps;
419char ch;{
420 struct point p;
421 p.col = ps->col + 1; p.line = ps->line + 1;
422 if (
423 (p.col >= 0) &&
424 (p.line >= 0) &&
425 (
426 (
427 (p.line < LINES) &&
428 (p.col < COLUMNS)
429 ) ||
430 (
431 (p.col == COLUMNS) &&
432 (p.line < LINES-1)
433 )
434 )
435 ){
436 move(&p);
437 pch(ch);
438 }
439}
440
441
442outch(c)
443{
444 putchar(c);
445}
446
447putpad(str)
448char *str;
449{
450 if (str)
451 tputs(str, 1, outch);
452}
453baudrate()
454{
455
456 switch (orig.sg_ospeed){
457 case B300:
458 return(300);
459 case B1200:
460 return(1200);
461 case B4800:
462 return(4800);
463 case B9600:
464 return(9600);
465 default:
466 return(0);
467 }
468}
469delay(t)
470int t;
471{
472 int k,j;
473
474 k = baudrate() * t / 300;
475 for(j=0;j<k;j++){
476 putchar(PC);
477 }
478}
479
480done()
481{
482 cook();
483 exit(0);
484}
485
486cook()
487{
488 delay(1);
489 putpad(TE);
490 putpad(KE);
491 fflush(stdout);
492 stty(0, &orig);
493#ifdef TIOCSLTC
494 ioctl(0, TIOCSLTC, &olttyc);
495#endif
496}
497
498raw()
499{
500 stty(0, &new);
501#ifdef TIOCSLTC
502 ioctl(0, TIOCSLTC, &nlttyc);
503#endif
504}
505
506same(sp1,sp2)
507struct point *sp1, *sp2;
508{
509 if ((sp1->line == sp2->line) && (sp1->col == sp2->col))return(1);
510 return(0);
511}
512
513struct point *point(ps,x,y)
514struct point *ps;
515int x,y;
516{
517 ps->col=x;
518 ps->line=y;
519 return(ps);
520}
521
522char *ap;
523
524getcap()
525{
526 char *getenv();
527 char *term;
528 char *xPC;
529 struct point z;
530 int stop();
531
532 term = getenv("TERM");
533 if (term==0) {
534 fprintf(stderr, "No TERM in environment\n");
535 exit(1);
536 }
537
538 switch (tgetent(tbuf, term)) {
539 case -1:
540 fprintf(stderr, "Cannot open termcap file\n");
541 exit(2);
542 case 0:
543 fprintf(stderr, "%s: unknown terminal", term);
544 exit(3);
545 }
546
547 ap = tcapbuf;
548
549 LINES = tgetnum("li");
550 COLUMNS = tgetnum("co");
551 lcnt = LINES;
552 ccnt = COLUMNS - 1;
553
554 AM = tgetflag("am");
555 BW = tgetflag("bw");
556
557 ND = tgetstr("nd", &ap);
558 UP = tgetstr("up", &ap);
559
560 DO = tgetstr("do", &ap);
561 if (DO == 0)
562 DO = "\n";
563
564 BS = tgetstr("bc", &ap);
565 if (BS == 0 && tgetflag("bs"))
566 BS = "\b";
567 if (BS)
568 xBC = *BS;
569
570 TA = tgetstr("ta", &ap);
571 if (TA == 0 && tgetflag("pt"))
572 TA = "\t";
573
574 HO = tgetstr("ho", &ap);
575 CL = tgetstr("cl", &ap);
576 CM = tgetstr("cm", &ap);
577 LL = tgetstr("ll", &ap);
578
579 KL = tgetstr("kl", &ap);
580 KR = tgetstr("kr", &ap);
581 KU = tgetstr("ku", &ap);
582 KD = tgetstr("kd", &ap);
583 Klength = strlen(KL);
584 /* NOTE: If KL, KR, KU, and KD are not
585 * all the same length, some problems
586 * may arise, since tests are made on
587 * all of them together.
588 */
589
590 TI = tgetstr("ti", &ap);
591 TE = tgetstr("te", &ap);
592 KS = tgetstr("ks", &ap);
593 KE = tgetstr("ke", &ap);
594
595 xPC = tgetstr("pc", &ap);
596 if (xPC)
597 PC = *xPC;
598
599 NDlength = strlen(ND);
600 BSlength = strlen(BS);
601 if ((CM == 0) &&
602 (HO == 0 | UP==0 || BS==0 || ND==0)) {
603 fprintf(stderr, "Terminal must have addressible ");
604 fprintf(stderr, "cursor or home + 4 local motions\n");
605 exit(5);
606 }
607 if (tgetflag("os")) {
608 fprintf(stderr, "Terminal must not overstrike\n");
609 exit(5);
610 }
611 if (LINES <= 0 || COLUMNS <= 0) {
612 fprintf(stderr, "Must know the screen size\n");
613 exit(5);
614 }
615
616 gtty(0, &orig);
617 new=orig;
618 new.sg_flags &= ~(ECHO|CRMOD|ALLDELAY|XTABS);
619 new.sg_flags |= CBREAK;
620 signal(SIGINT,stop);
621 ospeed = orig.sg_ospeed;
622#ifdef TIOCGLTC
623 ioctl(0, TIOCGLTC, &olttyc);
624 nlttyc = olttyc;
625 nlttyc.t_suspc = '\377';
626 nlttyc.t_dsuspc = '\377';
627#endif
628 raw();
629
630 if ((orig.sg_flags & XTABS) == XTABS) TA=0;
631 putpad(KS);
632 putpad(TI);
633 point(&cursor,0,LINES-1);
634}