

 This page uses content from Wikipedia. The original article was at Snake_(video_game). The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)


Snake is a game where the player maneuvers a line which grows in length every time the snake reaches a food source.



Task
Implement a variant of the Snake game, in any interactive environment, in which a sole player attempts to eat items by running into them with the head of the snake.

Each item eaten makes the snake longer and a new item is randomly generated somewhere else on the plane.

The game ends when the snake attempts to eat himself.




constant W = 60, H = 30, MAX_LEN = 600
enum NORTH, EAST, SOUTH, WEST
 
sequence board, snake
bool alive
integer tailIdx, headIdx, hdX, hdY, d, points
 
procedure createField()
    clear_screen()
    board = repeat("+"&repeat(' ',W-2)&'+',H)
    for x=1 to W do
        board[1,x] = '+'
    end for
    board[H] = board[1]
    board[1+rand(H-2),1+rand(W-2)] = '@';
    snake = repeat(0,MAX_LEN)
    board[3,4] = '#'; tailIdx = 1; headIdx = 5;
    for c=tailIdx to headIdx do
        snake[c] = {3,3+c}
    end for
    {hdY,hdX} = snake[headIdx-1]; d = EAST; points = 0;
end procedure
 
procedure drawField()
    for y=1 to H do
        for x=1 to W do
            integer t = board[y,x]
            if t!=' ' then
                position(y,x)
                if x=hdX and y=hdY then
                    text_color(14); puts(1,'O');
                else
                    text_color({10,9,12}[find(t,"#+@")]); puts(1,t);
                end if
            end if
        end for
    end for
    position(H+1,1); text_color(7); printf(1,"Points: %d",points)
end procedure
 
procedure readKey()
    integer k = find(get_key(),{333,331,328,336})
    if k then d = {EAST,WEST,NORTH,SOUTH}[k] end if
end procedure
 
procedure moveSnake()
integer x,y
    switch d do
        case NORTH: hdY -= 1
        case EAST:  hdX += 1
        case SOUTH: hdY += 1
        case WEST:  hdX -= 1
    end switch
    integer t = board[hdY,hdX];
    if t!=' ' and t!='@' then alive = false; return; end if
    board[hdY,hdX] = '#'; snake[headIdx] = {hdY,hdX};
    headIdx += 1; if headIdx>MAX_LEN then headIdx = 1 end if
    if t=='@' then
        points += 1
        while 1 do
            x = 1+rand(W-2); y = 1+rand(H-2);
            if board[y,x]=' ' then
                board[y,x] = '@'
                return
            end if
        end while
    end if
    {y,x} = snake[tailIdx]; position(y,x); puts(1,' '); board[y,x] = ' ';
    tailIdx += 1; if tailIdx>MAX_LEN then tailIdx = 1 end if
end procedure
 
procedure play()
    while true do
        createField(); alive = true; cursor(NO_CURSOR)
        while alive do drawField(); readKey(); moveSnake(); sleep(0.05) end while
        cursor(BLOCK_CURSOR); position(H+2,1); bk_color(0); text_color(11);
        puts(1,"Play again [Y/N]? ")
        if upper(wait_key())!='Y' then return end if
    end while
end procedure
play()