'===========================================================================
' Subject: SNAKE GAME FOR RAPID-Q             Date: 07-25-00 (15:29)       
'  Author: Colin Breame                       Code: RAPIDQ                 
'  Origin: colin.breame@uk.worldplay.com    Packet: RAPIDQ.ABC
'===========================================================================
'  snake.bas
' SnakeV1 was written by Colin Breame for fun
' Controls:
'	' = up
'	/ = down
'	z = left
'	x = right
'
' The keyboard is not very responsive because
' the inkey$ method does not buffer the last character pressed
' i.e. you must have the key depressed when it checks (I think)
'
' Send comments/seguestions to colinbreame@hotmail.com

$TYPECHECK ON


' Def for the app
DIM borderChar AS STRING
dim snakeChar as string
DIM screenX as integer
dim screenY as integer

' Border character
borderChar = "#"
snakeChar = "+"
screenX = 78
screenY = 23

' Subrountines
DECLARE SUB drawBorder
declare sub initSnake
declare sub moveSnake
declare sub updateFrame
declare sub checkForCol
declare sub calcNewPosition
declare sub makeFood
declare sub removeListTail
declare sub addListHead
declare sub initList
declare sub updateFrame
declare sub handleInput



' Variables
' Whether were still alive
'	0 = alive
'	1 = dead
dim snakeDead as integer
' The snake head
dim headX as integer
dim headY as integer
' How long our snake is
dim size as integer
' And what direction weve moving in
'	0 = north
'	1 = east
'	2 = south
'	3 = west
dim dir as integer


' List of snake segments
dim segX(256) as integer
dim segY(256) as integer
dim listLen as integer
listLen = 256

dim nextElement as integer
dim baseElement as integer
dim numOfElements as integer


' Where the food is
dim foodVal as integer


CLS
RANDOMIZE TIMER

' Draw the border
call drawBorder
' initialise the snake
call initSnake

' Make some food
call makeFood

' Initialise the list of segments
call initList
call addListHead

' Setup our timer
dim interval as integer
interval = 250

dim timer1 as QTimer
timer1.Interval = interval
timer1.Enabled = 1
timer1.OnTimer = updateFrame

' Used for input
dim lastInput as string
dim newInput as string

' Now loop
do
	lastInput = lastInput + inkey$
	doevents
loop until snakeDead = 1


sub updateFrame
	call moveSnake
	if snakeDead = 0 then timer1.Interval = interval
end sub



' Moves the snake
sub moveSnake
	call handleInput
	call calcNewPosition
	call checkForCol
	call updateFrame
	if numOfElements>size then call removeListTail
end sub

' Handles user input
sub handleInput
	SELECT CASE right$(lastInput, 1)
		CASE "/"
			dir = 2
		CASE "'"
			dir = 0
		CASE "x"
			dir = 1
		CASE "z"
			dir = 3
	END SELECT
	lastInput = ""
end sub


' Updates this frame
sub updateFrame
	locate headY, headX
	print snakeChar
	
	locate segY(baseElement), segX(baseElement)
	print " "
end sub

' Checks for a collition against walls or snake
sub checkForCol
	dim c as string
	c = CHR$(PEEK((headY-1)*160+(headX-1)*2))

	if c = borderChar or c = snakeChar then snakeDead = 1
	
	if asc(c) > 48 and asc(c) <= 57 then 
		size = size + foodVal
		interval = interval - (foodVal*2)
		call makeFood
	end if
end sub

' Calculates the snakes new position (of head)
sub calcNewPosition
	if dir = 0 then	headY = headY-1 _
	else if dir = 1 then headX = headX+1 _
	else if dir = 2 then headY = headY+1 _
	else if dir = 3 then headX = headX-1

	' Add this new position to the list of snake segments
	call addListHead
end sub


' Initialises our snake
sub initSnake
	headX = screenX/2
	headY = screenY/2
	size = 1
	dir = rnd(4)
	snakeDead = 0
end sub

' Makes some food
sub makeFood
	foodVal = rnd(9)+1
	locate rnd(screenY-2)+2, rnd(screenX-2)+2
	print foodVal
end sub

' Draws the borders around the edge of the screen
SUB drawBorder
	DIM i as Integer

	for i=1 to screenX
		locate 1, i
		print borderChar
		locate screenY, i
		print borderChar
	next

	for i=1 to screenY
		locate i, 1
		print borderChar
		locate i, screenX
		print borderChar
	next
END SUB


' Rotary list methods

' Initialise the list
sub initList
	nextElement = 0
	baseElement = 0
end sub

' Add head
sub addListHead
	segX(nextElement) = headX
	segY(nextElement) = headY

	nextElement = nextElement + 1
	if (nextElement>listLen) then nextElement = nextElement-listLen
	numOfElements = numOfElements + 1
end sub

' Remove tail
sub removeListTail
	baseElement = baseElement + 1
	if (baseElement>listLen) then baseElement = baseElement-listLen
	numOfElements = numOfElements - 1
end sub
