home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v941.tgz
/
icon.v941src.tar
/
icon.v941src
/
ipl
/
progs
/
snake.icn
< prev
next >
Wrap
Text File
|
2002-03-26
|
6KB
|
249 lines
############################################################################
#
# File: snake.icn
#
# Subject: Program to play the snake game
#
# Author: Richard L. Goerwitz
#
# Date: March 26, 2002
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# Version: 1.9
#
############################################################################
#
# While away the idle moments watching the snake eat blank squares
# on your screen. Snake has only one (optional) argument -
#
# usage: snake [character]
#
# where "character" represents a single character to be used in drawing
# the snake. The default is an "o." In order to run snake, your ter-
# minal must have cursor movement capability, and must be able to do re-
# verse video.
#
# I wrote this program to test itlib.icn, iscreen.icn, and some
# miscellaneous utilities I wrote. It clears the screen, moves the cur-
# sor to arbitrary squares on the screen, changes video mode, and in
# general exercises the terminal capability database on the target ma-
# chine.
#
############################################################################
#
# Bugs: Most magic cookie terminals just won't work. Terminal really
# needs reverse video (it will work without, but won't look as cute).
#
############################################################################
#
# Requires: UNIX (MS-DOS is okay, if you replace itlib with itlibdos.icn)
#
############################################################################
#
# Links: itlib, iscreen, random
#
############################################################################
link itlib
link iscreen
link random
global max_l, max_w, snake_char
record wholething(poop,body)
procedure main(a)
local snake, limit, sl, sw, CM, x, r, leftbehind
randomize()
if not (getval("so"), CM := getval("cm"))
then stop("snake: Your terminal is too stupid to run me. Sorry.")
clear(); Kludge() # if your term likes it, use emphasize(); clear()
# Decide how much space we have to operate in.
max_l := getval("li")-2 # global
max_w := getval("co")-1 # global
# Determine the character that will be used to represent the snake.
snake_char := (\a[1])[1] | "o"
# Make the head.
snake := []; put(snake,[?(max_l-1)+1, ?(max_w-1)+1])
# Make the body, displaying it as it grows.
every x := 2 to 25 do {
display(,snake)
put(snake,findnext(snake[x-1],snake))
}
# Begin "eating" all the standout mode spaces on the screen.
repeat {
r := makenew(snake)
leftbehind := r.poop
snake := r.body
display(leftbehind,snake) | break
}
# Shrink the snake down to nothing, displaying successively smaller bits.
while leftbehind := get(snake)
do display(leftbehind,snake)
iputs(igoto(getval("cm"), 1, getval("li")-1))
normal()
end
procedure findnext(L, snake)
local i, j, k, op, l
static sub_lists
initial {
sub_lists := [[1,2,3], [1,3,2], [3,2,1], [3,1,2], [2,1,3], [2,3,1]]
}
# global max_l, max_w
i := L[1]; j := L[2] # for clarity, use i, j (not l[i|j])
# L is the last snake segment; find k and l, such that k and l are
# valid line and column numbers differing from l[1] and l[2] by no
# more than 1, respectively. Put simply: Create a new segment
# [k, l] adjacent to the last one (L).
op := (different | Null) &
(k := max_l+1 > [i,i+1,i-1][!sub_lists[?6]]) > 1 &
(l := max_w+1 > [j,j+1,j-1][!sub_lists[?6]]) > 1 &
op([k, l], snake)
return [k, l]
end
procedure different(l,snake)
local bit
(l[1] = (bit := !\snake)[1], l[2] = bit[2]) & fail
return
end
procedure Null(a[])
return
end
procedure display(lb,snake)
local last_segment, character
static CM
initial CM := getval("cm")
# Change the mode of the square just "vacated" by the moving snake.
if *snake = 0 | different(\lb,snake) then {
iputs(igoto(CM, lb[2], lb[1]))
normal()
writes(" ")
}
if last_segment := (0 ~= *snake) then {
# Write the last segment (which turns out to be the snakes head!).
iputs(igoto(CM, snake[last_segment][2], snake[last_segment][1]))
emphasize(); writes(snake_char) # snake_char is global
}
# Check to see whether we've eaten every edible square on the screen.
if done_yet(lb)
then fail
else return
end
procedure makenew(snake)
local leftbehind, i
# Move each constituent list up one position in snake, discard
# the first element, and tack a new one onto the end.
every i := 1 to *snake - 1 do
snake[i] :=: snake[i+1]
leftbehind := copy(snake[i+1])
snake[i+1] := findnext(snake[i],snake)
return wholething(leftbehind,snake)
end
procedure the_same(l1, l2)
if l1[1] = l2[1] & l1[2] = l2[2]
then return else fail
end
procedure done_yet(l)
local i, j
# Check to see if we've eaten every edible square on the screen.
# It's easy for snake to screw up on this one, since somewhere
# along the line most terminal/driver/line combinations will con-
# spire to drop a character somewhere along the line.
static square_set
initial {
square_set := set()
every i := 2 to max_l do {
every j := 2 to max_w do {
insert(square_set, i*j)
}
}
}
/l & fail
delete(square_set, l[1]*l[2])
if *square_set = 0 then return
else fail
end
procedure Kludge()
local i
# Horrible way of clearing the screen to all reverse-video, but
# the only apparent way we can do it "portably" using the termcap
# capability database.
iputs(igoto(getval("cm"),1,1))
if getval("am") then {
emphasize()
every 1 to (getval("li")-1) * getval("co") do
writes(" ")
}
else {
every i := 1 to getval("li")-1 do {
iputs(igoto(getval("cm"), 1, i))
emphasize()
writes(repl(" ",getval("co")))
}
}
iputs(igoto(getval("cm"),1,1))
end