Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
3
Task/Snake/00-META.yaml
Normal file
3
Task/Snake/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Snake
|
||||
note: Games
|
||||
12
Task/Snake/00-TASK.txt
Normal file
12
Task/Snake/00-TASK.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<br><br>
|
||||
[[wp:Snake_(video_game)|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.
|
||||
<br><br>
|
||||
|
||||
288
Task/Snake/Ada/snake.ada
Normal file
288
Task/Snake/Ada/snake.ada
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
-- This code is a basic implementation of snake in Ada using the command prompt
|
||||
-- feel free to improve it!
|
||||
|
||||
-- Snake.ads
|
||||
with Ada.Containers; use Ada.Containers;
|
||||
with Ada.Containers.Vectors;
|
||||
|
||||
package Snake is
|
||||
|
||||
-- copy from 2048 game (
|
||||
-- Keyboard management
|
||||
type directions is (Up, Down, Right, Left, Quit, Restart, Invalid);
|
||||
|
||||
-- Redefining this standard procedure as function to allow Get_Keystroke as an expression function
|
||||
function Get_Immediate return Character;
|
||||
|
||||
Arrow_Prefix : constant Character := Character'Val(224); -- works for windows
|
||||
|
||||
function Get_Keystroke return directions;
|
||||
-- )
|
||||
|
||||
-- The container for game data
|
||||
type gameBoard is array (Natural range <>, Natural range <>) of Character;
|
||||
|
||||
-- Initilize the board
|
||||
procedure init;
|
||||
|
||||
-- Run the game
|
||||
procedure run;
|
||||
|
||||
-- Displaying the board
|
||||
procedure Display_Board;
|
||||
-- Clear the board from content
|
||||
procedure ClearBoard;
|
||||
|
||||
-- coordinates data structure
|
||||
type coord is tagged record
|
||||
X,Y : Integer;
|
||||
end record;
|
||||
|
||||
-- list of coordinate (one coordinate for each body part of the snake)
|
||||
package snakeBody is new Ada.Containers.Vectors (Natural, coord);
|
||||
use snakeBody;
|
||||
|
||||
-- update snake's part depending on the snakeDirection and checking colicion (with borders and snak's part)
|
||||
function moveSnake return Boolean;
|
||||
|
||||
-- generate food if it was eaten
|
||||
procedure generateFood;
|
||||
|
||||
-- Add snake and food to the board
|
||||
procedure addDataToBoard;
|
||||
|
||||
-- generate random integer between 1 and upperBound to generate random food position
|
||||
function getRandomInteger(upperBound : Integer) return Integer;
|
||||
|
||||
private
|
||||
|
||||
width, height : Positive := 10;
|
||||
board : gameBoard := (0 .. (width+1) => (0 .. (height+1) => ' '));
|
||||
snake : Vector := (1,1) & (2,1) & (3,1);
|
||||
snakeDirection : directions := Right;
|
||||
|
||||
food : coord := (5,5);
|
||||
|
||||
end Snake;
|
||||
|
||||
|
||||
-- Snake.adb
|
||||
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
with Ada.Numerics.Discrete_Random;
|
||||
|
||||
package body Snake is
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Redefining this standard procedure as function to allow Get_Keystroke as an expression function (copy from 2048 game)
|
||||
function Get_Immediate return Character is
|
||||
begin
|
||||
return Answer : Character do Ada.Text_IO.Get_Immediate(Answer);
|
||||
end return;
|
||||
end Get_Immediate;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- (copy from 2048 game)
|
||||
function Get_Keystroke return directions is
|
||||
(case Get_Immediate is
|
||||
when 'Q' | 'q' => Quit,
|
||||
when 'R' | 'r' => Restart,
|
||||
when 'W' | 'w' => Left,
|
||||
when 'A' | 'a' => Up,
|
||||
when 'S' | 's' => Down,
|
||||
when 'D' | 'd' => Right,
|
||||
-- Windows terminal
|
||||
when Arrow_Prefix => (case Character'Pos(Get_Immediate) is
|
||||
when 72 => Up,
|
||||
when 75 => Left,
|
||||
when 77 => Right,
|
||||
when 80 => Down,
|
||||
when others => Invalid),
|
||||
-- Unix escape sequences
|
||||
when ASCII.ESC => (case Get_Immediate is
|
||||
when '[' => (case Get_Immediate is
|
||||
when 'A' => Up,
|
||||
when 'B' => Down,
|
||||
when 'C' => Right,
|
||||
when 'D' => Left,
|
||||
when others => Invalid),
|
||||
when others => Invalid),
|
||||
when others => Invalid);
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
procedure init is
|
||||
begin
|
||||
|
||||
for Row in 0 .. width+1 loop
|
||||
for Column in 0 .. height+1 loop
|
||||
|
||||
if Row = 0 or Row = width+1 then
|
||||
board(Row,Column) := '#';
|
||||
-- Insert(board(Row,0), Column, '#');
|
||||
else
|
||||
if Column = 0 or Column = height+1 then
|
||||
board(Row,Column) := '#';
|
||||
-- Insert(board, board(Row, Column), "#");
|
||||
else
|
||||
board(Row,Column) := ' ';
|
||||
-- Insert(board, board(Row, Column), " ");
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end loop;
|
||||
end loop;
|
||||
end;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
procedure run is
|
||||
|
||||
task T;
|
||||
task body T is
|
||||
begin
|
||||
loop
|
||||
snakeDirection := Get_Keystroke;
|
||||
end loop;
|
||||
end T;
|
||||
|
||||
begin
|
||||
|
||||
init;
|
||||
loop
|
||||
exit when snakeDirection = Quit;
|
||||
|
||||
if moveSnake = False then
|
||||
Put_Line("GAME OVER!!!");
|
||||
Put_Line("Your score is:" & Length(snake)'Image);
|
||||
exit;
|
||||
end if;
|
||||
|
||||
|
||||
Display_Board;
|
||||
delay 0.7;
|
||||
|
||||
end loop;
|
||||
end run;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
procedure Display_Board is
|
||||
begin
|
||||
|
||||
for Row in 0 .. width+1 loop
|
||||
for Column in 0 .. height+1 loop
|
||||
Put(board(Row, Column));
|
||||
end loop;
|
||||
New_Line;
|
||||
end loop;
|
||||
|
||||
end Display_Board;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
procedure ClearBoard is
|
||||
begin
|
||||
|
||||
for Row in 1 .. width loop
|
||||
for Column in 1 .. height loop
|
||||
board(Row, Column) := ' ';
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
end ClearBoard;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
function moveSnake return Boolean is
|
||||
colision : Boolean := False;
|
||||
headCoord : coord := Snake.First_Element;
|
||||
addSnakePart : Boolean := False;
|
||||
begin
|
||||
|
||||
case snakeDirection is
|
||||
when Up => headCoord.X := headCoord.X - 1;
|
||||
when Down => headCoord.X := headCoord.X + 1;
|
||||
when Right => headCoord.Y := headCoord.Y + 1;
|
||||
when Left => headCoord.Y := headCoord.Y - 1;
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
if headCoord.Y = height+1 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if headCoord.Y = 0 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if headCoord.X = width+1 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if headCoord.X = 0 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
for index in snake.Iterate loop
|
||||
if headCoord = snake(To_Index(index)) then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
snake.Prepend(headCoord);
|
||||
|
||||
if headCoord /= food then
|
||||
snake.Delete_Last;
|
||||
else
|
||||
food := (0,0);
|
||||
generateFood;
|
||||
end if;
|
||||
|
||||
addDataToBoard;
|
||||
|
||||
return True;
|
||||
end moveSnake;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
procedure generateFood is
|
||||
begin
|
||||
if food.X = 0 or food.Y = 0 then
|
||||
food := (getRandomInteger(width), getRandomInteger(height));
|
||||
end if;
|
||||
end generateFood;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
procedure addDataToBoard is
|
||||
begin
|
||||
ClearBoard;
|
||||
|
||||
board(food.X, food.Y) := '*';
|
||||
|
||||
for index in snake.Iterate loop
|
||||
board(snake(To_Index(index)).X, snake(To_Index(index)).Y) := 'o';
|
||||
end loop;
|
||||
|
||||
end addDataToBoard;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
function getRandomInteger(upperBound : Integer) return Integer is
|
||||
|
||||
subtype Random_Range is Integer range 1 .. upperBound;
|
||||
|
||||
package R is new
|
||||
Ada.Numerics.Discrete_Random (Random_Range);
|
||||
use R;
|
||||
|
||||
G : Generator;
|
||||
begin
|
||||
Reset (G);
|
||||
return Random (G);
|
||||
end getRandomInteger;
|
||||
|
||||
end Snake;
|
||||
|
||||
|
||||
-- main.adb
|
||||
|
||||
with Snake;
|
||||
|
||||
procedure Main is
|
||||
begin
|
||||
Snake.run;
|
||||
end;
|
||||
700
Task/Snake/Amazing-Hopper/snake.hopper
Normal file
700
Task/Snake/Amazing-Hopper/snake.hopper
Normal file
|
|
@ -0,0 +1,700 @@
|
|||
/* Snake */
|
||||
/* Implementing this task in Hopper-FLOW-MATIC++ */
|
||||
/* The snake must catch a bite before time runs out, which decreases by
|
||||
10 points every 800 milliseconds.
|
||||
The remaining time will be added to your total score. */
|
||||
|
||||
#include <flow.h>
|
||||
#include <flow-term.h>
|
||||
#include <keys.h>
|
||||
|
||||
#define LIMIT_TIME 120
|
||||
#define INF_TIME 80 //70
|
||||
#define ONE_SECOND 1000
|
||||
#define TOTAL_TIME 100
|
||||
#define DECREMENT_TIME 10
|
||||
#define COLOR_FOOD 232
|
||||
#define BACK_FOOD 255
|
||||
#define TIME_LEVEL 90000 //90000 // un minuto y medio
|
||||
#define TIME_CHALLENGE 40000 // 40 segundos
|
||||
#define TIME_LOST 30000
|
||||
#define COLUMNA_PRINT 55
|
||||
#define SIZE_INITIAL -7
|
||||
|
||||
#enum 1,N,E,S,W
|
||||
#enum 1,SPACE,FOOD,BORDER
|
||||
|
||||
DEF-MAIN
|
||||
BREAK-ON
|
||||
STACK 16
|
||||
|
||||
MSET(C, quit, nHead, dir, Size, SCORE, counter, T, TPlay,TSound, ConsPrey,Consumed stage )
|
||||
|
||||
SET(len,0)
|
||||
|
||||
SET( w, 50)
|
||||
SET( h, 28)
|
||||
SET( color food, COLOR_FOOD )
|
||||
SET( back food, BACK_FOOD )
|
||||
SET( TIME, 100 )
|
||||
LET( Size := MUL(w,h) )
|
||||
SET( LEVEL,1 )
|
||||
SET( REAL LEVEL,1 )
|
||||
FALSE(swPierde)
|
||||
TRUE(swExtra1,swExtra2)
|
||||
|
||||
TRUE( tiles )
|
||||
SET( back tiles,1 ), MSET(tile1, tile2)
|
||||
VOID( head back tiles )
|
||||
MEM("\033[48;5;28m","\033[48;5;29m","\033[48;5;62m","\033[48;5;63m","\033[48;5;70m","\033[48;5;71m","\033[48;5;4m","\033[48;5;27m" )
|
||||
MEM("\033[48;5;99m","\033[48;5;97m","\033[48;5;17m","\033[48;5;18m","\033[48;5;62m","\033[48;5;63m")
|
||||
APND-LST(head back tiles)
|
||||
[back tiles] GET(head back tiles), MOVE-TO(tile1)
|
||||
[PLUS-ONE(back tiles)] GET(head back tiles), MOVE-TO(tile2)
|
||||
|
||||
VOID( big number, numL1, numL2, numL3 )
|
||||
|
||||
VOID( sounds ), SET( sound index, 1 )
|
||||
MEM("Snake_music.wav","Snake_music_l3.wav","Snake_music_l5.wav","Snake_music_l4.wav","Snake_music_l6.wav")
|
||||
APND-LST(sounds)
|
||||
|
||||
GOSUB( set score )
|
||||
|
||||
MSET(tBoard1,tmpLimit,Maze,wM,hM,SizeM)
|
||||
DIM( Size ) AS-ONES( board ), {board} MOVE-TO(tBoard1)
|
||||
|
||||
// load and prepare maze for challenge stage:
|
||||
SET(i,1)
|
||||
LET( Maze := REPLICATE("3",50) )
|
||||
|
||||
PERF-UP(i,26,1)
|
||||
LET( Maze := CAT( Maze, CAT( CAT("3", REPLICATE("1",48) ), "3") ) )
|
||||
NEXT
|
||||
LET( Maze := CAT( Maze, REPLICATE("3",50) ))
|
||||
GOSUB( prepare maze )
|
||||
|
||||
HIDE-CURSOR
|
||||
CLR-SCR
|
||||
|
||||
SET( TLimit := LIMIT_TIME )
|
||||
MEM(SIZE_INITIAL),GOSUB( start )
|
||||
SET( time out, TIME_LEVEL)
|
||||
|
||||
SYS( CAT(CAT("aplay fl/",[sound index]CGET(sounds)), "</dev/null >/dev/null 2>&1 &"))
|
||||
GOSUB( titles )
|
||||
|
||||
/* PLAY GAME!! */
|
||||
SET(lives,3)
|
||||
WHILE( lives )
|
||||
GOSUB( show )
|
||||
GOSUB( put titles )
|
||||
GOSUB( ready ), SLEEP(1.5)
|
||||
TIC( T ), TIC( TPlay ), TIC(TSound)
|
||||
KBD-FREE
|
||||
WHILE( NOT (quit) )
|
||||
ON-TIME( TLimit ~= TPlay ){
|
||||
GOSUB( show )
|
||||
WHEN( KEY-PRESSED? ){
|
||||
SCAN-CODE( C )
|
||||
SELECT( C )
|
||||
CASE( K_UP ) { dir = N, EXIT }
|
||||
CASE( K_RIGHT ){ dir = E, EXIT }
|
||||
CASE( K_DOWN ) { dir = S, EXIT }
|
||||
CASE( K_LEFT ) { dir = W, EXIT }
|
||||
CASE( K_ESC ) { quit = 1, EXIT }
|
||||
CASE( 32 ) { PAUSE, EXIT }
|
||||
SELEND
|
||||
}
|
||||
GOSUB( step )
|
||||
}
|
||||
ON-TIME( ONE_SECOND ~= T ) {
|
||||
TIME-=DECREMENT_TIME, CLAMP(0,TOTAL_TIME,TIME)
|
||||
{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
|
||||
}
|
||||
ON-TIME( time out ~= TSound ){
|
||||
GOSUB(LEVELCLEAR)
|
||||
}
|
||||
WEND
|
||||
|
||||
COND( OR(EQ?(LEVEL,3),EQ?(LEVEL,6)) )
|
||||
GOSUB(you lost),SLEEP(3)
|
||||
SET(quit,0), [nHead]{len}CPUT(board)
|
||||
LOCATE(1,1), FILL-BOX(" ",29,54)
|
||||
GOSUB( another play )
|
||||
ELS
|
||||
GOSUB(you lost), SLEEP(3)
|
||||
--lives
|
||||
SET(quit,0)
|
||||
TRUE(swPierde)
|
||||
{len}GOSUB( start )
|
||||
COND( IS-NOT-ZERO?(lives) )
|
||||
SYS("aplay fl/Snake_music_vida_repechaje.wav </dev/null >/dev/null 2>&1 &")
|
||||
CEND
|
||||
CEND
|
||||
|
||||
WEND
|
||||
|
||||
/* GAME OVER */
|
||||
GOSUB(game over ), SLEEP(7)
|
||||
SET-VIDEO-TEXT
|
||||
SHOW-CURSOR
|
||||
PRNL
|
||||
END
|
||||
|
||||
RUTINES
|
||||
|
||||
DEF-FUN( KILLSOUND )
|
||||
SET( PID,0 )
|
||||
LET( PID := ONLY-CHR("0123456789 ", EXEC( "pidof aplay" )))
|
||||
COND( LEN(PID) )
|
||||
SYS( CAT(CAT("kill ",PID), " </dev/null >/dev/null 2>&1"))
|
||||
CEND
|
||||
RET
|
||||
|
||||
// initialize the board, plant a very first food item
|
||||
DEF-FUN( start, initial pos )
|
||||
|
||||
COND( NOT-EQ?(LEVEL,3) )
|
||||
{tBoard1} MOVE-TO(board)
|
||||
{50,28},MUL(50,28), MOVE-TO( w, h, Size )
|
||||
|
||||
[1:w] {BORDER} CPUT(board) // top
|
||||
[ SUB(MUL(h,w),MINUS-ONE(w)) : end] {BORDER} CPUT(board) // bottom
|
||||
[1:w:end] {BORDER} CPUT(board) // left
|
||||
|
||||
SET(i, 1)
|
||||
FOR( LE?(i, h), ++i )
|
||||
[ MUL(i, w )] {BORDER} PUT(board) // right
|
||||
NEXT
|
||||
LET( time out:=TIME_LEVEL )
|
||||
|
||||
ELS
|
||||
TRASH(board)
|
||||
CEND
|
||||
|
||||
SELECT(LEVEL)
|
||||
CASE(2){
|
||||
SET(i,3)
|
||||
PERF-UP(i,5,1)
|
||||
// laterales extremos:
|
||||
[ADD(MUL(i,w),5):ADD(MUL(i,w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(i,w),SUB(w,7)):ADD(MUL(i,w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// laterales fondo
|
||||
[ADD(MUL(ADD(i,19),w),5):ADD(MUL(ADD(i,19),w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,19),w),SUB(w,7)):ADD(MUL(ADD(i,19),w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
|
||||
NEXT
|
||||
EXIT
|
||||
}
|
||||
CASE(3){ // challenge stage!
|
||||
SPLIT(Maze,board, "" ), VAL(board), MOVE-TO(board)
|
||||
[1:w] {BORDER}CPUT(board)
|
||||
SET(i,1)
|
||||
|
||||
PERF-UP(i,19,1)
|
||||
GOSUB(plant)
|
||||
NEXT
|
||||
LET(time out := TIME_CHALLENGE)
|
||||
EXIT
|
||||
}
|
||||
CASE(4){
|
||||
SET(i,3)
|
||||
PERF-UP(i,5,1)
|
||||
// laterales medios
|
||||
[ADD(MUL(ADD(i,9),w),5):ADD(MUL(ADD(i,9),w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,9),w),SUB(w,7)):ADD(MUL(ADD(i,9),w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// medio arriba
|
||||
[ADD(MUL(i,w),17):ADD(MUL(i,w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(i,w),31):ADD(MUL(i,w),34)] {BORDER} CPUT(board)
|
||||
// medio abajo
|
||||
[ADD(MUL(ADD(i,19),w),17):ADD(MUL(ADD(i,19),w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,19),w),31):ADD(MUL(ADD(i,19),w),34)] {BORDER} CPUT(board)
|
||||
NEXT
|
||||
EXIT
|
||||
}
|
||||
|
||||
CASE(5){
|
||||
SET(i,3)
|
||||
PERF-UP(i,5,1)
|
||||
// laterales extremos:
|
||||
[ADD(MUL(i,w),5):ADD(MUL(i,w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(i,w),SUB(w,7)):ADD(MUL(i,w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// laterales medios
|
||||
[ADD(MUL(ADD(i,9),w),5):ADD(MUL(ADD(i,9),w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,9),w),SUB(w,7)):ADD(MUL(ADD(i,9),w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// laterales fondo
|
||||
[ADD(MUL(ADD(i,19),w),5):ADD(MUL(ADD(i,19),w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,19),w),SUB(w,7)):ADD(MUL(ADD(i,19),w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// medio arriba
|
||||
[ADD(MUL(i,w),17):ADD(MUL(i,w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(i,w),31):ADD(MUL(i,w),34)] {BORDER} CPUT(board)
|
||||
// medio abajo
|
||||
[ADD(MUL(ADD(i,19),w),17):ADD(MUL(ADD(i,19),w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,19),w),31):ADD(MUL(ADD(i,19),w),34)] {BORDER} CPUT(board)
|
||||
NEXT
|
||||
EXIT
|
||||
}
|
||||
CASE(6){
|
||||
SET(i,1)
|
||||
PERF-UP(i,29,1)
|
||||
GOSUB(plant)
|
||||
NEXT
|
||||
LET(time out := TIME_CHALLENGE)
|
||||
}
|
||||
|
||||
CASE(7){
|
||||
SET(i,3)
|
||||
PERF-UP(i,5,1)
|
||||
// laterales extremos:
|
||||
[ADD(MUL(i,w),5):ADD(MUL(i,w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(i,w),SUB(w,7)):ADD(MUL(i,w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// laterales medios
|
||||
[ADD(MUL(ADD(i,9),w),5):ADD(MUL(ADD(i,9),w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,9),w),SUB(w,7)):ADD(MUL(ADD(i,9),w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// laterales fondo
|
||||
[ADD(MUL(ADD(i,19),w),5):ADD(MUL(ADD(i,19),w),8)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,19),w),SUB(w,7)):ADD(MUL(ADD(i,19),w),SUB(w,4))] {BORDER} CPUT(board)
|
||||
// medio arriba
|
||||
[ADD(MUL(i,w),17):ADD(MUL(i,w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(i,w),31):ADD(MUL(i,w),34)] {BORDER} CPUT(board)
|
||||
// medio medio
|
||||
[ADD(MUL(ADD(i,9),w),17):ADD(MUL(ADD(i,9),w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,9),w),31):ADD(MUL(ADD(i,9),w),34)] {BORDER} CPUT(board)
|
||||
// medio abajo
|
||||
[ADD(MUL(ADD(i,19),w),17):ADD(MUL(ADD(i,19),w),20)] {BORDER} CPUT(board)
|
||||
[ADD(MUL(ADD(i,19),w),31):ADD(MUL(ADD(i,19),w),34)] {BORDER} CPUT(board)
|
||||
NEXT
|
||||
EXIT
|
||||
}
|
||||
SELEND
|
||||
|
||||
COND( NOT-EQ?(LEVEL,3) )
|
||||
LET( nHead := MUL( w, SUB( SUB( h, 1 ), MOD(h,2) )) DIV-INTO(2) )
|
||||
LET( dir := N )
|
||||
ELS
|
||||
LET( nHead := ADD( MUL( w, 13 ), 26 ) )
|
||||
LET( dir := N )
|
||||
CEND
|
||||
[ nHead ] {initial pos} CPUT( board )
|
||||
|
||||
IF( swPierde, SRAND( ~SECONDS); FALSE(swPierde); {TIME_LOST} »» (time out),\
|
||||
SRAND( 26785 ) )
|
||||
|
||||
GOSUB( plant )
|
||||
RET
|
||||
|
||||
DEF-FUN( you lost )
|
||||
SET(i,1), SET(k,0), SET(n,1)
|
||||
FOR( LE?(i, h), ++i)
|
||||
SET(j,1)
|
||||
FOR( LE?(j, w), ++j)
|
||||
LET( k := [ n ] GET(board) )
|
||||
COND( IS-NEG?( k ))
|
||||
LOCATE(i,j)
|
||||
PRN("\033[38;15;3m\033[48;5;9m~\OFF")
|
||||
CEND
|
||||
++n
|
||||
NEXT
|
||||
NEXT
|
||||
SYS("aplay fl/Snake_dolor.wav </dev/null >/dev/null 2>&1 &")
|
||||
|
||||
RET
|
||||
|
||||
DEF-FUN( show )
|
||||
|
||||
SET(i,1)
|
||||
MSET(j, k)
|
||||
SET(n,1)
|
||||
LOCATE(1,1)
|
||||
FOR( LE?(i, h), ++i)
|
||||
SET(j,1),LOG-INV(tiles)
|
||||
FOR( LE?(j, w), ++j)
|
||||
LET( k := [ n ] GET(board) )
|
||||
COND( IS-NEG?( k ))
|
||||
COND( NOT-EQ?(n,nHead) )
|
||||
IF(GT?(k,-3),IF(tiles,{tile1},{tile2});{"\033[38;5;15m+\OFF"},"\033[38;5;6m\033[48;5;11m \OFF")
|
||||
ELS
|
||||
COND( EQ?(dir,N))
|
||||
IF(tiles,"\033[38;5;9m\033[48;5;15mv\OFF","\033[38;5;9m\033[48;5;15m|\OFF")
|
||||
|
||||
ELS-COND( EQ?(dir,S))
|
||||
IF(tiles,"\033[38;5;9m\033[48;5;15m|\OFF","\033[38;5;9m\033[48;5;15m^\OFF")
|
||||
|
||||
ELS-COND( EQ?(dir,E))
|
||||
IF(tiles,"\033[38;5;9m\033[48;5;15m<\OFF","\033[38;5;9m\033[48;5;15m-\OFF")
|
||||
|
||||
ELS
|
||||
IF(tiles,"\033[38;5;9m\033[48;5;15m-\OFF","\033[38;5;9m\033[48;5;15m>\OFF")
|
||||
|
||||
CEND
|
||||
CEND
|
||||
|
||||
ELS-COND( {k} IS-EQ?(BORDER))
|
||||
{"\033[38;5;82m\033[48;5;57m \OFF"}
|
||||
|
||||
ELS-COND( {k}IS-EQ?(FOOD) )
|
||||
COLOR-FG(color food ),IF(tiles,{tile1},{tile2}) //back food)
|
||||
{"@\OFF"}
|
||||
ELS
|
||||
IF(tiles,{tile1},{tile2})
|
||||
{" \OFF"}
|
||||
CEND
|
||||
PRN
|
||||
LOG-INV(tiles)
|
||||
++n
|
||||
NEXT
|
||||
PRNL
|
||||
NEXT
|
||||
color food+=2,
|
||||
back food-=2, WHEN( EQ?(color food, PLUS-ONE(BACK_FOOD))){
|
||||
LET( color food:=COLOR_FOOD)
|
||||
LET( back food:=BACK_FOOD)
|
||||
}
|
||||
RET
|
||||
|
||||
// negative values denote the snake (a negated time-to-live in given cell)
|
||||
|
||||
// reduce a time-to-live, effectively erasing the tail
|
||||
DEF-FUN( age )
|
||||
|
||||
MSET( r, jAge, jR )
|
||||
CART( IS-NEG?( board ) ) »» (r), SET-RANGE(r)
|
||||
|
||||
GET( board ) PLUS(1) »» (jAge)
|
||||
|
||||
// this is necessary, because Hopper arrays begining in 1
|
||||
CART( IS-ZERO?(jAge) ) »» (jR)
|
||||
COND( IS-ARRAY?(jR) )
|
||||
SET-RANGE(jR), SET(jAge, 1), SET-RANGE(r)
|
||||
CEND
|
||||
// ******
|
||||
{jAge} PUT(board), CLR-RANGE
|
||||
|
||||
RET
|
||||
|
||||
DEF-FUN( step )
|
||||
LET( len := [nHead] GET(board) )
|
||||
SELECT(dir)
|
||||
CASE (N){ nHead -= w, EXIT }
|
||||
CASE (S){ nHead += w, EXIT }
|
||||
CASE (W){ --nHead, EXIT }
|
||||
CASE (E){ ++nHead, EXIT }
|
||||
SELEND
|
||||
SELECT( [nHead]CGET(board))
|
||||
CASE (SPACE){
|
||||
--len, LET( len := IF( EQ?(len,0), 1, len) )
|
||||
[nHead] { len }, CPUT(board) // keep in mind len is negative
|
||||
GOSUB( age )
|
||||
EXIT
|
||||
}
|
||||
CASE (FOOD){
|
||||
COND( NOT(OR(EQ?(LEVEL,3),EQ?(LEVEL,6))))
|
||||
--len, LET( len := IF( IS-ZERO?(len), 1, len) )
|
||||
ELS
|
||||
++len // quita celda del cuerpo: suma vida!
|
||||
CEND
|
||||
[nHead] { len }, CPUT(board)
|
||||
WHEN(AND(NOT-EQ?(LEVEL,3),NOT-EQ?(LEVEL,6))){ GOSUB( plant ) }
|
||||
ADD(SCORE,TIME), MOVE-TO(SCORE)
|
||||
|
||||
{SCORE, 4, COLUMNA_PRINT} GOSUB( put score )
|
||||
LET( TIME := 100 )
|
||||
++counter, COND( EQ?( counter, 25 ) )
|
||||
LET( TLimit := SUB( TLimit,5 ))
|
||||
CLAMP(INF_TIME, LIMIT_TIME, TLimit)
|
||||
LET( counter := 0 )
|
||||
CEND
|
||||
WHEN( OR(EQ?(LEVEL,3),EQ?(LEVEL,6))){ ++Consumed stage }
|
||||
++ConsPrey
|
||||
COLOR-FG(10)
|
||||
LOCATE(20,COLUMNA_PRINT) PRN("SPEED: ")
|
||||
LOC-ROW(21), PRN( ROUND(MUL(INV(TLimit),LIMIT_TIME),2), " M/S " )
|
||||
|
||||
LOC-ROW(23) PRN("CONSUMED PREY:")
|
||||
LOC-ROW(24) PRN(ConsPrey,"\OFF")
|
||||
|
||||
LET( color food:=COLOR_FOOD)
|
||||
LET( back food:=BACK_FOOD)
|
||||
|
||||
SYS("aplay fl/Snake_mascada.wav </dev/null >/dev/null 2>&1 &")
|
||||
|
||||
TIC( T ),{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
|
||||
|
||||
EXIT
|
||||
}
|
||||
CASE-NEGATIVE {
|
||||
GOSUB(KILLSOUND)
|
||||
SYS("aplay fl/Snake_mascada.wav </dev/null >/dev/null 2>&1")
|
||||
LET( quit := 1 )
|
||||
EXIT
|
||||
}
|
||||
DEFAULT {
|
||||
GOSUB(KILLSOUND)
|
||||
SYS("aplay fl/Snake_golpe.wav </dev/null >/dev/null 2>&1")
|
||||
|
||||
LET( quit := 1 )
|
||||
}
|
||||
SELEND
|
||||
RET
|
||||
|
||||
DEF-FUN( LEVELCLEAR )
|
||||
GOSUB(KILLSOUND)
|
||||
GOSUB( level clear )
|
||||
SYS("aplay fl/Snake_level_clear.wav </dev/null >/dev/null 2>&1")
|
||||
SLEEP(1)
|
||||
|
||||
WHEN( OR( EQ?(LEVEL,3), EQ?(LEVEL,6))){
|
||||
WHEN( EQ?(Consumed stage,20)){
|
||||
GOSUB( show )
|
||||
SYS( "aplay fl/Snake_bono.wav </dev/null >/dev/null 2>&1 &" )
|
||||
GOSUB(GANA BONO),SLEEP(3)
|
||||
ADD(SCORE,1000), MOVE-TO(SCORE)
|
||||
{SCORE, 4, COLUMNA_PRINT} GOSUB( put score )
|
||||
}
|
||||
}
|
||||
GOSUB( another play )
|
||||
RET
|
||||
|
||||
DEF-FUN( another play )
|
||||
++sound index, WHEN( EQ?(sound index,6)){ LET(sound index := 2) }
|
||||
back tiles+=2, WHEN( EQ?(back tiles,15)){ LET(back tiles:=1) }
|
||||
|
||||
[back tiles] GET(head back tiles), MOVE-TO(tile1)
|
||||
[PLUS-ONE(back tiles)] GET(head back tiles), MOVE-TO(tile2)
|
||||
|
||||
++LEVEL, WHEN( GT?(LEVEL,7)){ LET(LEVEL:=1) }
|
||||
|
||||
++ REAL LEVEL
|
||||
COLOR-FG(15),LOCATE(26,COLUMNA_PRINT) SET-ITALIC, PRN("LEVEL: ",REAL LEVEL,"\OFF")
|
||||
|
||||
LET( len := [nHead] GET(board) )
|
||||
[1:Size] MEM(1) CPUT(board)
|
||||
CLR-INTERVAL
|
||||
MEM(len), GOSUB( start )
|
||||
|
||||
GOSUB( show )
|
||||
COND( OR( EQ?(LEVEL,3), EQ?(LEVEL,6)))
|
||||
GOSUB(challenge stage)
|
||||
ELS
|
||||
GOSUB( ready )
|
||||
CEND
|
||||
SLEEP(2)
|
||||
SYS( CAT(CAT("aplay fl/",[sound index]CGET(sounds)), "</dev/null >/dev/null 2>&1 &"))
|
||||
LET( TIME := TOTAL_TIME )
|
||||
{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
|
||||
RET
|
||||
|
||||
// put a piece of food at random empty position
|
||||
DEF-FUN( plant )
|
||||
SET(r, 0)
|
||||
LOOP( search position )
|
||||
LET( r := MOD( CEIL(RAND(MINUS-ONE(Size))), Size ) )
|
||||
BACK-IF-NOT-EQ( [r] GET(board), SPACE, search position)
|
||||
[r] {FOOD} CPUT( board )
|
||||
RET
|
||||
|
||||
DEF-FUN( put titles )
|
||||
LOCATE(2,COLUMNA_PRINT) PRN("\033[38;5;15mSCORE\OFF")
|
||||
{SCORE, 4, COLUMNA_PRINT} GOSUB( put score )
|
||||
LOCATE(10,COLUMNA_PRINT) PRN("\033[38;5;11mTIME\OFF")
|
||||
{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
|
||||
|
||||
COLOR-FG(15)
|
||||
LOCATE(26,COLUMNA_PRINT) SET-ITALIC, PRN("LEVEL: ",REAL LEVEL,"\OFF")
|
||||
LOCATE(27,COLUMNA_PRINT) SET-INVERSE, PRN("LIVES: ",lives,"\OFF")
|
||||
|
||||
RET
|
||||
|
||||
DEF-FUN( put time, B, posx, posy )
|
||||
MSET( i,j,x )
|
||||
MSET( sb, lsb,nB, p4 )
|
||||
SET( k,1 )
|
||||
|
||||
LOCATE (posx, posy) FILL-BOX(" ",5,20)
|
||||
LET( sb := STR(B) )
|
||||
LET( lsb := LEN(sb) )
|
||||
SET( rx, posy )
|
||||
LET( p4 := ADD( posx, 4 ))
|
||||
|
||||
COLOR-FG(11)
|
||||
PERF-UP(k, lsb, 1)
|
||||
LET( nB := VAL( MID( 1, k, sb )) )
|
||||
SET(x, 1), SET( i, posx )
|
||||
FOR( LE?(i, p4), ++i )
|
||||
SET( j, rx )
|
||||
FOR( LE?(j, ADD( rx, 2 ) ), ++j )
|
||||
LOCATE(i, j) PRN( STR-TO-UTF8(CHAR( [ PLUS-ONE(nB), x] CGET(big number) MUL-BY(219) )))
|
||||
++x
|
||||
NEXT
|
||||
NEXT
|
||||
rx += 4
|
||||
NEXT
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( put score, SCORE, posx, posy )
|
||||
MSET( ln,s, sp )
|
||||
|
||||
LET( sp := STR( SCORE ))
|
||||
LET( ln := LEN(sp))
|
||||
|
||||
LOCATE ( posx, posy ) FILL-BOX(" ",4,20)
|
||||
SET(i, 1)
|
||||
COLOR-FG(15)
|
||||
PERF-UP( i, ln, 1)
|
||||
LET( s := VAL( MID( 1, i, sp )) )
|
||||
[ PLUS-ONE(s) ]
|
||||
LOCATE( posx, posy ), PRN ( STR-TO-UTF8( GET(numL1) ))
|
||||
LOC-ROW( PLUS-ONE(posx) ), PRN ( STR-TO-UTF8( GET(numL2) ))
|
||||
LOC-ROW( PLUS-TWO(posx) ), PRN ( STR-TO-UTF8( GET(numL3) ))
|
||||
posy += 2
|
||||
NEXT
|
||||
PRN("\OFF")
|
||||
COND( swExtra1 )
|
||||
COND( GE?(SCORE,5000) )
|
||||
++lives
|
||||
FALSE(swExtra1)
|
||||
SYS( "aplay fl/Snake_bono.wav </dev/null >/dev/null 2>&1 &" )
|
||||
LOCATE(27,COLUMNA_PRINT) SET-INVERSE, PRN("LIVES: ",lives,"\OFF")
|
||||
CEND
|
||||
ELS-COND(swExtra2)
|
||||
COND( GE?(SCORE,10000) )
|
||||
++lives
|
||||
FALSE(swExtra2)
|
||||
SYS( "aplay fl/Snake_bono.wav </dev/null >/dev/null 2>&1 &" )
|
||||
LOCATE(27,COLUMNA_PRINT) SET-INVERSE, PRN("LIVES: ",lives,"\OFF")
|
||||
CEND
|
||||
CEND
|
||||
RET
|
||||
|
||||
DEF-FUN( set score )
|
||||
|
||||
{"┌┐"," ┐","┌┐","┌┐","┐┐","┌┐","┌┐","┌┐","┌┐","┌┐"} APND-LST(numL1)
|
||||
{"││"," │","┌┘"," ┤","└┤","└┐","├┐"," │","├┤","└┤"} APND-LST(numL2)
|
||||
{"└┘"," ┴","└┘","└┘"," ┘","└┘","└┘"," ┴","└┘","└┘"} APND-LST(numL3)
|
||||
|
||||
{1,1,1,1,0,1,1,0,1,1,0,1,1,1,1} APND-ROW( big number )
|
||||
{1,1,0,0,1,0,0,1,0,0,1,0,1,1,1} APND-ROW( big number )
|
||||
{1,1,1,0,0,1,1,1,1,1,0,0,1,1,1} APND-ROW( big number )
|
||||
{1,1,1,0,0,1,0,1,1,0,0,1,1,1,1} APND-ROW( big number )
|
||||
{1,0,1,1,0,1,1,1,1,0,0,1,0,0,1} APND-ROW( big number )
|
||||
{1,1,1,1,0,0,1,1,1,0,0,1,1,1,1} APND-ROW( big number )
|
||||
{1,0,0,1,0,0,1,1,1,1,0,1,1,1,1} APND-ROW( big number )
|
||||
{1,1,1,0,0,1,0,0,1,0,0,1,0,0,1} APND-ROW( big number )
|
||||
{1,1,1,1,0,1,1,1,1,1,0,1,1,1,1} APND-ROW( big number )
|
||||
{1,1,1,1,0,1,1,1,1,0,0,1,0,0,1} APND-ROW( big number )
|
||||
|
||||
RET
|
||||
|
||||
DEF-FUN( ready )
|
||||
{"\033[38;5;4m\033[48;5;11m"}
|
||||
LOC-COL(16)
|
||||
LOC-ROW(13); PRN( STR-TO-UTF8(" ▄ ▄▄ ▄ ▄▄ ▄ ▄ "))
|
||||
LOC-ROW(14); PRN( STR-TO-UTF8(" █▄▀ █▀ █▄█ █ █ ▀▄▀ "))
|
||||
LOC-ROW(15); PRN( STR-TO-UTF8(" ▀ ▀ ▀▀ ▀ ▀ ▀▄▀ ▀ "))
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( level clear )
|
||||
{"\033[38;5;4m\033[48;5;11m"}
|
||||
LOC-COL(17)
|
||||
LOC-ROW(12); PRN( STR-TO-UTF8( " ▄ ▄▄ ▄ ▄ ▄▄ ▄ "))
|
||||
LOC-ROW(13); PRN( STR-TO-UTF8( " █ █▀ █ █ █▀ █ "))
|
||||
LOC-ROW(14); PRN( STR-TO-UTF8( " ▀ ▀▀ ▀ ▀▀ ▀ "))
|
||||
LOC-ROW(15); PRN( STR-TO-UTF8( " ▄ ▄ ▄▄ ▄ ▄ "))
|
||||
LOC-ROW(16); PRN( STR-TO-UTF8( " █ █ █▀ █▄█ █▄▀ "))
|
||||
LOC-ROW(17); PRN( STR-TO-UTF8( " ▀ ▀ ▀▀ ▀ ▀ ▀ ▀ "))
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( challenge stage )
|
||||
{"\033[38;5;4m\033[48;5;11m"}
|
||||
LOC-COL(9)
|
||||
LOC-ROW(12); PRN( STR-TO-UTF8( " ▄ ▄ ▄ ▄ ▄ ▄ ▄▄ ▄ ▄▄ ▄▄ "))
|
||||
LOC-ROW(13); PRN( STR-TO-UTF8( " █ █▄█ █▄█ █ █ █▀ █ █ █ ▄ █▀ "))
|
||||
LOC-ROW(14); PRN( STR-TO-UTF8( " ▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀ ▀ ▀ ▀▀ ▀▀ "))
|
||||
LOC-ROW(15); PRN( STR-TO-UTF8( " ▄ ▄ ▄ ▄ ▄▄ ▄▄ "))
|
||||
LOC-ROW(16); PRN( STR-TO-UTF8( " ▀▄ █ █▄█ █ ▄ █▀ "))
|
||||
LOC-ROW(17); PRN( STR-TO-UTF8( " ▀ ▀ ▀ ▀ ▀▀ ▀▀ "))
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( GANA BONO )
|
||||
{"\033[38;5;11m\033[48;5;196m"}
|
||||
LOC-COL(17)
|
||||
LOC-ROW(12); PRN( STR-TO-UTF8(" ▄ ▄ ▄ ▄ ▄ ▄ "))
|
||||
LOC-ROW(13); PRN( STR-TO-UTF8(" █▄▀ █ █ █ █ █ █ ▀▄ "))
|
||||
LOC-ROW(14); PRN( STR-TO-UTF8(" ▀▄▀ ▀ ▀ ▀ ▀ ▀ "))
|
||||
LOC-ROW(15); PRN( STR-TO-UTF8(" ▄ ▄ ▄ ▄ "))
|
||||
LOC-ROW(16); PRN( STR-TO-UTF8(" █ █ █ █ █ █ █ "))
|
||||
LOC-ROW(17); PRN( STR-TO-UTF8(" █ ▄ ▀▄▀ ▀▄▀ ▀▄▀ "))
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( game over )
|
||||
{"\033[38;5;15m\033[48;5;9m"}
|
||||
LOC-COL(17)
|
||||
LOC-ROW(12); PRN( STR-TO-UTF8(" ▄▄ ▄ ▄ ▄ ▄▄ "))
|
||||
LOC-ROW(13); PRN( STR-TO-UTF8(" █ ▄ █▄█ █ █ █ █▀ "))
|
||||
LOC-ROW(14); PRN( STR-TO-UTF8(" ▀▀ ▀ ▀ ▀ ▀ ▀ ▀▀ "))
|
||||
LOC-ROW(15); PRN( STR-TO-UTF8(" ▄ ▄ ▄ ▄▄ ▄ "))
|
||||
LOC-ROW(16); PRN( STR-TO-UTF8(" █ █ █ █ █▀ █▄▀ "))
|
||||
LOC-ROW(17); PRN( STR-TO-UTF8(" ▀ ▀ ▀▀ ▀ ▀ "))
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( titles )
|
||||
#define COLOR_INI 232
|
||||
#define COLOR_FIN 255
|
||||
SET(k,1)
|
||||
PERF-UP(k,2,1)
|
||||
SET(j,COLOR_INI), SET(jbg,COLOR_FIN)
|
||||
PERF-UP(j,COLOR_FIN,1)
|
||||
COLOR(j, jbg--)
|
||||
LOC-COL(17)
|
||||
LOC-ROW(12); PRN(STR-TO-UTF8(" "))
|
||||
LOC-ROW(13); PRN(STR-TO-UTF8(" ▄ ▄ ▄ ▄ ▄ ▄▄ "))
|
||||
LOC-ROW(14); PRN(STR-TO-UTF8(" ▀▄ █ █ █▄█ █▄ █▀ "))
|
||||
LOC-ROW(15); PRN(STR-TO-UTF8(" ▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀ "))
|
||||
LOC-ROW(16); PRN(STR-TO-UTF8(" ▄ ▄ ▄▄ ▄▄ ▄▄ "))
|
||||
LOC-ROW(17); PRN(STR-TO-UTF8(" ▀▄ █▄█ █▀ █▀ █ █ "))
|
||||
LOC-ROW(18); PRN(STR-TO-UTF8(" ▀ ▀ ▀▀ ▀▀ ▀▄▀ "))
|
||||
LOC-ROW(19); PRN(STR-TO-UTF8(" "))
|
||||
MICROSECS(20000)
|
||||
NEXT
|
||||
SET(j,COLOR_FIN), SET(jbg,COLOR_INI)
|
||||
PERF-DOWN(j,COLOR_INI,1)
|
||||
COLOR(j, jbg++)
|
||||
LOC-COL(17)
|
||||
LOC-ROW(12); PRN(STR-TO-UTF8(" "))
|
||||
LOC-ROW(13); PRN(STR-TO-UTF8(" ▄ ▄ ▄ ▄ ▄ ▄▄ "))
|
||||
LOC-ROW(14); PRN(STR-TO-UTF8(" ▀▄ █ █ █▄█ █▄ █▀ "))
|
||||
LOC-ROW(15); PRN(STR-TO-UTF8(" ▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀ "))
|
||||
LOC-ROW(16); PRN(STR-TO-UTF8(" ▄ ▄ ▄▄ ▄▄ ▄▄ "))
|
||||
LOC-ROW(17); PRN(STR-TO-UTF8(" ▀▄ █▄█ █▀ █▀ █ █ "))
|
||||
LOC-ROW(18); PRN(STR-TO-UTF8(" ▀ ▀ ▀▀ ▀▀ ▀▄▀ "))
|
||||
LOC-ROW(19); PRN(STR-TO-UTF8(" "))
|
||||
MICROSECS(20000)
|
||||
NEXT
|
||||
NEXT
|
||||
PRN("\OFF")
|
||||
RET
|
||||
|
||||
DEF-FUN( prepare maze )
|
||||
REPL(12,ADD(MUL(w, 3),20),"333333333333",Maze), MOVE-TO(Maze)
|
||||
REPL(12,ADD(MUL(w, 24),20),"333333333333",Maze), MOVE-TO(Maze)
|
||||
|
||||
REPL(12,ADD(MUL(w, 6),7),"333333333333",Maze), MOVE-TO(Maze)
|
||||
REPL(12,ADD(MUL(w, 6),33),"333333333333",Maze), MOVE-TO(Maze)
|
||||
|
||||
REPL(12,ADD(MUL(w, 21),7),"333333333333",Maze), MOVE-TO(Maze)
|
||||
REPL(12,ADD(MUL(w, 21),33),"333333333333",Maze), MOVE-TO(Maze)
|
||||
|
||||
SET(i,7)
|
||||
PERF-UP(i,10,1)
|
||||
REPL(1,ADD(MUL(w, i),7),"3",Maze), MOVE-TO(Maze)
|
||||
REPL(1,ADD(MUL(w, i),44),"3",Maze), MOVE-TO(Maze)
|
||||
REPL(1,ADD(MUL(w, ADD(i,10)),44),"3",Maze), MOVE-TO(Maze)
|
||||
REPL(1,ADD(MUL(w, ADD(i,10)),7),"3",Maze), MOVE-TO(Maze)
|
||||
NEXT
|
||||
RET
|
||||
59
Task/Snake/Applesoft-BASIC/snake.basic
Normal file
59
Task/Snake/Applesoft-BASIC/snake.basic
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
REM === VARIABLES ===
|
||||
REM
|
||||
REM D(4) X DELTAS
|
||||
REM E(4) Y DELTAS
|
||||
REM K(255) KEYCODE BEHESTS
|
||||
REM FN X X COORDINATES OF SNAKE FROM MEMORY
|
||||
REM FN Y Y COORDINATES OF SNAKE FROM MEMORY
|
||||
REM A <UNUSED>
|
||||
REM B BEHEST: 0=NOTHING 1=RIGHT 2=LEFT 3=DOWN 4=UP 5=QUIT
|
||||
REM C SCRN COLOR
|
||||
REM D X-DELTA
|
||||
REM E Y-DELTA
|
||||
REM F FOOD COLOR= 4 DARK GREEN
|
||||
REM H HIT= 127
|
||||
REM I KEYBOARD= 49152
|
||||
REM J CLEAR KEYBOARD= 49168
|
||||
REM K KEYCODE
|
||||
REM L LENGTH WIDTH&HEIGHT= 40
|
||||
REM M MAX= 1599 UPPER BOUND OF SNAKE X AND Y COORDINATES
|
||||
REM N NEW POSITION OF HEAD OF SNAKE
|
||||
REM O OLD POSITION OF TAIL OF SNAKE
|
||||
REM P ADDRESS OF 1600 X COORDINATES OF SNAKE
|
||||
REM Q QUIT= 5
|
||||
REM R REMAINING COLOR= 9 ORANGE
|
||||
REM S SNAKE HEAD COLOR= 13 YELLOW
|
||||
REM T ONE= 1
|
||||
REM U X FOOD COORDINATE
|
||||
REM V Y FOOD COORDINATE
|
||||
REM W WALL COLOR= 10 GREY
|
||||
REM X X SNAKE HEAD COORDINATE
|
||||
REM Y Y SNAKE HEAD COORDINATE
|
||||
REM Z ADDRESS OF 1600 Y COORDINATES OF SNAKE
|
||||
REM Q$ QUIT MESSAGE
|
||||
|
||||
REM === KEYBOARD ===
|
||||
REM
|
||||
REM UPPER LOWER KEY BEHEST
|
||||
REM 155 ESC QUIT
|
||||
REM 139 UP UP
|
||||
REM 193 225 A UP
|
||||
REM 201 233 I UP
|
||||
REM 138 DOWN DOWN
|
||||
REM 218 250 Z DOWN
|
||||
REM 203 235 K DOWN
|
||||
REM 136 LEFT LEFT
|
||||
REM 202 234 J LEFT
|
||||
REM 149 RIGHT RIGHT
|
||||
REM 204 236 L RIGHT
|
||||
|
||||
0 ON B = Q GOTO 5: IF B THEN D = D(B):E = E(B)
|
||||
1 X = X + D:Y = Y + E:C = SCRN( X,Y): COLOR= S: PLOT X,Y: COLOR= R: PLOT FN X(N), FN Y(N):N = N - T + (N = 0) * M: POKE P + N,X: POKE Z + N,Y: ON C(C) GOTO 4: IF NOT C THEN COLOR= 0: PLOT FN X(O), FN Y(O):O = O - T + (O = 0) * M
|
||||
2 IF C THEN U = INT ( RND (T) * L):V = INT ( RND (T) * L): ON SCRN( U,V) > 0 GOTO 2: COLOR= F: PLOT U,V
|
||||
3 K = PEEK (I):B = PEEK (J * (K > H)):B = K(K): GOTO
|
||||
4 COLOR= T: PLOT X,Y: READ Q$: DATA5,20,20,1,-1,1,-1,13,9,4,10,1,40,1599,127,49152,49168,4608,6400,5,4,4,4,4,4,3,3,3,3,3,2,2,2,1,1,1,DONE,GAME OVER
|
||||
5 IF Q = 5 THEN PRINT Q$;: END : HOME :Q = Q * (B = Q):B = 0: ON Q = 5 GOTO : RUN
|
||||
6 LOMEM: 24576
|
||||
7 DIM K(255),D(4),E(4),C(15): READ Q,X,Y,D(1),D(2),E(3),E(4),S,R,F,W,T,L,M,H,I,J,P,Z,K(155),K(139),K(193),K(225),K(201),K(233),K(138),K(218),K(250),K(203),K(235),K(136),K(202),K(234),K(149),K(204),K(236),Q$
|
||||
8 DEF FN X(I) = PEEK (P + I): DEF FN Y(I) = PEEK (Z + I):B = RND (0):C(S) = T:C(R) = T:C(W) = T:B = INT ( RND (T) * 4) + T:D = D(B):E = E(B): POKE P + O,X: POKE Z + O,Y
|
||||
9 GR : HOME : COLOR= W: VLIN 0,39 AT 0: VLIN 0,39 AT 39: HLIN 1,38 AT 0: HLIN 1,38 AT 39: COLOR= F: PLOT X + D,Y + E: GOTO
|
||||
121
Task/Snake/AutoHotkey/snake.ahk
Normal file
121
Task/Snake/AutoHotkey/snake.ahk
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
gosub Init
|
||||
Gui, +AlwaysOnTop
|
||||
Gui, font, s12, consolas
|
||||
Gui, add, Edit, vEditGrid x10 y10 ReadOnly, % grid2Text(oGrid)
|
||||
Gui, add, Text, vScore x10 y+10 w200 ReadOnly, % "Your Score = " Score
|
||||
Gui, show,, Snake
|
||||
GuiControl, Focus, Score
|
||||
return
|
||||
;-----------------------------------------
|
||||
Init:
|
||||
Width := 100, Height := 30 ; set grid size
|
||||
tail := 20, step := 10
|
||||
Timer := 75
|
||||
item := 0, direction := ""
|
||||
oTrail := [], Score := 0
|
||||
xx := generateGrid(width, Height)
|
||||
oGrid := xx.1
|
||||
row := xx.2, col := xx.3
|
||||
return
|
||||
;-----------------------------------------
|
||||
Move:
|
||||
if !item
|
||||
{
|
||||
loop
|
||||
{
|
||||
Random, itemC, 3, % width-2
|
||||
Random, itemR, 3, % Height-2
|
||||
}
|
||||
until, !oGrid[itemR, itemC]
|
||||
oGrid[itemR, itemC] := "@"
|
||||
item := true
|
||||
}
|
||||
gosub, crawl
|
||||
return
|
||||
;-----------------------------------------
|
||||
#IfWinActive, Snake
|
||||
left::
|
||||
Right::
|
||||
up::
|
||||
Down::
|
||||
if ((A_ThisHotkey = "right") && (Direction = "left"))
|
||||
|| ((A_ThisHotkey = "left") && (Direction = "right"))
|
||||
|| ((A_ThisHotkey = "up") && (Direction = "Down"))
|
||||
|| ((A_ThisHotkey = "Down") && (Direction = "up"))
|
||||
|| ((A_ThisHotkey = "right") && (Direction = "right"))
|
||||
|| ((A_ThisHotkey = "left") && (Direction = "left"))
|
||||
|| ((A_ThisHotkey = "up") && (Direction = "up"))
|
||||
|| ((A_ThisHotkey = "Down") && (Direction = "Down"))
|
||||
return
|
||||
|
||||
Direction := A_ThisHotkey
|
||||
gosub, crawl
|
||||
return
|
||||
#IfWinActive
|
||||
;-----------------------------------------
|
||||
crawl:
|
||||
switch, Direction
|
||||
{
|
||||
case "left" : oGrid[row , col--] := 1
|
||||
case "Right" : oGrid[row , col++] := 1
|
||||
case "up" : oGrid[row--, col ] := 1
|
||||
case "Down" : oGrid[row++, col ] := 1
|
||||
}
|
||||
|
||||
; out of bounds or snake eats itself
|
||||
if oGrid[row, col] = 1 || col < 1 || col > width || row < 1 || row > height
|
||||
gosub, YouLose
|
||||
|
||||
; snake eats item
|
||||
if (oGrid[row, col] = "@")
|
||||
{
|
||||
item := false
|
||||
tail += step
|
||||
GuiControl,, Score, % "Your Score = " ++Score
|
||||
}
|
||||
|
||||
; snake advances
|
||||
oGrid[row, col] := 2
|
||||
oTrail.Push(row "," col)
|
||||
if (oTrail.count() >= tail)
|
||||
x := StrSplit(oTrail.RemoveAt(1), ","), oGrid[x.1, x.2] := false
|
||||
|
||||
GuiControl,, EditGrid, % grid2Text(oGrid)
|
||||
SetTimer, Move, % 0-Timer
|
||||
return
|
||||
;-----------------------------------------
|
||||
YouLose:
|
||||
SetTimer, Move, Off
|
||||
MsgBox, 262180, ,% "Your Score is " Score "`nPlay Again?"
|
||||
IfMsgBox, No
|
||||
ExitApp
|
||||
|
||||
gosub Init
|
||||
GuiControl,, EditGrid, % grid2Text(oGrid)
|
||||
return
|
||||
;-----------------------------------------
|
||||
grid2Text(oGrid){
|
||||
for row, obj in oGrid {
|
||||
for col, val in obj ; @=item, 2=Head, 1=tail
|
||||
text .= val = "@" ? "@" : val =2 ? "█" : val = 1 ? "▓" : " "
|
||||
text .= "`n"
|
||||
}
|
||||
return trim(text, "`n")
|
||||
}
|
||||
;-----------------------------------------
|
||||
generateGrid(width, Height){
|
||||
global oTrail
|
||||
oGrid := []
|
||||
loop, % width
|
||||
{
|
||||
col := A_Index
|
||||
loop, % Height
|
||||
row := A_Index, oGrid[row, col] := false
|
||||
}
|
||||
Random, col, 3, % width-2
|
||||
Random, row, 3, % Height-2
|
||||
oGrid[row, col] := 2
|
||||
oTrail.Push(row "," col)
|
||||
return [oGrid, row, col]
|
||||
}
|
||||
;-----------------------------------------
|
||||
112
Task/Snake/C++/snake.cpp
Normal file
112
Task/Snake/C++/snake.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#include <windows.h>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
const int WID = 60, HEI = 30, MAX_LEN = 600;
|
||||
enum DIR { NORTH, EAST, SOUTH, WEST };
|
||||
|
||||
class snake {
|
||||
public:
|
||||
snake() {
|
||||
console = GetStdHandle( STD_OUTPUT_HANDLE ); SetConsoleTitle( "Snake" );
|
||||
COORD coord = { WID + 1, HEI + 2 }; SetConsoleScreenBufferSize( console, coord );
|
||||
SMALL_RECT rc = { 0, 0, WID, HEI + 1 }; SetConsoleWindowInfo( console, TRUE, &rc );
|
||||
CONSOLE_CURSOR_INFO ci = { 1, false }; SetConsoleCursorInfo( console, &ci );
|
||||
}
|
||||
void play() {
|
||||
std::string a;
|
||||
while( 1 ) {
|
||||
createField(); alive = true;
|
||||
while( alive ) { drawField(); readKey(); moveSnake(); Sleep( 50 ); }
|
||||
COORD c = { 0, HEI + 1 }; SetConsoleCursorPosition( console, c );
|
||||
SetConsoleTextAttribute( console, 0x000b );
|
||||
std::cout << "Play again [Y/N]? "; std::cin >> a;
|
||||
if( a.at( 0 ) != 'Y' && a.at( 0 ) != 'y' ) return;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void createField() {
|
||||
COORD coord = { 0, 0 }; DWORD c;
|
||||
FillConsoleOutputCharacter( console, ' ', ( HEI + 2 ) * 80, coord, &c );
|
||||
FillConsoleOutputAttribute( console, 0x0000, ( HEI + 2 ) * 80, coord, &c );
|
||||
SetConsoleCursorPosition( console, coord );
|
||||
int x = 0, y = 1; for( ; x < WID * HEI; x++ ) brd[x] = 0;
|
||||
for( x = 0; x < WID; x++ ) {
|
||||
brd[x] = brd[x + WID * ( HEI - 1 )] = '+';
|
||||
}
|
||||
for( ; y < HEI; y++ ) {
|
||||
brd[0 + WID * y] = brd[WID - 1 + WID * y] = '+';
|
||||
}
|
||||
do {
|
||||
x = rand() % WID; y = rand() % ( HEI >> 1 ) + ( HEI >> 1 );
|
||||
} while( brd[x + WID * y] );
|
||||
brd[x + WID * y] = '@';
|
||||
tailIdx = 0; headIdx = 4; x = 3; y = 2;
|
||||
for( int c = tailIdx; c < headIdx; c++ ) {
|
||||
brd[x + WID * y] = '#';
|
||||
snk[c].X = 3 + c; snk[c].Y = 2;
|
||||
}
|
||||
head = snk[3]; dir = EAST; points = 0;
|
||||
}
|
||||
void readKey() {
|
||||
if( GetAsyncKeyState( 39 ) & 0x8000 ) dir = EAST;
|
||||
if( GetAsyncKeyState( 37 ) & 0x8000 ) dir = WEST;
|
||||
if( GetAsyncKeyState( 38 ) & 0x8000 ) dir = NORTH;
|
||||
if( GetAsyncKeyState( 40 ) & 0x8000 ) dir = SOUTH;
|
||||
}
|
||||
void drawField() {
|
||||
COORD coord; char t;
|
||||
for( int y = 0; y < HEI; y++ ) {
|
||||
coord.Y = y;
|
||||
for( int x = 0; x < WID; x++ ) {
|
||||
t = brd[x + WID * y]; if( !t ) continue;
|
||||
coord.X = x; SetConsoleCursorPosition( console, coord );
|
||||
if( coord.X == head.X && coord.Y == head.Y ) {
|
||||
SetConsoleTextAttribute( console, 0x002e );
|
||||
std::cout << 'O'; SetConsoleTextAttribute( console, 0x0000 );
|
||||
continue;
|
||||
}
|
||||
switch( t ) {
|
||||
case '#': SetConsoleTextAttribute( console, 0x002a ); break;
|
||||
case '+': SetConsoleTextAttribute( console, 0x0019 ); break;
|
||||
case '@': SetConsoleTextAttribute( console, 0x004c ); break;
|
||||
}
|
||||
std::cout << t; SetConsoleTextAttribute( console, 0x0000 );
|
||||
}
|
||||
}
|
||||
std::cout << t; SetConsoleTextAttribute( console, 0x0007 );
|
||||
COORD c = { 0, HEI }; SetConsoleCursorPosition( console, c );
|
||||
std::cout << "Points: " << points;
|
||||
}
|
||||
void moveSnake() {
|
||||
switch( dir ) {
|
||||
case NORTH: head.Y--; break;
|
||||
case EAST: head.X++; break;
|
||||
case SOUTH: head.Y++; break;
|
||||
case WEST: head.X--; break;
|
||||
}
|
||||
char t = brd[head.X + WID * head.Y];
|
||||
if( t && t != '@' ) { alive = false; return; }
|
||||
brd[head.X + WID * head.Y] = '#';
|
||||
snk[headIdx].X = head.X; snk[headIdx].Y = head.Y;
|
||||
if( ++headIdx >= MAX_LEN ) headIdx = 0;
|
||||
if( t == '@' ) {
|
||||
points++; int x, y;
|
||||
do {
|
||||
x = rand() % WID; y = rand() % ( HEI >> 1 ) + ( HEI >> 1 );
|
||||
} while( brd[x + WID * y] );
|
||||
brd[x + WID * y] = '@'; return;
|
||||
}
|
||||
SetConsoleCursorPosition( console, snk[tailIdx] ); std::cout << ' ';
|
||||
brd[snk[tailIdx].X + WID * snk[tailIdx].Y] = 0;
|
||||
if( ++tailIdx >= MAX_LEN ) tailIdx = 0;
|
||||
}
|
||||
bool alive; char brd[WID * HEI];
|
||||
HANDLE console; DIR dir; COORD snk[MAX_LEN];
|
||||
COORD head; int tailIdx, headIdx, points;
|
||||
};
|
||||
int main( int argc, char* argv[] ) {
|
||||
srand( static_cast<unsigned>( time( NULL ) ) );
|
||||
snake s; s.play(); return 0;
|
||||
}
|
||||
143
Task/Snake/C/snake.c
Normal file
143
Task/Snake/C/snake.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// Snake
|
||||
|
||||
// The problem with implementing this task in C is, the language standard
|
||||
// does not cover some details essential for interactive games:
|
||||
// a nonblocking keyboard input, a positional console output,
|
||||
// a and millisecond-precision timer: these things are all system-dependent.
|
||||
|
||||
// Therefore the program is split in two pieces, a system-independent
|
||||
// game logic, and a system-dependent UI, separated by a tiny API:
|
||||
char nonblocking_getch();
|
||||
void positional_putch(int x, int y, char ch);
|
||||
void millisecond_sleep(int n);
|
||||
void init_screen();
|
||||
void update_screen();
|
||||
void close_screen();
|
||||
|
||||
// The implementation of a system-dependent part.
|
||||
// Requires POSIX IEEE 1003.1-2008 compliant system and ncurses library.
|
||||
#ifdef __linux__
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <time.h> // nanosleep
|
||||
#include <ncurses.h> // getch, mvaddch, and others
|
||||
char nonblocking_getch() { return getch(); }
|
||||
void positional_putch(int x, int y, char ch) { mvaddch(x, y, ch); }
|
||||
void millisecond_sleep(int n) {
|
||||
struct timespec t = { 0, n * 1000000 };
|
||||
nanosleep(&t, 0);
|
||||
// for older POSIX standards, consider usleep()
|
||||
}
|
||||
void update_screen() { refresh(); }
|
||||
void init_screen() {
|
||||
initscr();
|
||||
noecho();
|
||||
cbreak();
|
||||
nodelay(stdscr, TRUE);
|
||||
}
|
||||
void close_screen() { endwin(); }
|
||||
#endif
|
||||
|
||||
// An implementation for some other system...
|
||||
#ifdef _WIN32
|
||||
#error "not implemented"
|
||||
#endif
|
||||
|
||||
// The game logic, system-independent
|
||||
#include <time.h> // time
|
||||
#include <stdlib.h> // rand, srand
|
||||
|
||||
#define w 80
|
||||
#define h 40
|
||||
|
||||
int board[w * h];
|
||||
int head;
|
||||
enum Dir { N, E, S, W } dir;
|
||||
int quit;
|
||||
|
||||
enum State { SPACE=0, FOOD=1, BORDER=2 };
|
||||
// negative values denote the snake (a negated time-to-live in given cell)
|
||||
|
||||
// reduce a time-to-live, effectively erasing the tail
|
||||
void age() {
|
||||
int i;
|
||||
for(i = 0; i < w * h; ++i)
|
||||
if(board[i] < 0)
|
||||
++board[i];
|
||||
}
|
||||
|
||||
// put a piece of food at random empty position
|
||||
void plant() {
|
||||
int r;
|
||||
do
|
||||
r = rand() % (w * h);
|
||||
while(board[r] != SPACE);
|
||||
board[r] = FOOD;
|
||||
}
|
||||
|
||||
// initialize the board, plant a very first food item
|
||||
void start(void) {
|
||||
int i;
|
||||
for(i = 0; i < w; ++i)
|
||||
board[i] = board[i + (h - 1) * w] = BORDER;
|
||||
for(i = 0; i < h; ++i)
|
||||
board[i * w] = board[i * w + w - 1] = BORDER;
|
||||
head = w * (h - 1 - h % 2) / 2; // screen center for any h
|
||||
board[head] = -5;
|
||||
dir = N;
|
||||
quit = 0;
|
||||
srand(time(0));
|
||||
plant();
|
||||
}
|
||||
|
||||
void step() {
|
||||
int len = board[head];
|
||||
switch(dir) {
|
||||
case N: head -= w; break;
|
||||
case S: head += w; break;
|
||||
case W: --head; break;
|
||||
case E: ++head; break;
|
||||
}
|
||||
switch(board[head]) {
|
||||
case SPACE:
|
||||
board[head] = len - 1; // keep in mind len is negative
|
||||
age();
|
||||
break;
|
||||
case FOOD:
|
||||
board[head] = len - 1;
|
||||
plant();
|
||||
break;
|
||||
default:
|
||||
quit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void show() {
|
||||
const char * symbol = " @.";
|
||||
int i;
|
||||
for(i = 0; i < w * h; ++i)
|
||||
positional_putch(i / w, i % w,
|
||||
board[i] < 0 ? '#' : symbol[board[i]]);
|
||||
update_screen();
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
init_screen();
|
||||
start();
|
||||
do {
|
||||
show();
|
||||
switch(nonblocking_getch()) {
|
||||
case 'i': dir = N; break;
|
||||
case 'j': dir = W; break;
|
||||
case 'k': dir = S; break;
|
||||
case 'l': dir = E; break;
|
||||
case 'q': quit = 1; break;
|
||||
}
|
||||
step();
|
||||
millisecond_sleep(100); // beware, this approach
|
||||
// is not suitable for anything but toy projects like this
|
||||
}
|
||||
while(!quit);
|
||||
millisecond_sleep(999);
|
||||
close_screen();
|
||||
return 0;
|
||||
}
|
||||
170
Task/Snake/Craft-Basic/snake.basic
Normal file
170
Task/Snake/Craft-Basic/snake.basic
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
rem Snake example game for Craft Basic
|
||||
rem by Gemino Smothers 2022
|
||||
rem www.lucidapogee.com
|
||||
|
||||
title "Snake!"
|
||||
|
||||
define gfxx = 330, gfxy = 296
|
||||
define upkey = 0, rightkey = 0, downkey = 0, leftkey = 0, esckey = 0
|
||||
define speed = 0, delay = 0, score = 0, game = 1
|
||||
define maxsize = 1000, size = 9, direction = int(rnd * 4) + 1
|
||||
define rx = int(rnd * (gfxx - 24)) + 12
|
||||
define ry = int(rnd * (gfxy - 40)) + 25
|
||||
|
||||
dim sx[maxsize]
|
||||
dim sy[maxsize]
|
||||
|
||||
let sx[0] = gfxx / 2
|
||||
let sy[0] = gfxy / 2
|
||||
|
||||
fill on
|
||||
bgcolor 128, 64, 0
|
||||
cls graphics
|
||||
|
||||
resize 0, 0, gfxx + 10, gfxy + 56
|
||||
center
|
||||
|
||||
formid 1
|
||||
staticform 1, 1, 100, 14
|
||||
fgcolor 255, 255, 0
|
||||
bgcolor 0, 80, 0
|
||||
colorform
|
||||
|
||||
alert "Snake! by Gemino Smothers 2022"
|
||||
alert "Get the gray little rodents and avoid hitting yourself or walls."
|
||||
alert "Use arrow keys to move. Esc to exit."
|
||||
|
||||
input "Enter game speed between 0 to 100+", speed
|
||||
|
||||
fgcolor 0, 80, 0
|
||||
rect 0, 0, gfxx, gfxy
|
||||
|
||||
do
|
||||
|
||||
button upkey, 38
|
||||
button rightkey, 39
|
||||
button downkey, 40
|
||||
button leftkey, 37
|
||||
button esckey, 27
|
||||
|
||||
if upkey = 1 and direction <> 3 then
|
||||
|
||||
let direction = 1
|
||||
|
||||
endif
|
||||
|
||||
if rightkey = 1 and direction <> 4 then
|
||||
|
||||
let direction = 2
|
||||
|
||||
endif
|
||||
|
||||
if downkey = 1 and direction <> 1 then
|
||||
|
||||
let direction = 3
|
||||
|
||||
endif
|
||||
|
||||
if leftkey = 1 and direction <> 2 then
|
||||
|
||||
let direction = 4
|
||||
|
||||
endif
|
||||
|
||||
fgcolor 0, 80, 0
|
||||
oval sx[size], sy[size], 15, 15
|
||||
|
||||
let i = size + 1
|
||||
|
||||
do
|
||||
|
||||
let i = i - 1
|
||||
let c = i - 1
|
||||
|
||||
if sx[0] = sx[i] and sy[0] = sy[i] = 1 then
|
||||
|
||||
let game = 0
|
||||
|
||||
endif
|
||||
|
||||
let sx[i] = sx[c]
|
||||
let sy[i] = sy[c]
|
||||
|
||||
fgcolor 0, 255, 0
|
||||
oval sx[i], sy[i], 15, 15
|
||||
|
||||
loop i > 1
|
||||
|
||||
fgcolor 0, 0, 255
|
||||
oval sx[0] + 5, sy[0] + 5, 3, 3
|
||||
oval sx[0] + 9, sy[0] + 5, 3, 3
|
||||
|
||||
if direction = 1 then
|
||||
|
||||
let sy[0] = sy[0] - 15
|
||||
|
||||
endif
|
||||
|
||||
if direction = 2 then
|
||||
|
||||
let sx[0] = sx[0] + 15
|
||||
|
||||
endif
|
||||
|
||||
if direction = 3 then
|
||||
|
||||
let sy[0] = sy[0] + 15
|
||||
|
||||
endif
|
||||
|
||||
if direction = 4 then
|
||||
|
||||
let sx[0] = sx[0] - 15
|
||||
|
||||
endif
|
||||
|
||||
if sx[0] <= -10 or sx[0] >= gfxx or sy[0] <= -10 or sy[0] >= gfxy = 1 then
|
||||
|
||||
let game = 0
|
||||
|
||||
endif
|
||||
|
||||
if sx[0] + 15 >= rx and sx[0] <= rx + 15 and sy[0] + 15 >= ry and sy[0] <= ry + 15 = 1 then
|
||||
|
||||
playwave "examples\tada.wav"
|
||||
|
||||
fgcolor 0, 80, 0
|
||||
rect 0, 0, gfxx, gfxy
|
||||
|
||||
let rx = int(rnd * (gfxx - 24)) + 12
|
||||
let ry = int(rnd * (gfxy - 40)) + 25
|
||||
|
||||
let size = size + 3
|
||||
let score = score + 1
|
||||
|
||||
endif
|
||||
|
||||
fgcolor 100,100,100
|
||||
oval rx, ry, 15, 15
|
||||
|
||||
fgcolor 255, 0, 0
|
||||
oval rx + 5, ry + 5, 3, 3
|
||||
oval rx + 9, ry + 5, 3, 3
|
||||
|
||||
fgcolor 255, 255, 0
|
||||
formid 1
|
||||
formtext "Score: ", score
|
||||
updateform
|
||||
|
||||
let delay = clock
|
||||
|
||||
do
|
||||
|
||||
wait
|
||||
|
||||
loop clock < delay + speed
|
||||
|
||||
loop esckey <> 1 and game = 1
|
||||
|
||||
playwave "examples\boom.wav"
|
||||
alert "Game over! Score: ", score
|
||||
356
Task/Snake/Delphi/snake-1.delphi
Normal file
356
Task/Snake/Delphi/snake-1.delphi
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
unit SnakeGame;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Winapi.Windows, System.SysUtils,
|
||||
System.Classes, Vcl.Graphics, Vcl.Forms, Vcl.Dialogs,
|
||||
System.Generics.Collections, Vcl.ExtCtrls;
|
||||
|
||||
type
|
||||
TSnakeApp = class(TForm)
|
||||
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure FormPaint(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
||||
procedure DoFrameStep(Sender: TObject);
|
||||
procedure Reset;
|
||||
private
|
||||
{ Private declarations }
|
||||
FrameTimer: TTimer;
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
TSnake = class
|
||||
len: Integer;
|
||||
alive: Boolean;
|
||||
pos: TPoint;
|
||||
posArray: TList<TPoint>;
|
||||
dir: Byte;
|
||||
private
|
||||
function Eat(Fruit: TPoint): Boolean;
|
||||
function Overlap: Boolean;
|
||||
procedure update;
|
||||
public
|
||||
procedure Paint(Canvas: TCanvas);
|
||||
procedure Reset;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
TFruit = class
|
||||
FruitTime: Boolean;
|
||||
pos: TPoint;
|
||||
constructor Create;
|
||||
procedure Reset;
|
||||
procedure Paint(Canvas: TCanvas);
|
||||
private
|
||||
procedure SetFruit;
|
||||
end;
|
||||
|
||||
const
|
||||
L = 1;
|
||||
R = 2;
|
||||
D = 4;
|
||||
U = 8;
|
||||
|
||||
var
|
||||
SnakeApp: TSnakeApp;
|
||||
block: Integer = 24;
|
||||
wid: Integer = 30;
|
||||
hei: Integer = 20;
|
||||
fruit: TFruit;
|
||||
snake: TSnake;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
function Rect(x, y, w, h: Integer): TRect;
|
||||
begin
|
||||
Result := TRect.Create(x, y, x + w, y + h);
|
||||
end;
|
||||
|
||||
{ TSnake }
|
||||
|
||||
constructor TSnake.Create;
|
||||
begin
|
||||
posArray := TList<TPoint>.Create;
|
||||
Reset;
|
||||
end;
|
||||
|
||||
procedure TSnake.Paint(Canvas: TCanvas);
|
||||
var
|
||||
pos: TPoint;
|
||||
i, l: Integer;
|
||||
r: TRect;
|
||||
begin
|
||||
with Canvas do
|
||||
begin
|
||||
Brush.Color := rgb(130, 190, 0);
|
||||
|
||||
i := posArray.count - 1;
|
||||
l := posArray.count;
|
||||
while True do
|
||||
begin
|
||||
pos := posArray[i];
|
||||
dec(i);
|
||||
r := rect(pos.x * block, pos.y * block, block, block);
|
||||
FillRect(r);
|
||||
dec(l);
|
||||
if l = 0 then
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSnake.Reset;
|
||||
begin
|
||||
alive := true;
|
||||
pos := Tpoint.Create(1, 1);
|
||||
posArray.Clear;
|
||||
posArray.Add(Tpoint.Create(pos));
|
||||
len := posArray.Count;
|
||||
dir := r;
|
||||
end;
|
||||
|
||||
destructor TSnake.Destroy;
|
||||
begin
|
||||
posArray.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TSnake.Eat(Fruit: TPoint): Boolean;
|
||||
begin
|
||||
result := (pos.X = Fruit.X) and (pos.y = Fruit.y);
|
||||
if result then
|
||||
begin
|
||||
inc(len);
|
||||
if len > 5000 then
|
||||
len := 500;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSnake.Overlap: Boolean;
|
||||
var
|
||||
aLen: Integer;
|
||||
tp: TPoint;
|
||||
i: Integer;
|
||||
begin
|
||||
aLen := posArray.count - 1;
|
||||
|
||||
for i := 0 to aLen - 1 do
|
||||
begin
|
||||
tp := posArray[i];
|
||||
if (tp.x = pos.x) and (tp.y = pos.y) then
|
||||
Exit(True);
|
||||
end;
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
procedure TSnake.update;
|
||||
begin
|
||||
if not alive then
|
||||
exit;
|
||||
case dir of
|
||||
l:
|
||||
begin
|
||||
dec(pos.X);
|
||||
if pos.X < 1 then
|
||||
pos.x := wid - 2
|
||||
end;
|
||||
r:
|
||||
begin
|
||||
inc(pos.x);
|
||||
if (pos.x > (wid - 2)) then
|
||||
pos.x := 1;
|
||||
end;
|
||||
U:
|
||||
begin
|
||||
dec(pos.y);
|
||||
|
||||
if (pos.y < 1) then
|
||||
pos.y := hei - 2
|
||||
end;
|
||||
D:
|
||||
begin
|
||||
inc(pos.y);
|
||||
|
||||
if (pos.y > hei - 2) then
|
||||
pos.y := 1;
|
||||
end;
|
||||
end;
|
||||
if Overlap then
|
||||
alive := False
|
||||
else
|
||||
begin
|
||||
posArray.Add(TPoint(pos));
|
||||
|
||||
if len < posArray.Count then
|
||||
posArray.Delete(0);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TFruit }
|
||||
|
||||
constructor TFruit.Create;
|
||||
begin
|
||||
Reset;
|
||||
end;
|
||||
|
||||
procedure TFruit.Paint(Canvas: TCanvas);
|
||||
var
|
||||
r: TRect;
|
||||
begin
|
||||
with Canvas do
|
||||
begin
|
||||
Brush.Color := rgb(200, 50, 20);
|
||||
|
||||
r := Rect(pos.x * block, pos.y * block, block, block);
|
||||
|
||||
FillRect(r);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFruit.Reset;
|
||||
begin
|
||||
fruitTime := true;
|
||||
pos := Tpoint.Create(0, 0);
|
||||
end;
|
||||
|
||||
procedure TFruit.SetFruit;
|
||||
begin
|
||||
pos.x := Trunc(Random(wid - 2) + 1);
|
||||
pos.y := Trunc(Random(hei - 2) + 1);
|
||||
fruitTime := false;
|
||||
end;
|
||||
|
||||
procedure TSnakeApp.DoFrameStep(Sender: TObject);
|
||||
begin
|
||||
Invalidate;
|
||||
end;
|
||||
|
||||
procedure TSnakeApp.FormClose(Sender: TObject; var Action: TCloseAction);
|
||||
begin
|
||||
FrameTimer.Free;
|
||||
snake.Free;
|
||||
Fruit.Free;
|
||||
end;
|
||||
|
||||
procedure TSnakeApp.FormCreate(Sender: TObject);
|
||||
begin
|
||||
Canvas.pen.Style := psClear;
|
||||
ClientHeight := block * hei;
|
||||
ClientWidth := block * wid;
|
||||
DoubleBuffered := True;
|
||||
KeyPreview := True;
|
||||
|
||||
OnClose := FormClose;
|
||||
OnKeyDown := FormKeyDown;
|
||||
OnPaint := FormPaint;
|
||||
|
||||
snake := TSnake.Create;
|
||||
Fruit := TFruit.Create();
|
||||
FrameTimer := TTimer.Create(nil);
|
||||
FrameTimer.Interval := 250;
|
||||
FrameTimer.OnTimer := DoFrameStep;
|
||||
FrameTimer.Enabled := True;
|
||||
end;
|
||||
|
||||
procedure TSnakeApp.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
|
||||
function ValidDir(value: Byte): Byte;
|
||||
var
|
||||
combination: Byte;
|
||||
begin
|
||||
combination := (value or snake.dir);
|
||||
if (combination = 3) or (combination = 12) then
|
||||
Result := snake.dir
|
||||
else
|
||||
Result := value;
|
||||
end;
|
||||
|
||||
begin
|
||||
case Key of
|
||||
VK_LEFT:
|
||||
snake.dir := ValidDir(l);
|
||||
VK_RIGHT:
|
||||
snake.dir := ValidDir(r);
|
||||
VK_UP:
|
||||
snake.dir := ValidDir(U);
|
||||
VK_DOWN:
|
||||
snake.dir := ValidDir(D);
|
||||
VK_ESCAPE:
|
||||
Reset;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSnakeApp.FormPaint(Sender: TObject);
|
||||
var
|
||||
i: Integer;
|
||||
r: TRect;
|
||||
frameR: Double;
|
||||
begin
|
||||
with Canvas do
|
||||
begin
|
||||
Brush.Color := rgb(0, $22, 0);
|
||||
FillRect(ClipRect);
|
||||
Brush.Color := rgb(20, 50, 120);
|
||||
|
||||
for i := 0 to wid - 1 do
|
||||
begin
|
||||
r := rect(i * block, 0, block, block);
|
||||
FillRect(r);
|
||||
r := rect(i * block, ClientHeight - block, block, block);
|
||||
FillRect(r);
|
||||
end;
|
||||
|
||||
for i := 1 to hei - 2 do
|
||||
begin
|
||||
r := Rect(1, i * block, block, block);
|
||||
FillRect(r);
|
||||
r := Rect(ClientWidth - block, i * block, block, block);
|
||||
FillRect(r);
|
||||
end;
|
||||
|
||||
if (Fruit.fruitTime) then
|
||||
begin
|
||||
Fruit.setFruit();
|
||||
frameR := FrameTimer.Interval * 0.95;
|
||||
if frameR < 30 then
|
||||
frameR := 30;
|
||||
FrameTimer.Interval := trunc(frameR);
|
||||
end;
|
||||
|
||||
Fruit.Paint(Canvas);
|
||||
snake.update();
|
||||
|
||||
if not snake.alive then
|
||||
begin
|
||||
FrameTimer.Enabled := False;
|
||||
Application.ProcessMessages;
|
||||
ShowMessage('Game over');
|
||||
Reset;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if (snake.eat(Fruit.pos)) then
|
||||
Fruit.fruitTime := true;
|
||||
snake.Paint(Canvas);
|
||||
|
||||
Brush.Style := bsClear;
|
||||
Font.Color := rgb(200, 200, 200);
|
||||
Font.Size := 18;
|
||||
TextOut(50, 0, (snake.len - 1).ToString);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSnakeApp.Reset;
|
||||
begin
|
||||
snake.Reset;
|
||||
Fruit.Reset;
|
||||
FrameTimer.Interval := 250;
|
||||
FrameTimer.Enabled := True;
|
||||
end;
|
||||
end.
|
||||
3
Task/Snake/Delphi/snake-2.delphi
Normal file
3
Task/Snake/Delphi/snake-2.delphi
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
object SnakeApp: TSnakeApp
|
||||
OnCreate = FormCreate
|
||||
end
|
||||
98
Task/Snake/EasyLang/snake.easy
Normal file
98
Task/Snake/EasyLang/snake.easy
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
subr fruit
|
||||
rx = (random 20 - 1) * 5 + 2.5
|
||||
ry = (random 20 - 1) * 5 + 2.5
|
||||
.
|
||||
subr start
|
||||
call fruit
|
||||
game = 1
|
||||
sx[] = [ 52.5 0 0 0 0 ]
|
||||
sy[] = [ 52.5 0 0 0 0 ]
|
||||
dir = random 4
|
||||
timer 0
|
||||
.
|
||||
background 242
|
||||
move 30 70
|
||||
clear
|
||||
color 997
|
||||
text "SNAKE"
|
||||
textsize 5
|
||||
move 10 40
|
||||
text "Arrow keys for control"
|
||||
move 10 30
|
||||
text "Press space to to start"
|
||||
#
|
||||
on key
|
||||
if keybkey = "ArrowUp" and dir <> 3
|
||||
dir = 1
|
||||
elif keybkey = "ArrowRight" and dir <> 4
|
||||
dir = 2
|
||||
elif keybkey = "ArrowDown" and dir <> 1
|
||||
dir = 3
|
||||
elif keybkey = "ArrowLeft" and dir <> 2
|
||||
dir = 4
|
||||
elif keybkey = " " and game = 0
|
||||
call start
|
||||
.
|
||||
.
|
||||
on timer
|
||||
clear
|
||||
color 997
|
||||
move 2 96
|
||||
text "Score: " & 10 * len sx[] - 50
|
||||
color 966
|
||||
move rx ry
|
||||
circle 1.5
|
||||
#
|
||||
sx = sx[1] ; sy = sy[1]
|
||||
if dir = 1
|
||||
sy += 5
|
||||
elif dir = 2
|
||||
sx += 5
|
||||
elif dir = 3
|
||||
sy -= 5
|
||||
elif dir = 4
|
||||
sx -= 5
|
||||
.
|
||||
if sx < 0 or sx > 100 or sy < 0 or sy > 100
|
||||
game = 0
|
||||
.
|
||||
color 494
|
||||
for i = len sx[] downto 2
|
||||
if sx = sx[i] and sy = sy[i]
|
||||
game = 0
|
||||
.
|
||||
sx[i] = sx[i - 1]
|
||||
sy[i] = sy[i - 1]
|
||||
if sx[i] > 0
|
||||
move sx[i] sy[i]
|
||||
circle 2.5
|
||||
.
|
||||
.
|
||||
move sx sy
|
||||
circle 2.5
|
||||
color 000
|
||||
if dir = 2 or dir = 4
|
||||
move sx sy + 1
|
||||
circle 0.5
|
||||
move sx sy - 1
|
||||
circle 0.5
|
||||
else
|
||||
move sx + 1 sy
|
||||
circle 0.5
|
||||
move sx - 1 sy
|
||||
circle 0.5
|
||||
.
|
||||
if sx = rx and sy = ry
|
||||
len sx[] len sx[] + 3
|
||||
len sy[] len sy[] + 3
|
||||
call fruit
|
||||
.
|
||||
sx[1] = sx ; sy[1] = sy
|
||||
if game = 1
|
||||
timer 0.15
|
||||
else
|
||||
color 997
|
||||
move 10 10
|
||||
text "Press space for new game"
|
||||
.
|
||||
.
|
||||
299
Task/Snake/F-Sharp/snake.fs
Normal file
299
Task/Snake/F-Sharp/snake.fs
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
open System
|
||||
open System.Threading.Tasks
|
||||
open System.Threading
|
||||
|
||||
module SnakeGame =
|
||||
|
||||
/// 🚏 Directions on our grid:
|
||||
type Movement =
|
||||
| Left of Position
|
||||
| Right of Position
|
||||
| Down of Position
|
||||
| Up of Position
|
||||
| InvalidMove
|
||||
|
||||
/// 🐍 Sort of like a list, but not:
|
||||
and Snake<'Position> =
|
||||
| Head of Position * Snake<'Position>
|
||||
| Belly of Position * Snake<'Position>
|
||||
| Tail
|
||||
|
||||
/// 🕹️ Our basic runtime information:
|
||||
and Game =
|
||||
| GameRunning of Movement * Snake<Position> * Grid * Eaten:int * Food
|
||||
| GameOver of Grid * Eaten:int
|
||||
|
||||
/// 🧭 x & y in our plane:
|
||||
and Position = int * int
|
||||
|
||||
/// 🍎 The food our snake will eat:
|
||||
and Food = Position * string
|
||||
|
||||
/// 🌐 A simple two dimensional plane:
|
||||
and Grid = string[][]
|
||||
|
||||
/// Making a list of positions from a Snake 🐍
|
||||
let snakeUnzip (snake:Snake<Position>) =
|
||||
let rec unzip snake carry =
|
||||
match snake with
|
||||
| Head (p, rest) -> unzip rest <| carry @ [p]
|
||||
| Belly (p, rest) -> unzip rest <| carry @ [p]
|
||||
| Tail -> carry
|
||||
unzip snake []
|
||||
|
||||
/// Making a Snake from a list of positions 🐍
|
||||
let snakeZip (positions:list<Position>) (upto:int) =
|
||||
let correctLength = (List.take upto positions)
|
||||
let rec zip (carry:Snake<Position>) (rest:list<Position>) =
|
||||
match rest with
|
||||
| head::[] -> zip (Head(head, carry)) []
|
||||
| back::front -> zip (Belly (back, carry)) front
|
||||
| [] -> carry
|
||||
zip Tail (List.rev correctLength)
|
||||
|
||||
module Graphics =
|
||||
let private random = new Random()
|
||||
let private head = "🤢"
|
||||
let private belly = "🟢"
|
||||
let private display = "⬜"
|
||||
let private errorDisplay = "🟥"
|
||||
|
||||
let private food = [|"🐁";"🐀";"🐥";"🪺";"🐸";"🐛";"🪰";"🐞";"🦗"|]
|
||||
let private randomFood () = food.[random.Next(food.Length - 1)]
|
||||
|
||||
let isFood square = Array.contains square food
|
||||
let isFreeSpace square = square = display || square = errorDisplay
|
||||
let isOccupied square =
|
||||
match square with
|
||||
| square when isFreeSpace square -> false
|
||||
| square when isFood square -> false
|
||||
| _ -> true
|
||||
|
||||
let makeGrid (dimensionsSquared) : Grid =
|
||||
let row _ = Array.init dimensionsSquared (fun _ -> display)
|
||||
Array.init dimensionsSquared row
|
||||
|
||||
let clearGrid (grid:Grid) : unit =
|
||||
Array.iteri (fun i row ->
|
||||
Array.iteri (fun j _ ->
|
||||
grid.[i].[j] <- display
|
||||
) row
|
||||
) grid
|
||||
|
||||
let render (grid:Grid) : unit =
|
||||
Console.Clear()
|
||||
Array.iter (fun (row:string array) ->
|
||||
let prettyprint = String.concat "" row
|
||||
printfn $"{prettyprint}") grid
|
||||
printfn "Snake Game in FSharp by @wiredsister"
|
||||
printfn "Controls: ⬅️ ↕️ ➡️"
|
||||
printfn "Press Ctrl+C to Quit Game"
|
||||
Console.Title <- "FSharp Snake 🐍"
|
||||
|
||||
let getFreeSpaces (grid:Grid) : list<Position> =
|
||||
let results : Position list ref = ref []
|
||||
for i in 0..(grid.Length-1) do
|
||||
for j in 0..(grid.Length-1) do
|
||||
if isFreeSpace grid.[i].[j]
|
||||
then results.Value <- results.Value @ [i,j]
|
||||
else ()
|
||||
()
|
||||
results.Value
|
||||
|
||||
let getFood (grid:Grid) : Food =
|
||||
Console.Beep()
|
||||
let freeSpaces =
|
||||
getFreeSpaces grid
|
||||
|> Array.ofList
|
||||
let food = randomFood ()
|
||||
let randomPos = freeSpaces.[random.Next(freeSpaces.Length - 1)]
|
||||
randomPos, food
|
||||
|
||||
let dropFood (grid:Grid) (food:Food) =
|
||||
let (x, y), animal = food
|
||||
grid.[x].[y] <- animal
|
||||
|
||||
let slither (snake:Snake<Position>) (grid:Grid) : unit =
|
||||
try
|
||||
let rec slithering (body:Snake<Position>) =
|
||||
match body with
|
||||
| Head(p, s) ->
|
||||
let row, column = p
|
||||
grid.[row].[column] <- head
|
||||
slithering s
|
||||
| Belly(p, s) ->
|
||||
let row, column = p
|
||||
grid.[row].[column] <- belly
|
||||
slithering s
|
||||
| Tail -> ()
|
||||
do slithering snake
|
||||
with _ -> failwith "ERROR: Could not slither snake!"
|
||||
|
||||
let endGame (grid:Grid) : unit =
|
||||
Console.Clear()
|
||||
Array.iteri (fun i row ->
|
||||
Array.iteri (fun j _ ->
|
||||
grid.[i].[j] <- errorDisplay
|
||||
) row
|
||||
) grid
|
||||
Array.iter (fun (row:string array) ->
|
||||
let prettyprint = String.concat "" row
|
||||
printfn $"{prettyprint}") grid
|
||||
Console.Beep()
|
||||
|
||||
|
||||
module GamePlay =
|
||||
|
||||
let moveUp (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
|
||||
match snake with
|
||||
| Head (p, rest:Snake<Position>) ->
|
||||
let x, y = p
|
||||
let shiftUp = ((x-1), y)
|
||||
try
|
||||
match shiftUp with
|
||||
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
|
||||
GameOver (grid, eaten)
|
||||
| (row, column) when Graphics.isFood grid.[row].[column] ->
|
||||
let unzipped = snakeUnzip (Head (shiftUp, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped (eaten+1)
|
||||
let nextFood = Graphics.getFood grid
|
||||
GameRunning (Up shiftUp, newSnake, grid, eaten+1, nextFood)
|
||||
| pivot ->
|
||||
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped eaten
|
||||
GameRunning (Up pivot, newSnake, grid, eaten, food)
|
||||
with _ -> GameOver (grid, eaten)
|
||||
| _ -> failwith "ERROR: No head!"
|
||||
|
||||
let moveDown (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
|
||||
match snake with
|
||||
| Head (p, rest:Snake<Position>) ->
|
||||
let x, y = p
|
||||
let shiftDown = ((x+1), y)
|
||||
try
|
||||
match shiftDown with
|
||||
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
|
||||
GameOver (grid, eaten)
|
||||
| (row, column) when Graphics.isFood grid.[row].[column] ->
|
||||
let unzipped = snakeUnzip (Head (shiftDown, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped (eaten+1)
|
||||
let nextFood = Graphics.getFood grid
|
||||
GameRunning (Down shiftDown, newSnake, grid, (eaten+1), nextFood)
|
||||
| pivot ->
|
||||
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped eaten
|
||||
GameRunning (Down pivot, newSnake, grid, eaten, food)
|
||||
with _ -> GameOver (grid, eaten)
|
||||
| _ -> failwith "ERROR: No head!"
|
||||
|
||||
let moveLeft (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
|
||||
match snake with
|
||||
| Head (p, rest:Snake<Position>) ->
|
||||
let x, y = p
|
||||
let shiftLeft = (x, (y-1))
|
||||
try
|
||||
match shiftLeft with
|
||||
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
|
||||
GameOver (grid, eaten)
|
||||
| (row, column) when Graphics.isFood grid.[row].[column] ->
|
||||
let unzipped = snakeUnzip (Head (shiftLeft, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped (eaten+1)
|
||||
let nextFood = Graphics.getFood grid
|
||||
GameRunning (Left shiftLeft, newSnake, grid, eaten+1, nextFood)
|
||||
| pivot ->
|
||||
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped eaten
|
||||
GameRunning (Left pivot, newSnake, grid, eaten, food)
|
||||
with _ -> GameOver (grid, eaten)
|
||||
| _ -> failwith "ERROR: No head!"
|
||||
|
||||
let moveRight (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
|
||||
match snake with
|
||||
| Head (p, rest:Snake<Position>) ->
|
||||
let (x: int), y = p
|
||||
let shiftRight = (x, (y+1))
|
||||
try
|
||||
match shiftRight with
|
||||
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
|
||||
GameOver (grid, eaten)
|
||||
| (row, column) when Graphics.isFood grid.[row].[column] ->
|
||||
let unzipped = snakeUnzip (Head (shiftRight, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped (eaten+1)
|
||||
let nextFood = Graphics.getFood grid
|
||||
GameRunning (Right shiftRight, newSnake, grid, eaten+1, nextFood)
|
||||
| pivot ->
|
||||
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
|
||||
let newSnake = snakeZip unzipped eaten
|
||||
GameRunning (Right pivot, newSnake, grid, eaten, food)
|
||||
with _ -> GameOver (grid, eaten)
|
||||
| _ -> failwith "ERROR: No head!"
|
||||
|
||||
open SnakeGame
|
||||
|
||||
[<EntryPoint>]
|
||||
let main _ =
|
||||
|
||||
/// A gentle slope function for making the snake go faster:
|
||||
let tick (eaten:int) = 100./log10(float eaten) |> int
|
||||
|
||||
let getNextMove prev snake grid eaten food : Task<Game> =
|
||||
task {
|
||||
do! Task.Delay(tick(eaten))
|
||||
if not Console.KeyAvailable
|
||||
then
|
||||
match prev with
|
||||
| Up _ -> return GamePlay.moveUp snake grid eaten food
|
||||
| Down _ -> return GamePlay.moveDown snake grid eaten food
|
||||
| Right _ -> return GamePlay.moveRight snake grid eaten food
|
||||
| Left _ -> return GamePlay.moveLeft snake grid eaten food
|
||||
| InvalidMove -> return GameOver (grid, eaten)
|
||||
else
|
||||
match Console.ReadKey() with
|
||||
| keystroke when keystroke.Key.Equals(ConsoleKey.UpArrow) ->
|
||||
return GamePlay.moveUp snake grid eaten food
|
||||
| keystroke when keystroke.Key.Equals(ConsoleKey.DownArrow) ->
|
||||
return GamePlay.moveDown snake grid eaten food
|
||||
| keystroke when keystroke.Key.Equals(ConsoleKey.RightArrow) ->
|
||||
return GamePlay.moveRight snake grid eaten food
|
||||
| keystroke when keystroke.Key.Equals(ConsoleKey.LeftArrow) ->
|
||||
return GamePlay.moveLeft snake grid eaten food
|
||||
| _ ->
|
||||
match prev with
|
||||
| Up _ -> return GamePlay.moveUp snake grid eaten food
|
||||
| Down _ -> return GamePlay.moveDown snake grid eaten food
|
||||
| Right _ -> return GamePlay.moveRight snake grid eaten food
|
||||
| Left _ -> return GamePlay.moveLeft snake grid eaten food
|
||||
| InvalidMove -> return GameOver (grid, eaten)
|
||||
}
|
||||
|
||||
let gridDimension = 20
|
||||
let segments = [(0,3); (0,2); (0,1); (0,0)]
|
||||
let youngSnake : Snake<Position> = snakeZip segments segments.Length
|
||||
let startingGrid = Graphics.makeGrid gridDimension
|
||||
let startingFood = Graphics.getFood startingGrid
|
||||
let start = GamePlay.moveRight youngSnake startingGrid segments.Length startingFood
|
||||
|
||||
let rec gameLoop (game:Game) =
|
||||
match game with
|
||||
| GameRunning (prev, snake, grid, eaten, food) ->
|
||||
do Graphics.clearGrid grid
|
||||
do Graphics.dropFood grid food
|
||||
do Graphics.slither snake grid
|
||||
do Graphics.render grid
|
||||
let eitherPlayerOrCursor = getNextMove prev snake grid eaten food
|
||||
do eitherPlayerOrCursor.Wait()
|
||||
gameLoop eitherPlayerOrCursor.Result
|
||||
| GameOver (grid,eaten) ->
|
||||
do Graphics.endGame grid
|
||||
printfn $"Game Over! Snake ate {eaten-segments.Length} critters!"
|
||||
do Thread.Sleep(1000)
|
||||
let rec wantToPlayAgain () =
|
||||
match Console.ReadKey() with
|
||||
| keystroke when keystroke.Key.Equals(ConsoleKey.Y) -> gameLoop start
|
||||
| keystroke when keystroke.Key.Equals(ConsoleKey.N) -> ()
|
||||
| _ -> wantToPlayAgain ()
|
||||
printfn $"Restart? Type Y to continue..."
|
||||
wantToPlayAgain()
|
||||
|
||||
do gameLoop start
|
||||
0
|
||||
115
Task/Snake/FreeBASIC/snake.basic
Normal file
115
Task/Snake/FreeBASIC/snake.basic
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
REM Snake
|
||||
|
||||
#define EXTCHAR Chr(255)
|
||||
|
||||
Dim Shared As Integer puntos, contar, longitud, posX, posY, oldhi = 0
|
||||
Dim Shared As Integer x(500), y(500)
|
||||
For contar = 1 To 500
|
||||
x(contar) = 0 : y(contar) = 0
|
||||
Next contar
|
||||
Dim Shared As Byte fruitX, fruitY, convida
|
||||
Dim Shared As Single delay
|
||||
Dim Shared As String direccion, usuario
|
||||
|
||||
Sub Intro
|
||||
Cls
|
||||
Color 15, 0
|
||||
Print " _ _ _ _ "
|
||||
Print " / \ / \ / \ / \ "
|
||||
Print " ___________/ _\/ _\/ _\/ _\____________ "
|
||||
Print " __________/ /_/ /_/ /_/ /______________ "
|
||||
Print " | /\ /\ /\ / \ \___ "
|
||||
Print " |/ \_/ \_/ \_/ \ "+Chr(248)+"\ "
|
||||
Print " \___/--< "
|
||||
Color 14, 0
|
||||
Locate 10, 28: Print "---SNAKE---"
|
||||
Locate 12, 4: Print "Para jugar, usa las teclas de flecha para moverte."
|
||||
Locate 13, 4: Print "Pulsa <1-3> para velocidad, o <Esc> para salir."
|
||||
If puntos > oldhi Then oldhi = puntos
|
||||
Locate 14, 4: Print "M xima puntuaci¢n: "; oldhi
|
||||
usuario = ""
|
||||
While usuario = ""
|
||||
usuario = Inkey
|
||||
Wend
|
||||
If usuario = Chr(27) Then End 'ESC
|
||||
delay = .14
|
||||
If usuario = "1" Then delay = .26
|
||||
If usuario = "3" Then delay = .08
|
||||
Cls
|
||||
longitud = 9
|
||||
puntos = 0
|
||||
posX = 40 : posY = 10
|
||||
direccion = "derecha"
|
||||
convida = true
|
||||
fruitX = Int(Rnd * 79) + 1
|
||||
fruitY = Int(Rnd * 20) + 1
|
||||
Locate 22, 1
|
||||
For contar = 1 To 80
|
||||
Print Chr(196); ''"-";
|
||||
Next contar
|
||||
End Sub
|
||||
|
||||
Sub MenuPrincipal
|
||||
Dim As Integer num, oldX, oldY
|
||||
Dim As Single tm, tm2
|
||||
|
||||
Color 10
|
||||
Locate 23, 2: Print "SNAKE - <Esc> salir - Puntos: "; puntos
|
||||
If posX = fruitX And posY = fruitY Then
|
||||
longitud += 1
|
||||
puntos += 1
|
||||
fruitX = Int(Rnd * 79) + 1
|
||||
fruitY = Int(Rnd * 21) + 1
|
||||
End If
|
||||
Locate fruitY, fruitX : Color 12: Print Chr(01) : Color 10'"@"
|
||||
x(0) = posX : y(0) = posY
|
||||
|
||||
For contar = 1 To 499
|
||||
num = 500 - contar
|
||||
x(num) = x(num - 1)
|
||||
y(num) = y(num - 1)
|
||||
Next contar
|
||||
|
||||
oldX = x(longitud) : oldY = y(longitud)
|
||||
If oldX > 0 And oldY > 0 Then Locate oldY, oldX : Print " "
|
||||
|
||||
Locate posY, posX: Print Chr(219) '"Û"
|
||||
tm = Timer
|
||||
tm2 = tm + delay
|
||||
While tm < tm2
|
||||
tm = Timer
|
||||
usuario = Inkey
|
||||
If usuario = EXTCHAR & "H" Then direccion = "arriba"
|
||||
If usuario = EXTCHAR & "P" Then direccion = "abajo"
|
||||
If usuario = EXTCHAR & "K" Then direccion = "izquierda"
|
||||
If usuario = EXTCHAR & "M" Then direccion = "derecha"
|
||||
If usuario = Chr(27) Then Intro
|
||||
Wend
|
||||
If direccion = "derecha" Then posX += 1
|
||||
If posX > 80 Then convida = false
|
||||
If direccion = "izquierda" Then posX -= 1
|
||||
If posX < 1 Then convida = false
|
||||
If direccion = "arriba" Then posY -= 1
|
||||
If posY < 1 Then convida = false
|
||||
If direccion = "abajo" Then posY += 1
|
||||
If posY > 21 Then convida = false
|
||||
|
||||
For contar = 0 To longitud
|
||||
If posX = x(contar) And posY = y(contar) Then convida = false
|
||||
Next contar
|
||||
|
||||
If convida = false Then
|
||||
Cls : Locate 11, 19: Print "Pulsa <space>..."
|
||||
Locate 10, 18: Print "Has muerto! Con"; puntos; " puntos." : Sleep
|
||||
While Inkey = "": Wend
|
||||
Intro
|
||||
End If
|
||||
MenuPrincipal
|
||||
End Sub
|
||||
|
||||
'--- Programa Principal ---
|
||||
Randomize Timer
|
||||
Intro
|
||||
MenuPrincipal
|
||||
End
|
||||
'--------------------------
|
||||
235
Task/Snake/Go/snake.go
Normal file
235
Task/Snake/Go/snake.go
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
termbox "github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
score, err := playSnake()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("Final score:", score)
|
||||
}
|
||||
|
||||
type snake struct {
|
||||
body []position // tail to head positions of the snake
|
||||
heading direction
|
||||
width, height int
|
||||
cells []termbox.Cell
|
||||
}
|
||||
|
||||
type position struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
type direction int
|
||||
|
||||
const (
|
||||
North direction = iota
|
||||
East
|
||||
South
|
||||
West
|
||||
)
|
||||
|
||||
func (p position) next(d direction) position {
|
||||
switch d {
|
||||
case North:
|
||||
p.Y--
|
||||
case East:
|
||||
p.X++
|
||||
case South:
|
||||
p.Y++
|
||||
case West:
|
||||
p.X--
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func playSnake() (int, error) {
|
||||
err := termbox.Init()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer termbox.Close()
|
||||
|
||||
termbox.Clear(fg, bg)
|
||||
termbox.HideCursor()
|
||||
s := &snake{
|
||||
// It would be more efficient to use a circular
|
||||
// buffer instead of a plain slice for s.body.
|
||||
body: make([]position, 0, 32),
|
||||
cells: termbox.CellBuffer(),
|
||||
}
|
||||
s.width, s.height = termbox.Size()
|
||||
s.drawBorder()
|
||||
s.startSnake()
|
||||
s.placeFood()
|
||||
s.flush()
|
||||
|
||||
moveCh, errCh := s.startEventLoop()
|
||||
const delay = 125 * time.Millisecond
|
||||
for t := time.NewTimer(delay); ; t.Reset(delay) {
|
||||
var move direction
|
||||
select {
|
||||
case err = <-errCh:
|
||||
return len(s.body), err
|
||||
case move = <-moveCh:
|
||||
if !t.Stop() {
|
||||
<-t.C // handles race between moveCh and t.C
|
||||
}
|
||||
case <-t.C:
|
||||
move = s.heading
|
||||
}
|
||||
if s.doMove(move) {
|
||||
time.Sleep(1 * time.Second)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return len(s.body), err
|
||||
}
|
||||
|
||||
func (s *snake) startEventLoop() (<-chan direction, <-chan error) {
|
||||
moveCh := make(chan direction)
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(errCh)
|
||||
for {
|
||||
switch ev := termbox.PollEvent(); ev.Type {
|
||||
case termbox.EventKey:
|
||||
switch ev.Ch { // WSAD and HJKL movement
|
||||
case 'w', 'W', 'k', 'K':
|
||||
moveCh <- North
|
||||
case 'a', 'A', 'h', 'H':
|
||||
moveCh <- West
|
||||
case 's', 'S', 'j', 'J':
|
||||
moveCh <- South
|
||||
case 'd', 'D', 'l', 'L':
|
||||
moveCh <- East
|
||||
case 0:
|
||||
switch ev.Key { // Cursor key movement
|
||||
case termbox.KeyArrowUp:
|
||||
moveCh <- North
|
||||
case termbox.KeyArrowDown:
|
||||
moveCh <- South
|
||||
case termbox.KeyArrowLeft:
|
||||
moveCh <- West
|
||||
case termbox.KeyArrowRight:
|
||||
moveCh <- East
|
||||
case termbox.KeyEsc: // Quit
|
||||
return
|
||||
}
|
||||
}
|
||||
case termbox.EventResize:
|
||||
// TODO
|
||||
errCh <- errors.New("terminal resizing unsupported")
|
||||
return
|
||||
case termbox.EventError:
|
||||
errCh <- ev.Err
|
||||
return
|
||||
case termbox.EventInterrupt:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return moveCh, errCh
|
||||
}
|
||||
|
||||
func (s *snake) flush() {
|
||||
termbox.Flush()
|
||||
s.cells = termbox.CellBuffer()
|
||||
}
|
||||
|
||||
func (s *snake) getCellRune(p position) rune {
|
||||
i := p.Y*s.width + p.X
|
||||
return s.cells[i].Ch
|
||||
}
|
||||
func (s *snake) setCell(p position, c termbox.Cell) {
|
||||
i := p.Y*s.width + p.X
|
||||
s.cells[i] = c
|
||||
}
|
||||
|
||||
func (s *snake) drawBorder() {
|
||||
for x := 0; x < s.width; x++ {
|
||||
s.setCell(position{x, 0}, border)
|
||||
s.setCell(position{x, s.height - 1}, border)
|
||||
}
|
||||
for y := 0; y < s.height-1; y++ {
|
||||
s.setCell(position{0, y}, border)
|
||||
s.setCell(position{s.width - 1, y}, border)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *snake) placeFood() {
|
||||
for {
|
||||
// a random empty cell
|
||||
x := rand.Intn(s.width-2) + 1
|
||||
y := rand.Intn(s.height-2) + 1
|
||||
foodp := position{x, y}
|
||||
r := s.getCellRune(foodp)
|
||||
if r != ' ' {
|
||||
continue
|
||||
}
|
||||
s.setCell(foodp, food)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *snake) startSnake() {
|
||||
// a random cell somewhat near the center
|
||||
x := rand.Intn(s.width/2) + s.width/4
|
||||
y := rand.Intn(s.height/2) + s.height/4
|
||||
head := position{x, y}
|
||||
s.setCell(head, snakeHead)
|
||||
s.body = append(s.body[:0], head)
|
||||
s.heading = direction(rand.Intn(4))
|
||||
}
|
||||
|
||||
func (s *snake) doMove(move direction) bool {
|
||||
head := s.body[len(s.body)-1]
|
||||
s.setCell(head, snakeBody)
|
||||
head = head.next(move)
|
||||
s.heading = move
|
||||
s.body = append(s.body, head)
|
||||
r := s.getCellRune(head)
|
||||
s.setCell(head, snakeHead)
|
||||
gameOver := false
|
||||
switch r {
|
||||
case food.Ch:
|
||||
s.placeFood()
|
||||
case border.Ch, snakeBody.Ch:
|
||||
gameOver = true
|
||||
fallthrough
|
||||
case empty.Ch:
|
||||
s.setCell(s.body[0], empty)
|
||||
s.body = s.body[1:]
|
||||
default:
|
||||
panic(r)
|
||||
}
|
||||
s.flush()
|
||||
return gameOver
|
||||
}
|
||||
|
||||
const (
|
||||
fg = termbox.ColorWhite
|
||||
bg = termbox.ColorBlack
|
||||
)
|
||||
|
||||
// Symbols to use.
|
||||
// Could use Unicode instead of simple ASCII.
|
||||
var (
|
||||
empty = termbox.Cell{Ch: ' ', Bg: bg, Fg: fg}
|
||||
border = termbox.Cell{Ch: '+', Bg: bg, Fg: termbox.ColorBlue}
|
||||
snakeBody = termbox.Cell{Ch: '#', Bg: bg, Fg: termbox.ColorGreen}
|
||||
snakeHead = termbox.Cell{Ch: 'O', Bg: bg, Fg: termbox.ColorYellow | termbox.AttrBold}
|
||||
food = termbox.Cell{Ch: '@', Bg: bg, Fg: termbox.ColorRed}
|
||||
)
|
||||
100
Task/Snake/Haskell/snake-1.hs
Normal file
100
Task/Snake/Haskell/snake-1.hs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
{-# LANGUAGE TemplateHaskell #-}
|
||||
import Control.Monad.Random (getRandomRs)
|
||||
import Graphics.Gloss.Interface.Pure.Game
|
||||
import Lens.Micro ((%~), (^.), (&), set)
|
||||
import Lens.Micro.TH (makeLenses)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- all data types
|
||||
|
||||
data Snake = Snake { _body :: [Point], _direction :: Point }
|
||||
makeLenses ''Snake
|
||||
|
||||
data World = World { _snake :: Snake , _food :: [Point]
|
||||
, _score :: Int , _maxScore :: Int }
|
||||
makeLenses ''World
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- everything snake can do
|
||||
|
||||
moves (Snake b d) = Snake (step b d : init b) d
|
||||
eats (Snake b d) = Snake (step b d : b) d
|
||||
bites (Snake b _) = any (== head b)
|
||||
step ((x,y):_) (a,b) = (x+a, y+b)
|
||||
|
||||
turn (x',y') (Snake b (x,y)) | (x+x',y+y') == (0,0) = Snake b (x,y)
|
||||
| otherwise = Snake b (x',y')
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- all randomness
|
||||
|
||||
createWorld = do xs <- map fromIntegral <$> getRandomRs (2, 38 :: Int)
|
||||
ys <- map fromIntegral <$> getRandomRs (2, 38 :: Int)
|
||||
return (Ok, World snake (zip xs ys) 0 0)
|
||||
where
|
||||
snake = Snake [(20, 20)] (1,0)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- A tyny DSL for declarative description of business logic
|
||||
|
||||
data Status = Ok | Fail | Stop
|
||||
|
||||
continue = \x -> (Ok, x)
|
||||
stop = \x -> (Stop, x)
|
||||
f >>> g = \x -> case f x of { (Ok, y) -> g y; b -> b } -- chain composition
|
||||
f <|> g = \x -> case f x of { (Fail, _) -> g x; b -> b } -- alternative
|
||||
p ==> f = \x -> if p x then f x else (Fail, x) -- condition
|
||||
l .& f = continue . (l %~ f) -- modification
|
||||
l .= y = continue . set l y -- setting
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- all business logic
|
||||
|
||||
updateWorld _ = id >>> (snakeEats <|> snakeMoves)
|
||||
where
|
||||
snakeEats = (snakeFindsFood ==> (snake .& eats)) >>>
|
||||
(score .& (+1)) >>> (food .& tail)
|
||||
|
||||
snakeMoves = (snakeBitesTail ==> stop) <|>
|
||||
(snakeHitsWall ==> stop) <|>
|
||||
(snake .& moves)
|
||||
|
||||
snakeFindsFood w = (w^.snake & moves) `bites` (w^.food & take 1)
|
||||
snakeBitesTail w = (w^.snake) `bites` (w^.snake.body & tail)
|
||||
snakeHitsWall w = (w^.snake.body) & head & isOutside
|
||||
isOutside (x,y) = or [x <= 0, 40 <= x, y <= 0, 40 <= y]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- all event handing
|
||||
|
||||
handleEvents e (s,w) = f w
|
||||
where f = case s of
|
||||
Ok -> case e of
|
||||
EventKey (SpecialKey k) _ _ _ -> case k of
|
||||
KeyRight -> snake .& turn (1,0)
|
||||
KeyLeft -> snake .& turn (-1,0)
|
||||
KeyUp -> snake .& turn (0,1)
|
||||
KeyDown -> snake .& turn (0,-1)
|
||||
_-> continue
|
||||
_-> continue
|
||||
_-> \w -> w & ((snake.body) .= [(20,20)]) >>>
|
||||
(maxScore .& max (w^.score)) >>> (score .= 0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- all graphics
|
||||
|
||||
renderWorld (s, w) = pictures [frame, color c drawSnake, drawFood, showScore]
|
||||
where c = case s of { Ok -> orange; _-> red }
|
||||
drawSnake = foldMap (rectangleSolid 10 10 `at`) (w^.snake.body)
|
||||
drawFood = color blue $ circleSolid 5 `at` (w^.food & head)
|
||||
frame = color black $ rectangleWire 400 400
|
||||
showScore = color orange $ scale 0.2 0.2 $ txt `at` (-80,130)
|
||||
txt = Text $ mconcat ["Score: ", w^.score & show
|
||||
," Maximal score: ", w^.maxScore & show]
|
||||
at p (x,y) = Translate (10*x-200) (10*y-200) p
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
main = do world <- createWorld
|
||||
play inW white 7 world renderWorld handleEvents updateWorld
|
||||
where inW = InWindow "The Snake" (400, 400) (10, 10)
|
||||
1
Task/Snake/Haskell/snake-2.hs
Normal file
1
Task/Snake/Haskell/snake-2.hs
Normal file
|
|
@ -0,0 +1 @@
|
|||
updateWorld _ = id >>> snakeSeeksFood >>> (snakeEats <|> snakeMoves)
|
||||
13
Task/Snake/Haskell/snake-3.hs
Normal file
13
Task/Snake/Haskell/snake-3.hs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
snakeSeeksFood w = w & snake .& turns optimalDirection
|
||||
where
|
||||
optimalDirection = minimumBy (comparing distanceToFood) safeTurns
|
||||
|
||||
safeTurns = filter safe [(x,y),(-y,x),(y,-x)] `ifEmpty` [(x,y)]
|
||||
where (x,y) = w^.snake.direction
|
||||
safe d = let w'' = w & snake %~ moves . turns d
|
||||
in not (snakeBitesTail w'' || snakeHitsWall w'')
|
||||
lst `ifEmpty` x = if null lst then x else lst
|
||||
|
||||
distanceToFood d = let (a,b) = w^.snake & turns d & moves & (^.body) & head
|
||||
(x,y) = w^.food & head
|
||||
in (a-x)^2 + (b-y)^2
|
||||
10
Task/Snake/Integer-BASIC/snake.basic
Normal file
10
Task/Snake/Integer-BASIC/snake.basic
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
0 IF B=Q THEN GOTO 9: IF B THEN D=D(B): IF B THEN E=E(B):X=X+D:Y=Y+E:A= SCRN(X,Y): COLOR=S: PLOT X,Y: COLOR=R: PLOT X(N),Y(N)
|
||||
1 N=N-T+(N=1)*M:X(N)=X:Y(N)=Y: IF C(A) THEN GOTO 9: IF A THEN GOTO 2: COLOR=0: PLOT X(O),Y(O):O=O-T+(O=1)*M: GOTO 3
|
||||
2 U= RND (L):V= RND (L): IF SCRN(U,V)>0 THEN GOTO 2: COLOR=F: PLOT U,V
|
||||
3 K= PEEK (I):B= PEEK (J*(K>H)):B=K(K): GOTO 0
|
||||
4 DIM X(1600),Y(1600),K(255),D(4),E(4),C(15): FOR I=0 TO 255:K(I)=0: NEXT I: FOR I=1 TO 4:D(I)=0:E(I)=0: NEXT I
|
||||
5 FOR I=0 TO 15:C(I)=0: NEXT I:Q=5:X=20:Y=20:E(1)=-1:D(2)=-1:E(3)=1:D(4)=1:S=13:R=9:F=4:W=10:T=1:L=40:M=1600
|
||||
6 H=127:I=-16384:J=-16368:K(155)=5:K(193)=1:K(225)=1:K(201)=1:K(233)=1:K(136)=2:K(202)=2:K(234)=2:N=1:O=1
|
||||
7 K(218)=3:K(250)=3:K(203)=3:K(235)=3:K(149)=4:K(204)=4:K(236)=4:C(S)=T:C(R)=T:C(W)=T:B= RND (4)+T:D=D(B)
|
||||
8 E=E(B):X(O)=X:Y(O)=Y: GR : CALL -936: COLOR=W: VLIN 0,39 AT 0: VLIN 0,39 AT 39: HLIN 1,38 AT 0: HLIN 1,38 AT 39: COLOR=F: PLOT X+D,Y+E: GOTO 0
|
||||
9 IF Q#5 THEN GOTO 4:Q=Q*(B=Q): COLOR=T: IF Q=0 THEN PLOT X,Y: IF Q=0 THEN PRINT "GAME OVER";: IF Q THEN PRINT "DONE";:K= PEEK (J):B=0: END
|
||||
70
Task/Snake/J/snake.j
Normal file
70
Task/Snake/J/snake.j
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
require'ide/qt/gl2'
|
||||
coinsert 'jgl2'
|
||||
|
||||
open=: wd@{{)n
|
||||
pc s closeok;
|
||||
cc n isidraw;
|
||||
set n wh 400 400;
|
||||
pshow;
|
||||
}}
|
||||
|
||||
start=: {{
|
||||
speed=: {.y,200
|
||||
open''
|
||||
snake=: 10 10,10 11,:10 12
|
||||
newdot''
|
||||
draw''
|
||||
}}
|
||||
|
||||
newdot=: {{
|
||||
dot=: ({~ ?@#) snake -.~ ,/(#: i.)40 40
|
||||
}}
|
||||
|
||||
s_n_char=: {{
|
||||
select. {.toupper sysdata
|
||||
case. 'W' do. move 0 _1
|
||||
case. 'A' do. move _1 0
|
||||
case. 'S' do. move 0 1
|
||||
case. 'D' do. move 1 0
|
||||
end.
|
||||
}}
|
||||
|
||||
move=: {{
|
||||
s_timer=: move@y
|
||||
wd 'ptimer ',":speed
|
||||
head=. y+{.snake
|
||||
if. head e. snake do. head gameover'' return. end.
|
||||
if. _1 e. head do. (0>.head) gameover'' return. end.
|
||||
if. 1 e. 40 <: head do. (39<.head) gameover'' return. end.
|
||||
if. dot -: head do.
|
||||
snake=: dot,snake
|
||||
newdot''
|
||||
else.
|
||||
snake=: head,}: snake
|
||||
end.
|
||||
draw''
|
||||
}}
|
||||
|
||||
draw=: {{
|
||||
glclear''
|
||||
glbrush glrgb 0 0 255
|
||||
glrect 10*}.snake,"1(1 1)
|
||||
glbrush glrgb 0 255 0
|
||||
glrect 10*({.snake),1 1
|
||||
glbrush glrgb 255 0 0
|
||||
glrect 10*dot,1 1
|
||||
glpaint''
|
||||
EMPTY
|
||||
}}
|
||||
|
||||
gameover=: {{
|
||||
wd 'ptimer 0'
|
||||
if. 1<#snake do.
|
||||
echo 'game over'
|
||||
echo 'score: ',":(#snake)*1000%speed
|
||||
draw''
|
||||
glbrush glrgb 255 255 0
|
||||
glrect 10*x,1 1
|
||||
end.
|
||||
snake=: ,:_ _
|
||||
}}
|
||||
107
Task/Snake/JavaScript/snake.js
Normal file
107
Task/Snake/JavaScript/snake.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
const L = 1, R = 2, D = 4, U = 8;
|
||||
var block = 24, wid = 30, hei = 20, frameR = 7, fruit, snake;
|
||||
function Snake() {
|
||||
this.length = 1;
|
||||
this.alive = true;
|
||||
this.pos = createVector( 1, 1 );
|
||||
this.posArray = [];
|
||||
this.posArray.push( createVector( 1, 1 ) );
|
||||
this.dir = R;
|
||||
this.draw = function() {
|
||||
fill( 130, 190, 0 );
|
||||
var pos, i = this.posArray.length - 1, l = this.length;
|
||||
while( true ){
|
||||
pos = this.posArray[i--];
|
||||
rect( pos.x * block, pos.y * block, block, block );
|
||||
if( --l == 0 ) break;
|
||||
}
|
||||
}
|
||||
this.eat = function( frut ) {
|
||||
var b = this.pos.x == frut.x && this.pos.y == frut.y;
|
||||
if( b ) this.length++;
|
||||
return b;
|
||||
}
|
||||
this.overlap = function() {
|
||||
var len = this.posArray.length - 1;
|
||||
for( var i = len; i > len - this.length; i-- ) {
|
||||
tp = this.posArray[i];
|
||||
if( tp.x === this.pos.x && tp.y === this.pos.y ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.update = function() {
|
||||
if( !this.alive ) return;
|
||||
switch( this.dir ) {
|
||||
case L:
|
||||
this.pos.x--; if( this.pos.x < 1 ) this.pos.x = wid - 2;
|
||||
break;
|
||||
case R:
|
||||
this.pos.x++; if( this.pos.x > wid - 2 ) this.pos.x = 1;
|
||||
break;
|
||||
case U:
|
||||
this.pos.y--; if( this.pos.y < 1 ) this.pos.y = hei - 2;
|
||||
break;
|
||||
case D:
|
||||
this.pos.y++; if( this.pos.y > hei - 2 ) this.pos.y = 1;
|
||||
break;
|
||||
}
|
||||
if( this.overlap() ) { this.alive = false; } else {
|
||||
this.posArray.push( createVector( this.pos.x, this.pos.y ) );
|
||||
if( this.posArray.length > 5000 ) { this.posArray.splice( 0, 1 ); }
|
||||
}
|
||||
}
|
||||
}
|
||||
function Fruit() {
|
||||
this.fruitTime = true;
|
||||
this.pos = createVector();
|
||||
this.draw = function() {
|
||||
fill( 200, 50, 20 );
|
||||
rect( this.pos.x * block, this.pos.y * block, block, block );
|
||||
}
|
||||
|
||||
this.setFruit = function() {
|
||||
this.pos.x = floor( random( 1, wid - 1 ) );
|
||||
this.pos.y = floor( random( 1, hei - 1 ) );
|
||||
this.fruitTime = false;
|
||||
}
|
||||
}
|
||||
function setup() {
|
||||
createCanvas( block * wid, block * hei );
|
||||
noStroke(); frameRate( frameR );
|
||||
snake = new Snake();fruit = new Fruit();
|
||||
}
|
||||
function keyPressed() {
|
||||
switch( keyCode ) {
|
||||
case LEFT_ARROW: snake.dir = L; break;
|
||||
case RIGHT_ARROW: snake.dir = R; break;
|
||||
case UP_ARROW: snake.dir = U; break;
|
||||
case DOWN_ARROW: snake.dir = D;
|
||||
}
|
||||
}
|
||||
function draw() {
|
||||
background( color( 0, 0x22, 0 ) );
|
||||
fill( 20, 50, 120 );
|
||||
for( var i = 0; i < wid; i++ ) {
|
||||
rect( i * block, 0, block, block );
|
||||
rect( i * block, height - block, block, block );
|
||||
}
|
||||
for( var i = 1; i < hei - 1; i++ ) {
|
||||
rect( 1, i * block, block, block );
|
||||
rect( width - block, i * block, block, block );
|
||||
}
|
||||
if( fruit.fruitTime ) {
|
||||
fruit.setFruit();
|
||||
frameR += .2;
|
||||
frameRate( frameR );
|
||||
}
|
||||
fruit.draw();
|
||||
snake.update();
|
||||
if( snake.eat( fruit.pos ) ) {
|
||||
fruit.fruitTime = true;
|
||||
}
|
||||
snake.draw();
|
||||
fill( 200 );
|
||||
textStyle( BOLD ); textAlign( RIGHT ); textSize( 120 );
|
||||
text( ""+( snake.length - 1 ), 690, 440 );
|
||||
if( !snake.alive ) text( "THE END", 630, 250 );
|
||||
}
|
||||
102
Task/Snake/Julia/snake.julia
Normal file
102
Task/Snake/Julia/snake.julia
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using GLMakie, GeometryBasics
|
||||
|
||||
mutable struct SnakeGame
|
||||
height::Int
|
||||
width::Int
|
||||
snake::Vector{CartesianIndex{2}}
|
||||
food::CartesianIndex{2}
|
||||
end
|
||||
|
||||
function SnakeGame(;height=6, width=8)
|
||||
snake = [rand(CartesianIndices((height, width)))]
|
||||
food = rand(CartesianIndices((height, width)))
|
||||
while food == snake[1]
|
||||
food = rand(CartesianIndices((height, width)))
|
||||
end
|
||||
SnakeGame(height, width, snake, food)
|
||||
end
|
||||
|
||||
function step!(game, direction)
|
||||
next_head = game.snake[1] + direction
|
||||
next_head = CartesianIndex(mod.(next_head.I, Base.OneTo.((game.height, game.width)))) # allow crossing boundry
|
||||
if is_valid(game, next_head)
|
||||
pushfirst!(game.snake, next_head)
|
||||
if next_head == game.food
|
||||
length(game.snake) < game.height * game.width && init_food!(game)
|
||||
else
|
||||
pop!(game.snake)
|
||||
end
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
is_valid(game, position) = position ∉ game.snake
|
||||
|
||||
function init_food!(game)
|
||||
p = rand(CartesianIndices((game.height, game.width)))
|
||||
while !is_valid(game, p)
|
||||
p = rand(CartesianIndices((game.height, game.width)))
|
||||
end
|
||||
game.food = p
|
||||
end
|
||||
|
||||
function play(;n=10,t=0.5)
|
||||
game = Observable(SnakeGame(;width=n,height=n))
|
||||
scene = Scene(resolution = (1000, 1000), raw = true, camera = campixel!)
|
||||
display(scene)
|
||||
|
||||
area = scene.px_area
|
||||
poly!(scene, area)
|
||||
|
||||
grid_size = @lift((widths($area)[1] / $game.height, widths($area)[2] / $game.width))
|
||||
|
||||
snake_boxes = @lift([FRect2D((p.I .- (1,1)) .* $grid_size , $grid_size) for p in $game.snake])
|
||||
poly!(scene, snake_boxes, color=:blue, strokewidth = 5, strokecolor = :black)
|
||||
|
||||
snake_head_box = @lift(FRect2D(($game.snake[1].I .- (1,1)) .* $grid_size , $grid_size))
|
||||
poly!(scene, snake_head_box, color=:black)
|
||||
snake_head = @lift((($game.snake[1].I .- 0.5) .* $grid_size))
|
||||
scatter!(scene, snake_head, marker='◉', color=:blue, markersize=@lift(minimum($grid_size)))
|
||||
|
||||
food_position = @lift(($game.food.I .- (0.5,0.5)) .* $grid_size)
|
||||
scatter!(scene, food_position, color=:red, marker='♥', markersize=@lift(minimum($grid_size)))
|
||||
|
||||
score_text = @lift("Score: $(length($game.snake)-1)")
|
||||
text!(scene, score_text, color=:gray, position = @lift((widths($area)[1]/2, widths($area)[2])), fontsize = 50, align = (:center, :top))
|
||||
|
||||
direction = Ref{Any}(nothing)
|
||||
|
||||
on(events(scene).keyboardbutton) do but
|
||||
if but.action == Keyboard.press || but.action == Keyboard.repeat
|
||||
if but.key == Keyboard.left
|
||||
direction[] = CartesianIndex(-1,0)
|
||||
elseif but.key == Keyboard.up
|
||||
direction[] = CartesianIndex(0,1)
|
||||
elseif but.key == Keyboard.down
|
||||
direction[] = CartesianIndex(0,-1)
|
||||
elseif but.key == Keyboard.right
|
||||
direction[] = CartesianIndex(1,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
last_dir = nothing
|
||||
while true
|
||||
# avoid turn back
|
||||
if !isnothing(direction[]) && (isnothing(last_dir) || direction[] != -last_dir)
|
||||
last_dir = direction[]
|
||||
end
|
||||
if !isnothing(last_dir)
|
||||
if step!(game[], last_dir)
|
||||
game[] = game[]
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
sleep(t)
|
||||
end
|
||||
end
|
||||
|
||||
play()
|
||||
182
Task/Snake/Kotlin/snake.kotlin
Normal file
182
Task/Snake/Kotlin/snake.kotlin
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// Kotlin Native v0.5
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import platform.posix.*
|
||||
import platform.windows.*
|
||||
|
||||
const val WID = 60
|
||||
const val HEI = 30
|
||||
const val MAX_LEN = 600
|
||||
const val NUL = '\u0000'
|
||||
|
||||
enum class Dir { NORTH, EAST, SOUTH, WEST }
|
||||
|
||||
class Snake {
|
||||
val console: HANDLE
|
||||
var alive = false
|
||||
val brd = CharArray(WID * HEI)
|
||||
var dir = Dir.NORTH
|
||||
val snk = nativeHeap.allocArray<COORD>(MAX_LEN)
|
||||
lateinit var head: COORD
|
||||
var tailIdx = 0
|
||||
var headIdx = 0
|
||||
var points = 0
|
||||
|
||||
init {
|
||||
console = GetStdHandle(STD_OUTPUT_HANDLE)!!
|
||||
SetConsoleTitleW("Snake")
|
||||
memScoped {
|
||||
val coord = alloc<COORD>().apply { X = (WID + 1).toShort(); Y = (HEI + 2).toShort() }
|
||||
SetConsoleScreenBufferSize(console, coord.readValue())
|
||||
val rc = alloc<SMALL_RECT>().apply {
|
||||
Left = 0; Top = 0; Right = WID.toShort(); Bottom = (HEI + 1).toShort()
|
||||
}
|
||||
SetConsoleWindowInfo(console, TRUE, rc.ptr)
|
||||
val ci = alloc<CONSOLE_CURSOR_INFO>().apply { dwSize = 1; bVisible = FALSE }
|
||||
SetConsoleCursorInfo(console, ci.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
fun play() {
|
||||
while (true) {
|
||||
createfield()
|
||||
alive = true
|
||||
while (alive) {
|
||||
drawfield()
|
||||
readKey()
|
||||
moveSnake()
|
||||
Sleep(50)
|
||||
}
|
||||
memScoped {
|
||||
val c = alloc<COORD>().apply { X = 0; Y = (HEI + 1).toShort() }
|
||||
SetConsoleCursorPosition(console, c.readValue())
|
||||
}
|
||||
SetConsoleTextAttribute(console, 0x000b)
|
||||
print("Play again [Y/N]? ")
|
||||
val a = readLine()!!.toLowerCase()
|
||||
if (a.length > 0 && a[0] != 'y') {
|
||||
nativeHeap.free(snk)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createfield() {
|
||||
memScoped {
|
||||
val coord = alloc<COORD>().apply { X = 0; Y = 0 }
|
||||
val c = alloc<DWORDVar>()
|
||||
FillConsoleOutputCharacterW(console, 32, (HEI + 2) * 80, coord.readValue(), c.ptr)
|
||||
FillConsoleOutputAttribute(console, 0x0000, (HEI + 2) * 80, coord.readValue(), c.ptr)
|
||||
SetConsoleCursorPosition(console, coord.readValue())
|
||||
}
|
||||
for (x in 0 until WID * HEI) brd[x] = NUL
|
||||
for (x in 0 until WID) {
|
||||
brd[x + WID * (HEI - 1)] = '+'
|
||||
brd[x] = '+'
|
||||
}
|
||||
for (y in 1 until HEI) {
|
||||
brd[WID - 1 + WID * y] = '+'
|
||||
brd[WID * y] = '+'
|
||||
}
|
||||
var xx: Int
|
||||
var yy: Int
|
||||
do {
|
||||
xx = rand() % WID
|
||||
yy = rand() % (HEI shr 1) + (HEI shr 1)
|
||||
}
|
||||
while (brd[xx + WID * yy] != NUL)
|
||||
brd[xx + WID * yy] = '@'
|
||||
tailIdx = 0
|
||||
headIdx = 4
|
||||
xx = 3
|
||||
yy = 2
|
||||
for (cc in tailIdx until headIdx) {
|
||||
brd[xx + WID * yy] = '#'
|
||||
snk[cc].X = (3 + cc).toShort()
|
||||
snk[cc].Y = 2
|
||||
}
|
||||
head = snk[3]
|
||||
dir = Dir.EAST
|
||||
points = 0
|
||||
}
|
||||
|
||||
private fun readKey() {
|
||||
if ((GetAsyncKeyState(39).toInt() and 0x8000) != 0) dir = Dir.EAST
|
||||
if ((GetAsyncKeyState(37).toInt() and 0x8000) != 0) dir = Dir.WEST
|
||||
if ((GetAsyncKeyState(38).toInt() and 0x8000) != 0) dir = Dir.NORTH
|
||||
if ((GetAsyncKeyState(40).toInt() and 0x8000) != 0) dir = Dir.SOUTH
|
||||
}
|
||||
|
||||
private fun drawfield() {
|
||||
memScoped {
|
||||
val coord = alloc<COORD>()
|
||||
var t = NUL
|
||||
for (y in 0 until HEI) {
|
||||
coord.Y = y.toShort()
|
||||
for (x in 0 until WID) {
|
||||
t = brd[x + WID * y]
|
||||
if (t == NUL) continue
|
||||
coord.X = x.toShort()
|
||||
SetConsoleCursorPosition(console, coord.readValue())
|
||||
if (coord.X == head.X && coord.Y == head.Y) {
|
||||
SetConsoleTextAttribute(console, 0x002e)
|
||||
print('O')
|
||||
SetConsoleTextAttribute(console, 0x0000)
|
||||
continue
|
||||
}
|
||||
when (t) {
|
||||
'#' -> SetConsoleTextAttribute(console, 0x002a)
|
||||
'+' -> SetConsoleTextAttribute(console, 0x0019)
|
||||
'@' -> SetConsoleTextAttribute(console, 0x004c)
|
||||
}
|
||||
print(t)
|
||||
SetConsoleTextAttribute(console, 0x0000)
|
||||
}
|
||||
}
|
||||
print(t)
|
||||
SetConsoleTextAttribute(console, 0x0007)
|
||||
val c = alloc<COORD>().apply { X = 0; Y = HEI.toShort() }
|
||||
SetConsoleCursorPosition(console, c.readValue())
|
||||
print("Points: $points")
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveSnake() {
|
||||
when (dir) {
|
||||
Dir.NORTH -> head.Y--
|
||||
Dir.EAST -> head.X++
|
||||
Dir.SOUTH -> head.Y++
|
||||
Dir.WEST -> head.X--
|
||||
}
|
||||
val t = brd[head.X + WID * head.Y]
|
||||
if (t != NUL && t != '@') {
|
||||
alive = false
|
||||
return
|
||||
}
|
||||
brd[head.X + WID * head.Y] = '#'
|
||||
snk[headIdx].X = head.X
|
||||
snk[headIdx].Y = head.Y
|
||||
if (++headIdx >= MAX_LEN) headIdx = 0
|
||||
if (t == '@') {
|
||||
points++
|
||||
var x: Int
|
||||
var y: Int
|
||||
do {
|
||||
x = rand() % WID
|
||||
y = rand() % (HEI shr 1) + (HEI shr 1)
|
||||
}
|
||||
while (brd[x + WID * y] != NUL)
|
||||
brd[x + WID * y] = '@'
|
||||
return
|
||||
}
|
||||
SetConsoleCursorPosition(console, snk[tailIdx].readValue())
|
||||
print(' ')
|
||||
brd[snk[tailIdx].X + WID * snk[tailIdx].Y] = NUL
|
||||
if (++tailIdx >= MAX_LEN) tailIdx = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
srand(time(null).toInt())
|
||||
Snake().play()
|
||||
}
|
||||
30
Task/Snake/Locomotive-Basic/snake.basic
Normal file
30
Task/Snake/Locomotive-Basic/snake.basic
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
10 mode 1:randomize time
|
||||
20 sx=20:sy=5:dx=1:dy=0:ml=20:dim ox(ml),oy(ml):oi=1:ll=4:skill=6
|
||||
30 f$=chr$(228):w$=chr$(127):b$=chr$(231)
|
||||
40 print string$(40,w$);
|
||||
50 for i=2 to 20:print w$;space$(38);w$;:next
|
||||
60 print string$(40,w$);
|
||||
70 locate 10, 12:print string$(20,w$);
|
||||
80 gosub 260
|
||||
90 frame
|
||||
100 if inkey(1)>-1 then dx=1:dy=0
|
||||
110 if inkey(8)>-1 then dx=-1:dy=0
|
||||
120 if inkey(0)>-1 then dx=0:dy=-1
|
||||
130 if inkey(2)>-1 then dx=0:dy=1
|
||||
140 locate sx,sy:print chr$(224);:ox(oi)=sx:oy(oi)=sy
|
||||
150 oi=oi+1:if oi>ml then oi=1
|
||||
160 nx=sx+dx:ny=sy+dy
|
||||
170 locate nx,ny:a$=copychr$(#0)
|
||||
180 if a$=w$ or a$=b$ then sound 2,62500/20,100:locate 13,6:print "You have died!":end
|
||||
190 if a$=f$ then sound 2,62500/500,10: sound 1,62500/1000,10: sound 4,62500/2000,10:p=p+100:print " ";:gosub 260:if ll<ml then ll=ll+1
|
||||
200 locate 1,24:print "SCORE:"p
|
||||
210 for i=1 to skill:frame:next
|
||||
220 locate sx,sy:print b$;
|
||||
230 nn=1+((oi+ml-ll) mod ml)
|
||||
240 if ox(nn)>0 then locate ox(nn),oy(nn):print " ";
|
||||
250 sx=nx:sy=ny:goto 90
|
||||
260 fx=rnd*39+1:fy=rnd*19+1
|
||||
270 locate fx,fy:a$=copychr$(#0)
|
||||
280 if a$<>" " then 260
|
||||
290 print f$;
|
||||
300 return
|
||||
168
Task/Snake/Lua/snake.lua
Normal file
168
Task/Snake/Lua/snake.lua
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
UP, RIGHT, DOWN, LEFT = 1, 2, 3, 4
|
||||
UpdateTime=0.200
|
||||
Timer = 0
|
||||
GridSize = 30
|
||||
GridWidth, GridHeight = 20, 10
|
||||
|
||||
local directions = {
|
||||
[UP] = {x= 0, y=-1},
|
||||
[RIGHT] = {x= 1, y= 0},
|
||||
[DOWN] = {x= 0, y= 1},
|
||||
[LEFT] = {x=-1, y= 0},
|
||||
}
|
||||
|
||||
local function isPositionInBody(x, y)
|
||||
for i = 1, #Body-3, 2 do -- skip tail, it moves before we get in
|
||||
if x == Body[i] and y == Body[i+1] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function isPositionInApple(x, y)
|
||||
if x == Apple.x and y == Apple.y then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function newApple ()
|
||||
local ApplePlaced = false
|
||||
while not ApplePlaced do
|
||||
local x = GridSize*math.random (GridWidth)
|
||||
local y = GridSize*math.random (GridHeight)
|
||||
if not isPositionInBody(x, y) then
|
||||
Apple = {x=x, y=y}
|
||||
ApplePlaced = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function newGame ()
|
||||
Score = 0
|
||||
GameOver = false
|
||||
local x = GridSize*math.floor(math.random (0.25*GridWidth, 0.75*GridWidth))
|
||||
print (x)
|
||||
local y = GridSize*math.floor(math.random (0.25*GridHeight, 0.75*GridHeight))
|
||||
print (y)
|
||||
local iDirection = math.random(4)
|
||||
local d = directions[iDirection]
|
||||
Head = {
|
||||
x=x,
|
||||
y=y,
|
||||
iDirection = iDirection,
|
||||
nextDirection = iDirection,
|
||||
}
|
||||
Body = {x, y, x-GridSize*d.x, y-GridSize*d.y}
|
||||
Apples = {}
|
||||
newApple ()
|
||||
end
|
||||
|
||||
function love.load()
|
||||
newGame ()
|
||||
end
|
||||
|
||||
local function moveSnake (x, y, iDirection, longer)
|
||||
table.insert (Body, 1, x)
|
||||
table.insert (Body, 2, y)
|
||||
Head.x = x
|
||||
Head.y = y
|
||||
Head.iDirection = iDirection
|
||||
if not longer then
|
||||
-- remove last pair
|
||||
table.remove(Body)
|
||||
table.remove(Body)
|
||||
end
|
||||
if x <= 0 or x > GridSize*(GridWidth) or
|
||||
y <= 0 or y > GridSize*(GridHeight) then
|
||||
GameOver = true
|
||||
end
|
||||
end
|
||||
|
||||
function love.update(dt)
|
||||
Timer = Timer + dt
|
||||
if Timer < UpdateTime then return end
|
||||
Timer = Timer - UpdateTime
|
||||
|
||||
local iDirection = Head.nextDirection
|
||||
local d = directions[iDirection]
|
||||
local x, y = Head.x+GridSize*d.x, Head.y+GridSize*d.y
|
||||
if isPositionInBody(x, y) then
|
||||
GameOver = true
|
||||
elseif isPositionInApple(x, y) then
|
||||
Score = Score + 1
|
||||
newApple ()
|
||||
moveSnake (x, y, iDirection, true)
|
||||
else
|
||||
moveSnake (x, y, iDirection, false)
|
||||
end
|
||||
end
|
||||
|
||||
function drawHead () -- position, length, width and angle
|
||||
love.graphics.push()
|
||||
love.graphics.translate(Head.x, Head.y)
|
||||
love.graphics.rotate((Head.iDirection-2)*math.pi/2)
|
||||
love.graphics.polygon("fill",
|
||||
-GridSize/3, -GridSize /3,
|
||||
-GridSize/3, GridSize /3,
|
||||
GridSize/3, 0)
|
||||
love.graphics.pop()
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
love.graphics.setColor(0,1,0)
|
||||
love.graphics.print ('Score: '..tostring(Score), 10, 10)
|
||||
if GameOver then
|
||||
love.graphics.print ('Game Over: '..tostring(GameOver)..'. Press "Space" to continue', 10, 30)
|
||||
else
|
||||
love.graphics.translate(GridSize, GridSize)
|
||||
love.graphics.setColor(0.6,0.6,0.6)
|
||||
love.graphics.setLineWidth(0.25)
|
||||
for x = GridSize, GridSize*GridWidth, GridSize do
|
||||
love.graphics.line (x, GridSize, x, GridSize*GridHeight)
|
||||
end
|
||||
for y = GridSize, GridSize*GridHeight, GridSize do
|
||||
love.graphics.line (GridSize, y, GridSize*GridWidth, y)
|
||||
end
|
||||
love.graphics.setLineWidth((GridSize/4)+0.5)
|
||||
love.graphics.setColor(1,1,1)
|
||||
love.graphics.line (Body)
|
||||
drawHead ()
|
||||
love.graphics.setColor(1,0,0)
|
||||
love.graphics.circle ('fill', Apple.x, Apple.y, GridSize/4)
|
||||
end
|
||||
end
|
||||
|
||||
function love.keypressed(key, scancode, isrepeat)
|
||||
if false then
|
||||
elseif key == "space" then
|
||||
if GameOver then
|
||||
GameOver = false
|
||||
newGame ()
|
||||
end
|
||||
elseif key == "escape" then
|
||||
love.event.quit()
|
||||
else
|
||||
local iDirection = Head.iDirection
|
||||
if iDirection == UP or
|
||||
iDirection == DOWN then
|
||||
local right = love.keyboard.isScancodeDown ("d")
|
||||
local left = love.keyboard.isScancodeDown ("a")
|
||||
if right and not left then
|
||||
iDirection = RIGHT
|
||||
elseif left and not right then
|
||||
iDirection = LEFT
|
||||
end
|
||||
else -- right or left
|
||||
local down = love.keyboard.isScancodeDown ("s")
|
||||
local up = love.keyboard.isScancodeDown ("w")
|
||||
if up and not down then
|
||||
iDirection = UP
|
||||
elseif down and not up then
|
||||
iDirection = DOWN
|
||||
end
|
||||
end
|
||||
Head.nextDirection = iDirection
|
||||
end
|
||||
end
|
||||
110
Task/Snake/Nim/snake.nim
Normal file
110
Task/Snake/Nim/snake.nim
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import macros, os, random
|
||||
import ncurses
|
||||
|
||||
when defined(Linux):
|
||||
proc positional_putch(x, y: int; ch: char) = mvaddch(x.cint, y.cint, ch.chtype)
|
||||
proc updateScreen = refresh()
|
||||
proc nonBlockingGetch(): char =
|
||||
let c = getch()
|
||||
result = if c in 0..255: char(c) else: '\0'
|
||||
proc closeScreen = endwin()
|
||||
|
||||
else:
|
||||
error "Not implemented"
|
||||
|
||||
const
|
||||
|
||||
W = 80
|
||||
H = 40
|
||||
Space = 0
|
||||
Food = 1
|
||||
Border = 2
|
||||
Symbol = [' ', '@', '.']
|
||||
|
||||
type
|
||||
|
||||
Dir {.pure.} = enum North, East, South, West
|
||||
Game = object
|
||||
board: array[W * H, int]
|
||||
head: int
|
||||
dir: Dir
|
||||
quit: bool
|
||||
|
||||
|
||||
proc age(game: var Game) =
|
||||
## Reduce a time-to-live, effectively erasing the tail.
|
||||
for i in 0..<W*H:
|
||||
if game.board[i] < 0: inc game.board[i]
|
||||
|
||||
|
||||
proc plant(game: var Game) =
|
||||
## Put a piece of food at random empty position.
|
||||
var r: int
|
||||
while true:
|
||||
r = rand(W * H - 1)
|
||||
if game.board[r] == Space: break
|
||||
game.board[r] = Food
|
||||
|
||||
|
||||
proc start(game: var Game) =
|
||||
## Initialize the board, plant a very first food item.
|
||||
for i in 0..<W:
|
||||
game.board[i] = Border
|
||||
game.board[i + (H - 1) * W] = Border
|
||||
for i in 0..<H:
|
||||
game.board[i * W] = Border
|
||||
game.board[i * W + W - 1] = Border
|
||||
game.head = W * (H - 1 - (H and 1)) shr 1 # Screen center for any H.
|
||||
game.board[game.head] = -5
|
||||
game.dir = North
|
||||
game.quit = false
|
||||
game.plant()
|
||||
|
||||
|
||||
proc step(game: var Game) =
|
||||
let len = game.board[game.head]
|
||||
case game.dir
|
||||
of North: dec game.head, W
|
||||
of South: inc game.head, W
|
||||
of West: dec game.head
|
||||
of East: inc game.head
|
||||
|
||||
case game.board[game.head]
|
||||
of Space:
|
||||
game.board[game.head] = len - 1 # Keep in mind "len" is negative.
|
||||
game.age()
|
||||
of Food:
|
||||
game.board[game.head] = len - 1
|
||||
game.plant()
|
||||
else:
|
||||
game.quit = true
|
||||
|
||||
|
||||
proc show(game: Game) =
|
||||
for i in 0..<W*H:
|
||||
positionalPutch(i div W, i mod W, if game.board[i] < 0: '#' else: Symbol[game.board[i]])
|
||||
updateScreen()
|
||||
|
||||
|
||||
var game: Game
|
||||
randomize()
|
||||
let win = initscr()
|
||||
cbreak() # Make sure thre is no buffering.
|
||||
noecho() # Suppress echoing of characters.
|
||||
nodelay(win, true) # Non-blocking mode.
|
||||
game.start()
|
||||
|
||||
while not game.quit:
|
||||
game.show()
|
||||
case nonBlockingGetch()
|
||||
of 'i': game.dir = North
|
||||
of 'j': game.dir = West
|
||||
of 'k': game.dir = South
|
||||
of 'l': game.dir = East
|
||||
of 'q': game.quit = true
|
||||
else: discard
|
||||
game.step()
|
||||
os.sleep(300) # Adjust here: 100 is very fast.
|
||||
|
||||
sleep(1000)
|
||||
closeScreen()
|
||||
154
Task/Snake/OCaml/snake.ocaml
Normal file
154
Task/Snake/OCaml/snake.ocaml
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
(* A simple Snake Game *)
|
||||
open Sdl
|
||||
|
||||
let width, height = (640, 480)
|
||||
|
||||
type pos = int * int
|
||||
|
||||
type game_state = {
|
||||
pos_snake: pos;
|
||||
seg_snake: pos list;
|
||||
dir_snake: [`left | `right | `up | `down];
|
||||
pos_fruit: pos;
|
||||
sleep_time: int;
|
||||
game_over: bool;
|
||||
}
|
||||
|
||||
let red = (255, 0, 0)
|
||||
let blue = (0, 0, 255)
|
||||
let green = (0, 255, 0)
|
||||
let black = (0, 0, 0)
|
||||
let alpha = 255
|
||||
|
||||
let fill_rect renderer (x, y) =
|
||||
let rect = Rect.make4 x y 20 20 in
|
||||
Render.fill_rect renderer rect;
|
||||
;;
|
||||
|
||||
|
||||
let display_game renderer state =
|
||||
let bg_color, snake_color, fruit_color =
|
||||
if state.game_over
|
||||
then (red, black, green)
|
||||
else (black, blue, red)
|
||||
in
|
||||
Render.set_draw_color renderer bg_color alpha;
|
||||
Render.clear renderer;
|
||||
Render.set_draw_color renderer fruit_color alpha;
|
||||
fill_rect renderer state.pos_fruit;
|
||||
Render.set_draw_color renderer snake_color alpha;
|
||||
List.iter (fill_rect renderer) state.seg_snake;
|
||||
Render.render_present renderer;
|
||||
;;
|
||||
|
||||
|
||||
let proc_events dir_snake = function
|
||||
| Event.KeyDown { Event.keycode = Keycode.Left } -> `left
|
||||
| Event.KeyDown { Event.keycode = Keycode.Right } -> `right
|
||||
| Event.KeyDown { Event.keycode = Keycode.Up } -> `up
|
||||
| Event.KeyDown { Event.keycode = Keycode.Down } -> `down
|
||||
| Event.KeyDown { Event.keycode = Keycode.Q }
|
||||
| Event.KeyDown { Event.keycode = Keycode.Escape }
|
||||
| Event.Quit _ -> Sdl.quit (); exit 0
|
||||
| _ -> (dir_snake)
|
||||
|
||||
|
||||
let rec event_loop dir_snake =
|
||||
match Event.poll_event () with
|
||||
| None -> (dir_snake)
|
||||
| Some ev ->
|
||||
let dir = proc_events dir_snake ev in
|
||||
event_loop dir
|
||||
|
||||
|
||||
let rec pop = function
|
||||
| [_] -> []
|
||||
| hd :: tl -> hd :: (pop tl)
|
||||
| [] -> invalid_arg "pop"
|
||||
|
||||
|
||||
let rec new_pos_fruit seg_snake =
|
||||
let new_pos =
|
||||
(20 * Random.int 32,
|
||||
20 * Random.int 24)
|
||||
in
|
||||
if List.mem new_pos seg_snake
|
||||
then new_pos_fruit seg_snake
|
||||
else (new_pos)
|
||||
|
||||
|
||||
let update_state req_dir ({
|
||||
pos_snake;
|
||||
seg_snake;
|
||||
pos_fruit;
|
||||
dir_snake;
|
||||
sleep_time;
|
||||
game_over;
|
||||
} as state) =
|
||||
if game_over then state else
|
||||
let dir_snake =
|
||||
match dir_snake, req_dir with
|
||||
| `left, `right -> dir_snake
|
||||
| `right, `left -> dir_snake
|
||||
| `up, `down -> dir_snake
|
||||
| `down, `up -> dir_snake
|
||||
| _ -> req_dir
|
||||
in
|
||||
let pos_snake =
|
||||
let x, y = pos_snake in
|
||||
match dir_snake with
|
||||
| `left -> (x - 20, y)
|
||||
| `right -> (x + 20, y)
|
||||
| `up -> (x, y - 20)
|
||||
| `down -> (x, y + 20)
|
||||
in
|
||||
let game_over =
|
||||
let x, y = pos_snake in
|
||||
List.mem pos_snake seg_snake
|
||||
|| x < 0 || y < 0
|
||||
|| x >= width
|
||||
|| y >= height
|
||||
in
|
||||
let seg_snake = pos_snake :: seg_snake in
|
||||
let seg_snake, pos_fruit, sleep_time =
|
||||
if pos_snake = pos_fruit
|
||||
then (seg_snake, new_pos_fruit seg_snake, sleep_time - 1)
|
||||
else (pop seg_snake, pos_fruit, sleep_time)
|
||||
in
|
||||
{ pos_snake;
|
||||
seg_snake;
|
||||
pos_fruit;
|
||||
dir_snake;
|
||||
sleep_time;
|
||||
game_over;
|
||||
}
|
||||
|
||||
|
||||
let () =
|
||||
Random.self_init ();
|
||||
Sdl.init [`VIDEO];
|
||||
let window, renderer =
|
||||
Render.create_window_and_renderer ~width ~height ~flags:[]
|
||||
in
|
||||
Window.set_title ~window ~title:"Snake OCaml-SDL2";
|
||||
let initial_state = {
|
||||
pos_snake = (100, 100);
|
||||
seg_snake = [
|
||||
(100, 100);
|
||||
( 80, 100);
|
||||
( 60, 100);
|
||||
];
|
||||
pos_fruit = (200, 200);
|
||||
dir_snake = `right;
|
||||
sleep_time = 120;
|
||||
game_over = false;
|
||||
} in
|
||||
|
||||
let rec main_loop state =
|
||||
let req_dir = event_loop state.dir_snake in
|
||||
let state = update_state req_dir state in
|
||||
display_game renderer state;
|
||||
Timer.delay state.sleep_time;
|
||||
main_loop state
|
||||
in
|
||||
main_loop initial_state
|
||||
171
Task/Snake/Perl/snake.pl
Normal file
171
Task/Snake/Perl/snake.pl
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
use utf8;
|
||||
use Time::HiRes qw(sleep);
|
||||
use Term::ANSIColor qw(colored);
|
||||
use Term::ReadKey qw(ReadMode ReadLine);
|
||||
|
||||
binmode(STDOUT, ':utf8');
|
||||
|
||||
use constant {
|
||||
VOID => 0,
|
||||
HEAD => 1,
|
||||
BODY => 2,
|
||||
TAIL => 3,
|
||||
FOOD => 4,
|
||||
};
|
||||
|
||||
use constant {
|
||||
LEFT => [+0, -1],
|
||||
RIGHT => [+0, +1],
|
||||
UP => [-1, +0],
|
||||
DOWN => [+1, +0],
|
||||
};
|
||||
|
||||
use constant {
|
||||
BG_COLOR => "on_black",
|
||||
SLEEP_SEC => 0.05,
|
||||
};
|
||||
|
||||
use constant {
|
||||
SNAKE_COLOR => ('bold green' . ' ' . BG_COLOR),
|
||||
FOOD_COLOR => ('red' . ' ' . BG_COLOR),
|
||||
};
|
||||
|
||||
use constant {
|
||||
U_HEAD => colored('▲', SNAKE_COLOR),
|
||||
D_HEAD => colored('▼', SNAKE_COLOR),
|
||||
L_HEAD => colored('◀', SNAKE_COLOR),
|
||||
R_HEAD => colored('▶', SNAKE_COLOR),
|
||||
|
||||
U_BODY => colored('╹', SNAKE_COLOR),
|
||||
D_BODY => colored('╻', SNAKE_COLOR),
|
||||
L_BODY => colored('╴', SNAKE_COLOR),
|
||||
R_BODY => colored('╶', SNAKE_COLOR),
|
||||
|
||||
U_TAIL => colored('╽', SNAKE_COLOR),
|
||||
D_TAIL => colored('╿', SNAKE_COLOR),
|
||||
L_TAIL => colored('╼', SNAKE_COLOR),
|
||||
R_TAIL => colored('╾', SNAKE_COLOR),
|
||||
|
||||
A_VOID => colored(' ', BG_COLOR),
|
||||
A_FOOD => colored('❇', FOOD_COLOR),
|
||||
};
|
||||
|
||||
local $| = 1;
|
||||
|
||||
my $w = eval { `tput cols` } || 80;
|
||||
my $h = eval { `tput lines` } || 24;
|
||||
my $r = "\033[H";
|
||||
|
||||
my @grid = map {
|
||||
[map { [VOID] } 1 .. $w]
|
||||
} 1 .. $h;
|
||||
|
||||
my $dir = LEFT;
|
||||
my @head_pos = ($h / 2, $w / 2);
|
||||
my @tail_pos = ($head_pos[0], $head_pos[1] + 1);
|
||||
|
||||
$grid[$head_pos[0]][$head_pos[1]] = [HEAD, $dir]; # head
|
||||
$grid[$tail_pos[0]][$tail_pos[1]] = [TAIL, $dir]; # tail
|
||||
|
||||
sub create_food {
|
||||
my ($food_x, $food_y);
|
||||
|
||||
do {
|
||||
$food_x = rand($w);
|
||||
$food_y = rand($h);
|
||||
} while ($grid[$food_y][$food_x][0] != VOID);
|
||||
|
||||
$grid[$food_y][$food_x][0] = FOOD;
|
||||
}
|
||||
|
||||
create_food();
|
||||
|
||||
sub display {
|
||||
my $i = 0;
|
||||
|
||||
print $r, join("\n",
|
||||
map {
|
||||
join("",
|
||||
map {
|
||||
my $t = $_->[0];
|
||||
if ($t != FOOD and $t != VOID) {
|
||||
my $p = $_->[1];
|
||||
$i =
|
||||
$p eq UP ? 0
|
||||
: $p eq DOWN ? 1
|
||||
: $p eq LEFT ? 2
|
||||
: 3;
|
||||
}
|
||||
$t == HEAD ? (U_HEAD, D_HEAD, L_HEAD, R_HEAD)[$i]
|
||||
: $t == BODY ? (U_BODY, D_BODY, L_BODY, R_BODY)[$i]
|
||||
: $t == TAIL ? (U_TAIL, D_TAIL, L_TAIL, R_TAIL)[$i]
|
||||
: $t == FOOD ? (A_FOOD)
|
||||
: (A_VOID);
|
||||
|
||||
} @{$_}
|
||||
)
|
||||
} @grid
|
||||
);
|
||||
}
|
||||
|
||||
sub move {
|
||||
my $grew = 0;
|
||||
|
||||
# Move the head
|
||||
{
|
||||
my ($y, $x) = @head_pos;
|
||||
|
||||
my $new_y = ($y + $dir->[0]) % $h;
|
||||
my $new_x = ($x + $dir->[1]) % $w;
|
||||
|
||||
my $cell = $grid[$new_y][$new_x];
|
||||
my $t = $cell->[0];
|
||||
|
||||
if ($t == BODY or $t == TAIL) {
|
||||
die "Game over!\n";
|
||||
}
|
||||
elsif ($t == FOOD) {
|
||||
create_food();
|
||||
$grew = 1;
|
||||
}
|
||||
|
||||
# Create a new head
|
||||
$grid[$new_y][$new_x] = [HEAD, $dir];
|
||||
|
||||
# Replace the current head with body
|
||||
$grid[$y][$x] = [BODY, $dir];
|
||||
|
||||
# Save the position of the head
|
||||
@head_pos = ($new_y, $new_x);
|
||||
}
|
||||
|
||||
# Move the tail
|
||||
if (not $grew) {
|
||||
my ($y, $x) = @tail_pos;
|
||||
|
||||
my $pos = $grid[$y][$x][1];
|
||||
my $new_y = ($y + $pos->[0]) % $h;
|
||||
my $new_x = ($x + $pos->[1]) % $w;
|
||||
|
||||
$grid[$y][$x][0] = VOID; # erase the current tail
|
||||
$grid[$new_y][$new_x][0] = TAIL; # create a new tail
|
||||
|
||||
# Save the position of the tail
|
||||
@tail_pos = ($new_y, $new_x);
|
||||
}
|
||||
}
|
||||
|
||||
ReadMode(3);
|
||||
while (1) {
|
||||
my $key;
|
||||
until (defined($key = ReadLine(-1))) {
|
||||
move();
|
||||
display();
|
||||
sleep(SLEEP_SEC);
|
||||
}
|
||||
|
||||
if ($key eq "\e[A" and $dir ne DOWN ) { $dir = UP }
|
||||
elsif ($key eq "\e[B" and $dir ne UP ) { $dir = DOWN }
|
||||
elsif ($key eq "\e[C" and $dir ne LEFT ) { $dir = RIGHT }
|
||||
elsif ($key eq "\e[D" and $dir ne RIGHT) { $dir = LEFT }
|
||||
}
|
||||
81
Task/Snake/Phix/snake.phix
Normal file
81
Task/Snake/Phix/snake.phix
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
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()
|
||||
261
Task/Snake/Python/snake.py
Normal file
261
Task/Snake/Python/snake.py
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import random
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from typing import Any
|
||||
from typing import Tuple
|
||||
|
||||
import pygame as pg
|
||||
|
||||
from pygame import Color
|
||||
from pygame import Rect
|
||||
|
||||
from pygame.surface import Surface
|
||||
|
||||
from pygame.sprite import AbstractGroup
|
||||
from pygame.sprite import Group
|
||||
from pygame.sprite import RenderUpdates
|
||||
from pygame.sprite import Sprite
|
||||
|
||||
|
||||
class Direction(Enum):
|
||||
UP = (0, -1)
|
||||
DOWN = (0, 1)
|
||||
LEFT = (-1, 0)
|
||||
RIGHT = (1, 0)
|
||||
|
||||
def opposite(self, other: Direction):
|
||||
return (self[0] + other[0], self[1] + other[1]) == (0, 0)
|
||||
|
||||
def __getitem__(self, i: int):
|
||||
return self.value[i]
|
||||
|
||||
|
||||
class SnakeHead(Sprite):
|
||||
def __init__(
|
||||
self,
|
||||
size: int,
|
||||
position: Tuple[int, int],
|
||||
facing: Direction,
|
||||
bounds: Rect,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.image = Surface((size, size))
|
||||
self.image.fill(Color("aquamarine4"))
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.center = position
|
||||
self.facing = facing
|
||||
self.size = size
|
||||
self.speed = size
|
||||
self.bounds = bounds
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
# Move the snake in the direction it is facing.
|
||||
self.rect.move_ip(
|
||||
(
|
||||
self.facing[0] * self.speed,
|
||||
self.facing[1] * self.speed,
|
||||
)
|
||||
)
|
||||
|
||||
# Move to the opposite side of the screen if the snake goes out of bounds.
|
||||
if self.rect.right > self.bounds.right:
|
||||
self.rect.left = 0
|
||||
elif self.rect.left < 0:
|
||||
self.rect.right = self.bounds.right
|
||||
|
||||
if self.rect.bottom > self.bounds.bottom:
|
||||
self.rect.top = 0
|
||||
elif self.rect.top < 0:
|
||||
self.rect.bottom = self.bounds.bottom
|
||||
|
||||
def change_direction(self, direction: Direction):
|
||||
if not self.facing == direction and not direction.opposite(self.facing):
|
||||
self.facing = direction
|
||||
|
||||
|
||||
class SnakeBody(Sprite):
|
||||
def __init__(
|
||||
self,
|
||||
size: int,
|
||||
position: Tuple[int, int],
|
||||
colour: str = "white",
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.image = Surface((size, size))
|
||||
self.image.fill(Color(colour))
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.center = position
|
||||
|
||||
|
||||
class Snake(RenderUpdates):
|
||||
def __init__(self, game: Game) -> None:
|
||||
self.segment_size = game.segment_size
|
||||
self.colours = itertools.cycle(["aquamarine1", "aquamarine3"])
|
||||
|
||||
self.head = SnakeHead(
|
||||
size=self.segment_size,
|
||||
position=game.rect.center,
|
||||
facing=Direction.RIGHT,
|
||||
bounds=game.rect,
|
||||
)
|
||||
|
||||
neck = [
|
||||
SnakeBody(
|
||||
size=self.segment_size,
|
||||
position=game.rect.center,
|
||||
colour=next(self.colours),
|
||||
)
|
||||
for _ in range(2)
|
||||
]
|
||||
|
||||
super().__init__(*[self.head, *neck])
|
||||
|
||||
self.body = Group()
|
||||
self.tail = neck[-1]
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
self.head.update()
|
||||
|
||||
# Snake body sprites don't update themselves. We update them here.
|
||||
segments = self.sprites()
|
||||
for i in range(len(segments) - 1, 0, -1):
|
||||
# Current sprite takes the position of the previous sprite.
|
||||
segments[i].rect.center = segments[i - 1].rect.center
|
||||
|
||||
def change_direction(self, direction: Direction):
|
||||
self.head.change_direction(direction)
|
||||
|
||||
def grow(self):
|
||||
tail = SnakeBody(
|
||||
size=self.segment_size,
|
||||
position=self.tail.rect.center,
|
||||
colour=next(self.colours),
|
||||
)
|
||||
self.tail = tail
|
||||
self.add(self.tail)
|
||||
self.body.add(self.tail)
|
||||
|
||||
|
||||
class SnakeFood(Sprite):
|
||||
def __init__(self, game: Game, size: int, *groups: AbstractGroup) -> None:
|
||||
super().__init__(*groups)
|
||||
self.image = Surface((size, size))
|
||||
self.image.fill(Color("red"))
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
self.rect.topleft = (
|
||||
random.randint(0, game.rect.width),
|
||||
random.randint(0, game.rect.height),
|
||||
)
|
||||
|
||||
self.rect.clamp_ip(game.rect)
|
||||
|
||||
# XXX: This approach to random food placement might end badly if the
|
||||
# snake is very large.
|
||||
while pg.sprite.spritecollideany(self, game.snake):
|
||||
self.rect.topleft = (
|
||||
random.randint(0, game.rect.width),
|
||||
random.randint(0, game.rect.height),
|
||||
)
|
||||
|
||||
self.rect.clamp_ip(game.rect)
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self) -> None:
|
||||
self.rect = Rect(0, 0, 640, 480)
|
||||
self.background = Surface(self.rect.size)
|
||||
self.background.fill(Color("black"))
|
||||
|
||||
self.score = 0
|
||||
self.framerate = 16
|
||||
|
||||
self.segment_size = 10
|
||||
self.snake = Snake(self)
|
||||
self.food_group = RenderUpdates(SnakeFood(game=self, size=self.segment_size))
|
||||
|
||||
pg.init()
|
||||
|
||||
def _init_display(self) -> Surface:
|
||||
bestdepth = pg.display.mode_ok(self.rect.size, 0, 32)
|
||||
screen = pg.display.set_mode(self.rect.size, 0, bestdepth)
|
||||
|
||||
pg.display.set_caption("Snake")
|
||||
pg.mouse.set_visible(False)
|
||||
|
||||
screen.blit(self.background, (0, 0))
|
||||
pg.display.flip()
|
||||
|
||||
return screen
|
||||
|
||||
def draw(self, screen: Surface):
|
||||
dirty = self.snake.draw(screen)
|
||||
pg.display.update(dirty)
|
||||
|
||||
dirty = self.food_group.draw(screen)
|
||||
pg.display.update(dirty)
|
||||
|
||||
def update(self, screen):
|
||||
self.food_group.clear(screen, self.background)
|
||||
self.food_group.update()
|
||||
self.snake.clear(screen, self.background)
|
||||
self.snake.update()
|
||||
|
||||
def main(self) -> int:
|
||||
screen = self._init_display()
|
||||
clock = pg.time.Clock()
|
||||
|
||||
while self.snake.head.alive():
|
||||
for event in pg.event.get():
|
||||
if event.type == pg.QUIT or (
|
||||
event.type == pg.KEYDOWN and event.key in (pg.K_ESCAPE, pg.K_q)
|
||||
):
|
||||
return self.score
|
||||
|
||||
# Change direction using the arrow keys.
|
||||
keystate = pg.key.get_pressed()
|
||||
|
||||
if keystate[pg.K_RIGHT]:
|
||||
self.snake.change_direction(Direction.RIGHT)
|
||||
elif keystate[pg.K_LEFT]:
|
||||
self.snake.change_direction(Direction.LEFT)
|
||||
elif keystate[pg.K_UP]:
|
||||
self.snake.change_direction(Direction.UP)
|
||||
elif keystate[pg.K_DOWN]:
|
||||
self.snake.change_direction(Direction.DOWN)
|
||||
|
||||
# Detect collisions after update.
|
||||
self.update(screen)
|
||||
|
||||
# Snake eats food.
|
||||
for food in pg.sprite.spritecollide(
|
||||
self.snake.head, self.food_group, dokill=False
|
||||
):
|
||||
food.kill()
|
||||
self.snake.grow()
|
||||
self.score += 1
|
||||
|
||||
# Increase framerate to speed up gameplay.
|
||||
if self.score % 5 == 0:
|
||||
self.framerate += 1
|
||||
|
||||
self.food_group.add(SnakeFood(self, self.segment_size))
|
||||
|
||||
# Snake hit its own tail.
|
||||
if pg.sprite.spritecollideany(self.snake.head, self.snake.body):
|
||||
self.snake.head.kill()
|
||||
|
||||
self.draw(screen)
|
||||
clock.tick(self.framerate)
|
||||
|
||||
return self.score
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
game = Game()
|
||||
score = game.main()
|
||||
print(score)
|
||||
175
Task/Snake/Raku/snake.raku
Normal file
175
Task/Snake/Raku/snake.raku
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
use SDL2::Raw;
|
||||
use Cairo;
|
||||
|
||||
constant W = 1280;
|
||||
constant H = 960;
|
||||
|
||||
constant FIELDW = W div 32;
|
||||
constant FIELDH = H div 32;
|
||||
|
||||
SDL_Init(VIDEO);
|
||||
|
||||
my $window = SDL_CreateWindow(
|
||||
'Snake',
|
||||
SDL_WINDOWPOS_CENTERED_MASK,
|
||||
SDL_WINDOWPOS_CENTERED_MASK,
|
||||
W, H,
|
||||
OPENGL
|
||||
);
|
||||
|
||||
my $render = SDL_CreateRenderer($window, -1, ACCELERATED +| PRESENTVSYNC);
|
||||
|
||||
my $snake_image = Cairo::Image.record(
|
||||
-> $_ {
|
||||
.save;
|
||||
.rectangle: 0, 0, 64, 64;
|
||||
.clip;
|
||||
.rgb: 0, 1, 0;
|
||||
.rectangle: 0, 0, 64, 64;
|
||||
.fill :preserve;
|
||||
.rgb: 0, 0, 0;
|
||||
.stroke;
|
||||
.restore;
|
||||
|
||||
.save;
|
||||
.translate: 64, 0;
|
||||
.rectangle: 0, 0, 64, 64;
|
||||
.clip;
|
||||
.rgb: 1, 0, 0;
|
||||
.arc: 32, 32, 30, 0, 2 * pi;
|
||||
.fill :preserve;
|
||||
.rgb: 0, 0, 0;
|
||||
.stroke;
|
||||
.restore;
|
||||
}, 128, 128, Cairo::FORMAT_ARGB32);
|
||||
|
||||
my $snake_texture = SDL_CreateTexture(
|
||||
$render,
|
||||
%PIXELFORMAT<ARGB8888>,
|
||||
STATIC,
|
||||
128,
|
||||
128
|
||||
);
|
||||
|
||||
SDL_UpdateTexture(
|
||||
$snake_texture,
|
||||
SDL_Rect.new(
|
||||
:x(0),
|
||||
:y(0),
|
||||
:w(128),
|
||||
:h(128)
|
||||
),
|
||||
$snake_image.data,
|
||||
$snake_image.stride // 128 * 4
|
||||
);
|
||||
|
||||
SDL_SetTextureBlendMode($snake_texture, 1);
|
||||
|
||||
SDL_SetRenderDrawBlendMode($render, 1);
|
||||
|
||||
my $snakepiece_srcrect = SDL_Rect.new(:w(64), :h(64));
|
||||
my $nompiece_srcrect = SDL_Rect.new(:w(64), :h(64), :x(64));
|
||||
|
||||
my $event = SDL_Event.new;
|
||||
|
||||
enum GAME_KEYS (
|
||||
K_UP => 82,
|
||||
K_DOWN => 81,
|
||||
K_LEFT => 80,
|
||||
K_RIGHT => 79,
|
||||
);
|
||||
|
||||
my Complex @snakepieces = 10+10i;
|
||||
my Complex @noms;
|
||||
my Complex $snakedir = 1+0i;
|
||||
my $nomspawn = 0;
|
||||
my $snakespeed = 0.1;
|
||||
my $snakestep = 0;
|
||||
my $nom = 4;
|
||||
|
||||
my $last_frame_start = now;
|
||||
main: loop {
|
||||
my $start = now;
|
||||
my $dt = $start - $last_frame_start // 0.00001;
|
||||
while SDL_PollEvent($event) {
|
||||
my $casted_event = SDL_CastEvent($event);
|
||||
given $casted_event {
|
||||
when *.type == QUIT { last main }
|
||||
when *.type == KEYDOWN {
|
||||
if GAME_KEYS(.scancode) -> $comm {
|
||||
given $comm {
|
||||
when 'K_LEFT' { $snakedir = -1+0i unless $snakedir == 1+0i }
|
||||
when 'K_RIGHT' { $snakedir = 1+0i unless $snakedir == -1+0i }
|
||||
when 'K_UP' { $snakedir = 0-1i unless $snakedir == 0+1i }
|
||||
when 'K_DOWN' { $snakedir = 0+1i unless $snakedir == 0-1i }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($nomspawn -= $dt) < 0 {
|
||||
$nomspawn += 1;
|
||||
@noms.push: (^FIELDW).pick + (^FIELDH).pick * i unless @noms > 3;
|
||||
@noms.pop if @noms[*-1] == any(@snakepieces);
|
||||
}
|
||||
|
||||
if ($snakestep -= $dt) < 0 {
|
||||
$snakestep += $snakespeed;
|
||||
|
||||
@snakepieces.unshift: do given @snakepieces[0] {
|
||||
($_.re + $snakedir.re) % FIELDW
|
||||
+ (($_.im + $snakedir.im) % FIELDH) * i
|
||||
}
|
||||
|
||||
if @snakepieces[2..*].first( * == @snakepieces[0], :k ) -> $idx {
|
||||
@snakepieces = @snakepieces[0..($idx + 1)];
|
||||
}
|
||||
|
||||
@noms .= grep(
|
||||
{ $^piece == @snakepieces[0] ?? ($nom += 1) && False !! True }
|
||||
);
|
||||
|
||||
if $nom == 0 {
|
||||
@snakepieces.pop;
|
||||
} else {
|
||||
$nom = $nom - 1;
|
||||
}
|
||||
}
|
||||
|
||||
for @snakepieces {
|
||||
SDL_SetTextureColorMod(
|
||||
$snake_texture,
|
||||
255,
|
||||
(cos((++$) / 2) * 100 + 155).round,
|
||||
255
|
||||
);
|
||||
|
||||
SDL_RenderCopy(
|
||||
$render,
|
||||
$snake_texture,
|
||||
$snakepiece_srcrect,
|
||||
SDL_Rect.new(.re * 32, .im * 32, 32, 32)
|
||||
);
|
||||
}
|
||||
|
||||
SDL_SetTextureColorMod($snake_texture, 255, 255, 255);
|
||||
|
||||
for @noms {
|
||||
SDL_RenderCopy(
|
||||
$render,
|
||||
$snake_texture,
|
||||
$nompiece_srcrect,
|
||||
SDL_Rect.new(.re * 32, .im * 32, 32, 32)
|
||||
)
|
||||
}
|
||||
|
||||
SDL_RenderPresent($render);
|
||||
SDL_SetRenderDrawColor($render, 0, 0, 0, 0);
|
||||
SDL_RenderClear($render);
|
||||
|
||||
$last_frame_start = $start;
|
||||
sleep(1 / 50);
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
116
Task/Snake/Rust/snake.rust
Normal file
116
Task/Snake/Rust/snake.rust
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/* add to file Cargo.toml:
|
||||
[dependencies]
|
||||
winsafe = "0.0.8" # IMHO: before the appearance of winsafe="0.1" it is not worth raising the version here
|
||||
rand = "0.8"
|
||||
derive-new = "0.5"
|
||||
*/
|
||||
|
||||
#![windows_subsystem = "windows"]
|
||||
|
||||
use derive_new::new;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use winsafe::{co, gui, prelude::*, COLORREF, HBRUSH, HPEN, RECT, SIZE};
|
||||
|
||||
const STEP: i32 = 3; // px, motion per frame
|
||||
const GCW: i32 = 7; // game grid cell width in STEPs
|
||||
const SNAKE_W: i32 = 20; // px
|
||||
const FW: i32 = 20; // the width of the square field in the cells of the game grid
|
||||
const TW: i32 = (FW + 2) * GCW; // total field width (with overlap for collisions) in STEPs
|
||||
const ID0: i32 = FW / 2 * GCW; // starting position id
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(new)]
|
||||
struct Context {
|
||||
wnd: gui::WindowMain,
|
||||
#[new(default) ] snake: Vec<i32>, // [rect_ids] where rect_id = y * TW + x (where x, y: nSTEPs)
|
||||
#[new(value = "[ID0; 6]")] r: [i32; 6], // ID 6 rect to color in next frame (bg, tail, turn, body, food, head)
|
||||
#[new(default) ] incr: i32, // 0 | -1 | 1 | -TW | TW - increment r[head] in next STEP
|
||||
#[new(value = "TW") ] next_incr: i32, // `incr` in the next grid cell
|
||||
#[new(default) ] gap: i32, // interval in STEPs to the next grid cell; negative - tail clipping mark
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let [bg, tail, turn, body, food, head] = [0_usize, 1, 2, 3, 4, 5];
|
||||
let grid: Vec<_> = (1..=FW).flat_map(|y| (1..=FW).map(move |x| (y * TW + x) * GCW)).collect();
|
||||
let mut colors = [(0x00, 0xF0, 0xA0); 6]; // color tail, turn, body
|
||||
colors[bg] = (0x00, 0x50, 0x90);
|
||||
colors[food] = (0xFF, 0x50, 0x00);
|
||||
colors[head] = (0xFF, 0xFF, 0x00);
|
||||
let brushes = COLORREF::new_array(&colors).map(|c| HBRUSH::CreateSolidBrush(c).unwrap());
|
||||
|
||||
let wnd = gui::WindowMain::new(gui::WindowMainOpts {
|
||||
title: "Snake - Start: Space, then press W-A-S-D".to_string(),
|
||||
size: SIZE::new(FW * GCW * STEP, FW * GCW * STEP),
|
||||
class_bg_brush: brushes[bg],
|
||||
..Default::default()
|
||||
});
|
||||
// WindowMain is based on Arc, so wnd.clone() is a shallow copy of a reference.
|
||||
let context = Rc::new(RefCell::new(Context::new(wnd.clone())));
|
||||
|
||||
wnd.on().wm_paint({
|
||||
let context = Rc::clone(&context);
|
||||
move || {
|
||||
let ctx = context.borrow();
|
||||
let mut ps = winsafe::PAINTSTRUCT::default();
|
||||
let hdc = ctx.wnd.hwnd().BeginPaint(&mut ps)?;
|
||||
hdc.SelectObjectPen(HPEN::CreatePen(co::PS::NULL, 0, COLORREF::new(0, 0, 0))?)?;
|
||||
for (&id, &brush) in ctx.r.iter().zip(&brushes[bg..=head]) {
|
||||
let [left, top] = [id % TW, id / TW].map(|i| i * STEP - (STEP * GCW + SNAKE_W) / 2);
|
||||
let rect = RECT { left, top, right: left + SNAKE_W, bottom: top + SNAKE_W };
|
||||
hdc.SelectObjectBrush(brush)?;
|
||||
hdc.RoundRect(rect, SIZE::new(SNAKE_W / 2, SNAKE_W / 2))?;
|
||||
}
|
||||
Ok(ctx.wnd.hwnd().EndPaint(&ps))
|
||||
}
|
||||
});
|
||||
|
||||
wnd.on().wm_key_down({
|
||||
let context = Rc::clone(&context);
|
||||
move |key| {
|
||||
let mut ctx = context.borrow_mut();
|
||||
Ok(match (ctx.incr.abs(), key.char_code as u8) {
|
||||
(0, b' ') => _ = ctx.wnd.hwnd().SetTimer(1, 10, None)?, // Start / Restart
|
||||
(TW, bt @ (b'A' | b'D')) => ctx.next_incr = if bt == b'A' { -1 } else { 1 },
|
||||
(1, bt @ (b'S' | b'W')) => ctx.next_incr = if bt == b'S' { TW } else { -TW },
|
||||
_ => (),
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
wnd.on().wm_timer(1, move || {
|
||||
let mut ctx = context.borrow_mut();
|
||||
let new_h = ctx.r[head] + ctx.incr;
|
||||
(ctx.r[body], ctx.r[head]) = (ctx.r[head], new_h);
|
||||
if ctx.gap < 0 {
|
||||
ctx.r[bg] = ctx.snake.remove(0);
|
||||
ctx.r[tail] = ctx.snake[0];
|
||||
ctx.r[turn] = ctx.snake[GCW as usize / 2];
|
||||
}
|
||||
ctx.gap -= ctx.gap.signum();
|
||||
if ctx.gap == 0 {
|
||||
ctx.gap = if new_h == ctx.r[food] { GCW } else { -GCW };
|
||||
let mut snake_cells: Vec<_> = ctx.snake.iter().step_by(GCW as usize).collect();
|
||||
if new_h == ctx.r[food] {
|
||||
ctx.wnd.hwnd().SetWindowText(&format!("Snake - Eaten: {}", snake_cells.len()))?;
|
||||
snake_cells.sort();
|
||||
ctx.r[food] = *(grid.iter())
|
||||
.filter(|i| **i != new_h && snake_cells.binary_search(i).is_err())
|
||||
.nth(thread_rng().gen_range(0..(grid.len() - 1 - snake_cells.len()).max(1)))
|
||||
.unwrap_or(&0);
|
||||
} else if grid.binary_search(&new_h).is_err() || snake_cells.contains(&&new_h) {
|
||||
ctx.wnd.hwnd().KillTimer(1)?; // Stop
|
||||
let title = ctx.wnd.hwnd().GetWindowText()?;
|
||||
ctx.wnd.hwnd().SetWindowText(&(title + ". Restart: Space"))?;
|
||||
*ctx = Context::new(ctx.wnd.clone());
|
||||
return Ok(());
|
||||
}
|
||||
ctx.incr = ctx.next_incr;
|
||||
}
|
||||
ctx.snake.push(new_h);
|
||||
ctx.wnd.hwnd().InvalidateRect(None, new_h == ID0)?; // call .wm_paint(), with erase on Restart
|
||||
Ok(())
|
||||
});
|
||||
|
||||
wnd.run_main(None).unwrap();
|
||||
}
|
||||
137
Task/Snake/Sidef/snake.sidef
Normal file
137
Task/Snake/Sidef/snake.sidef
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
class SnakeGame(w, h) {
|
||||
const readkey = frequire('Term::ReadKey')
|
||||
const ansi = frequire('Term::ANSIColor')
|
||||
|
||||
enum (VOID, HEAD, BODY, TAIL, FOOD)
|
||||
|
||||
define (
|
||||
LEFT = [+0, -1],
|
||||
RIGHT = [+0, +1],
|
||||
UP = [-1, +0],
|
||||
DOWN = [+1, +0],
|
||||
)
|
||||
|
||||
define BG_COLOR = "on_black"
|
||||
define FOOD_COLOR = ("red" + " " + BG_COLOR)
|
||||
define SNAKE_COLOR = ("bold green" + " " + BG_COLOR)
|
||||
define SLEEP_SEC = 0.02
|
||||
|
||||
const (
|
||||
A_VOID = ansi.colored(' ', BG_COLOR),
|
||||
A_FOOD = ansi.colored('❇', FOOD_COLOR),
|
||||
A_BLOCK = ansi.colored('■', SNAKE_COLOR),
|
||||
)
|
||||
|
||||
has dir = LEFT
|
||||
has grid = [[]]
|
||||
has head_pos = [0, 0]
|
||||
has tail_pos = [0, 0]
|
||||
|
||||
method init {
|
||||
grid = h.of { w.of { [VOID] } }
|
||||
|
||||
head_pos = [h//2, w//2]
|
||||
tail_pos = [head_pos[0], head_pos[1]+1]
|
||||
|
||||
grid[head_pos[0]][head_pos[1]] = [HEAD, dir] # head
|
||||
grid[tail_pos[0]][tail_pos[1]] = [TAIL, dir] # tail
|
||||
|
||||
self.make_food()
|
||||
}
|
||||
|
||||
method make_food {
|
||||
var (food_x, food_y)
|
||||
|
||||
do {
|
||||
food_x = w.rand.int
|
||||
food_y = h.rand.int
|
||||
} while (grid[food_y][food_x][0] != VOID)
|
||||
|
||||
grid[food_y][food_x][0] = FOOD
|
||||
}
|
||||
|
||||
method display {
|
||||
print("\033[H", grid.map { |row|
|
||||
row.map { |cell|
|
||||
given (cell[0]) {
|
||||
when (VOID) { A_VOID }
|
||||
when (FOOD) { A_FOOD }
|
||||
default { A_BLOCK }
|
||||
}
|
||||
}.join('')
|
||||
}.join("\n")
|
||||
)
|
||||
}
|
||||
|
||||
method move {
|
||||
var grew = false
|
||||
|
||||
# Move the head
|
||||
var (y, x) = head_pos...
|
||||
|
||||
var new_y = (y+dir[0] % h)
|
||||
var new_x = (x+dir[1] % w)
|
||||
|
||||
var cell = grid[new_y][new_x]
|
||||
|
||||
given (cell[0]) {
|
||||
when (BODY) { die "\nYou just bit your own body!\n" }
|
||||
when (TAIL) { die "\nYou just bit your own tail!\n" }
|
||||
when (FOOD) { grew = true; self.make_food() }
|
||||
}
|
||||
|
||||
# Create a new head
|
||||
grid[new_y][new_x] = [HEAD, dir]
|
||||
|
||||
# Replace the current head with body
|
||||
grid[y][x] = [BODY, dir]
|
||||
|
||||
# Update the head position
|
||||
head_pos = [new_y, new_x]
|
||||
|
||||
# Move the tail
|
||||
if (!grew) {
|
||||
var (y, x) = tail_pos...
|
||||
|
||||
var pos = grid[y][x][1]
|
||||
var new_y = (y+pos[0] % h)
|
||||
var new_x = (x+pos[1] % w)
|
||||
|
||||
grid[y][x][0] = VOID # erase the current tail
|
||||
grid[new_y][new_x][0] = TAIL # create a new tail
|
||||
|
||||
tail_pos = [new_y, new_x]
|
||||
}
|
||||
}
|
||||
|
||||
method play {
|
||||
STDOUT.autoflush(true)
|
||||
readkey.ReadMode(3)
|
||||
|
||||
try {
|
||||
loop {
|
||||
var key
|
||||
while (!defined(key = readkey.ReadLine(-1))) {
|
||||
self.move()
|
||||
self.display()
|
||||
Sys.sleep(SLEEP_SEC)
|
||||
}
|
||||
|
||||
given (key) {
|
||||
when ("\e[A") { if (dir != DOWN ) { dir = UP } }
|
||||
when ("\e[B") { if (dir != UP ) { dir = DOWN } }
|
||||
when ("\e[C") { if (dir != LEFT ) { dir = RIGHT } }
|
||||
when ("\e[D") { if (dir != RIGHT) { dir = LEFT } }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
readkey.ReadMode(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var w = `tput cols`.to_i
|
||||
var h = `tput lines`.to_i
|
||||
|
||||
SnakeGame(w || 80, h || 24).play
|
||||
111
Task/Snake/UNIX-Shell/snake.sh
Normal file
111
Task/Snake/UNIX-Shell/snake.sh
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
function main {
|
||||
typeset -i game_over=0
|
||||
typeset -i height=$(tput lines) width=$(tput cols)
|
||||
|
||||
# start out in the middle moving to the right
|
||||
typeset -i dx dy hx=$(( width/2 )) hy=$(( height/2 ))
|
||||
typeset -a sx=($hx) sy=($hy)
|
||||
typeset -a timeout
|
||||
clear
|
||||
tput cup "$sy" "$sx" && printf '@'
|
||||
tput cup $(( height/2+2 )) 0
|
||||
center $width "Press h, j, k, l to move left, down, up, right"
|
||||
|
||||
# place first food
|
||||
typeset -i fx=hx fy=hy
|
||||
while (( fx == hx && fy == hy )); do
|
||||
fx=$(( RANDOM % (width-2)+1 )) fy=$(( RANDOM % (height-2)+1 ))
|
||||
done
|
||||
tput cup "$fy" "$fx" && printf '*'
|
||||
|
||||
# handle variations between shells
|
||||
keypress=(-N 1) origin=0
|
||||
if [[ -n $ZSH_VERSION ]]; then
|
||||
keypress=(-k)
|
||||
origin=1
|
||||
fi
|
||||
|
||||
stty -echo
|
||||
tput civis
|
||||
typeset key
|
||||
read "${keypress[@]}" -s key
|
||||
typeset -i start_time=$(date +%s)
|
||||
tput cup "$(( height/2+2 ))" 0 && tput el
|
||||
while (( ! game_over )); do
|
||||
timeout=(-t $(printf '0.%04d' $(( 2000 / (${#sx[@]}+1) )) ) )
|
||||
if [[ -z $key ]]; then
|
||||
read "${timeout[@]}" "${keypress[@]}" -s key
|
||||
fi
|
||||
|
||||
case "$key" in
|
||||
h) if (( dx != 1 )); then dx=-1; dy=0; fi;;
|
||||
j) if (( dy != -1 )); then dy=1; dx=0; fi;;
|
||||
k) if (( dy != 1 )); then dy=-1; dx=0; fi;;
|
||||
l) if (( dx != -1 )); then dx=1; dy=0; fi;;
|
||||
q) game_over=1; tput cup 0 0 && print "Final food was at ($fx,$fy)";;
|
||||
esac
|
||||
key=
|
||||
(( hx += dx, hy += dy ))
|
||||
# if we try to go off screen, game over
|
||||
if (( hx < 0 || hx >= width || hy < 0 || hy >= height )); then
|
||||
game_over=1
|
||||
else
|
||||
# if we run into ourself, game over
|
||||
for (( i=0; i<${#sx[@]}; ++i )); do
|
||||
if (( hx==sx[i+origin] && hy==sy[i+origin] )); then
|
||||
game_over=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if (( game_over )); then
|
||||
break
|
||||
fi
|
||||
# add new spot
|
||||
sx+=($hx) sy+=($hy)
|
||||
|
||||
if (( hx == fx && hy == fy )); then
|
||||
# if we just ate some food, place some new food out
|
||||
ok=0
|
||||
while (( ! ok )); do
|
||||
# make sure we don't put it under ourselves
|
||||
ok=1
|
||||
fx=$(( RANDOM % (width-2)+1 )) fy=$(( RANDOM % (height-2)+1 ))
|
||||
for (( i=0; i<${#sx[@]}; ++i )); do
|
||||
if (( fx == sx[i+origin] && fy == sy[i+origin] )); then
|
||||
ok=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
done
|
||||
tput cup "$fy" "$fx" && printf '*'
|
||||
# and don't remove our tail because we've just grown by 1
|
||||
else
|
||||
# if we didn't just eat food, remove our tail from its previous spot
|
||||
tput cup ${sy[origin]} ${sx[origin]} && printf ' '
|
||||
sx=( ${sx[@]:1} )
|
||||
sy=( ${sy[@]:1} )
|
||||
fi
|
||||
# draw our new head
|
||||
tput cup "$hy" "$hx" && printf '@'
|
||||
done
|
||||
typeset -i end_time=$(date +%s)
|
||||
tput cup $(( height / 2 -1 )) 0 && center $width 'GAME OVER'
|
||||
tput cup $(( height / 2 )) 0 &&
|
||||
center $width 'Time: %d seconds' $(( end_time - start_time ))
|
||||
tput cup $(( height / 2 + 1 )) 0 &&
|
||||
center $width 'Final length: %d' ${#sx[@]}
|
||||
echo
|
||||
stty echo
|
||||
tput cnorm
|
||||
}
|
||||
|
||||
function center {
|
||||
typeset -i width=$1 i
|
||||
shift
|
||||
typeset message=$(printf "$@")
|
||||
tput cuf $(( (width-${#message}) / 2 ))
|
||||
printf '%s' "$message"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
136
Task/Snake/Wren/snake-1.wren
Normal file
136
Task/Snake/Wren/snake-1.wren
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/* snake.wren */
|
||||
|
||||
import "random" for Random
|
||||
import "./dynamic" for Enum, Lower
|
||||
|
||||
foreign class Window {
|
||||
construct initscr() {}
|
||||
|
||||
foreign nodelay(bf)
|
||||
}
|
||||
|
||||
class Ncurses {
|
||||
foreign static cbreak()
|
||||
|
||||
foreign static noecho()
|
||||
|
||||
foreign static refresh()
|
||||
|
||||
foreign static getch()
|
||||
|
||||
foreign static mvaddch(y, x, ch)
|
||||
|
||||
foreign static endwin()
|
||||
}
|
||||
|
||||
class C {
|
||||
foreign static usleep(usec)
|
||||
}
|
||||
|
||||
var Dir = Enum.create("Dir", ["N", "E", "S", "W"])
|
||||
var State = Enum.create("State", ["space", "food", "border"])
|
||||
|
||||
var w = 80
|
||||
var h = 40
|
||||
var board = List.filled(w * h, 0)
|
||||
var rand = Random.new()
|
||||
var head
|
||||
var dir
|
||||
var quit
|
||||
|
||||
// ASCII values
|
||||
var hash = 35
|
||||
var at = 64
|
||||
var dot = 46
|
||||
var spc = 32
|
||||
|
||||
/* negative values denote the snake (a negated time-to-live in given cell) */
|
||||
|
||||
// reduce a time-to-live, effectively erasing the tail
|
||||
var age = Fn.new {
|
||||
for (i in 0...w * h) {
|
||||
if (board[i] < 0) board[i] = board[i] + 1
|
||||
}
|
||||
}
|
||||
|
||||
// put a piece of food at random empty position
|
||||
var plant = Fn.new {
|
||||
var r
|
||||
while (true) {
|
||||
r = rand.int(w * h)
|
||||
if (board[r] = State.space) break
|
||||
}
|
||||
board[r] = State.food
|
||||
}
|
||||
|
||||
// initialize the board, plant a very first food item
|
||||
var start = Fn.new {
|
||||
for (i in 0...w) board[i] = board[i + (h - 1) * w] = State.border
|
||||
for (i in 0...h) board[i * w] = board[i * w + w - 1] = State.border
|
||||
head = (w * (h - 1 - h % 2) / 2).floor // screen center for any h
|
||||
board[head] = -5
|
||||
dir = Dir.N
|
||||
quit = false
|
||||
plant.call()
|
||||
}
|
||||
|
||||
var step = Fn.new {
|
||||
var len = board[head]
|
||||
if (dir == Dir.N) {
|
||||
head = head - w
|
||||
} else if (dir == Dir.S) {
|
||||
head = head + w
|
||||
} else if (dir == Dir.W) {
|
||||
head = head - 1
|
||||
} else if (dir == Dir.E) {
|
||||
head = head + 1
|
||||
}
|
||||
|
||||
if (board[head] == State.space) {
|
||||
board[head] = len - 1 // keep in mind len is negative
|
||||
age.call()
|
||||
} else if (board[head] == State.food) {
|
||||
board[head] = len - 1
|
||||
plant.call()
|
||||
} else {
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
|
||||
var show = Fn.new {
|
||||
var symbol = [spc, at, dot]
|
||||
for (i in 0...w*h) {
|
||||
Ncurses.mvaddch((i/w).floor, i % w, board[i] < 0 ? hash : symbol[board[i]])
|
||||
}
|
||||
Ncurses.refresh()
|
||||
}
|
||||
|
||||
var initScreen = Fn.new {
|
||||
var win = Window.initscr()
|
||||
Ncurses.cbreak()
|
||||
Ncurses.noecho()
|
||||
win.nodelay(true)
|
||||
}
|
||||
|
||||
initScreen.call()
|
||||
start.call()
|
||||
while (true) {
|
||||
show.call()
|
||||
var ch = Ncurses.getch()
|
||||
if (ch == Lower.i) {
|
||||
dir = Dir.N
|
||||
} else if (ch == Lower.j) {
|
||||
dir = Dir.W
|
||||
} else if (ch == Lower.k) {
|
||||
dir = Dir.S
|
||||
} else if (ch == Lower.l) {
|
||||
dir = Dir.E
|
||||
} else if (ch == Lower.q) {
|
||||
quit = true
|
||||
}
|
||||
step.call()
|
||||
C.usleep(300 * 1000) // 300 ms is a reasonable delay
|
||||
if (quit) break
|
||||
}
|
||||
C.usleep(999 * 1000)
|
||||
Ncurses.endwin()
|
||||
163
Task/Snake/Wren/snake-2.wren
Normal file
163
Task/Snake/Wren/snake-2.wren
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* gcc snake.c -o snake -lncurses -lwren -lm */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ncurses.h>
|
||||
#include <unistd.h>
|
||||
#include "wren.h"
|
||||
|
||||
/* C <=> Wren interface functions */
|
||||
|
||||
void C_windowAllocate(WrenVM* vm) {
|
||||
WINDOW** pwin = (WINDOW**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(WINDOW*));
|
||||
*pwin = initscr();
|
||||
}
|
||||
|
||||
void C_nodelay(WrenVM* vm) {
|
||||
WINDOW* win = *(WINDOW**)wrenGetSlotForeign(vm, 0);
|
||||
bool bf = wrenGetSlotBool(vm, 1);
|
||||
nodelay(win, bf);
|
||||
}
|
||||
|
||||
void C_cbreak(WrenVM* vm) {
|
||||
cbreak();
|
||||
}
|
||||
|
||||
void C_noecho(WrenVM* vm) {
|
||||
noecho();
|
||||
}
|
||||
|
||||
void C_refresh(WrenVM* vm) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
void C_getch(WrenVM* vm) {
|
||||
int ch = getch();
|
||||
wrenSetSlotDouble(vm, 0, (double)ch);
|
||||
}
|
||||
|
||||
void C_mvaddch(WrenVM* vm) {
|
||||
int y = (int)wrenGetSlotDouble(vm, 1);
|
||||
int x = (int)wrenGetSlotDouble(vm, 2);
|
||||
const chtype ch = (const chtype)wrenGetSlotDouble(vm, 3);
|
||||
mvaddch(y, x, ch);
|
||||
}
|
||||
|
||||
void C_endwin(WrenVM* vm) {
|
||||
endwin();
|
||||
}
|
||||
|
||||
void C_usleep(WrenVM* vm) {
|
||||
useconds_t usec = (useconds_t)wrenGetSlotDouble(vm, 1);
|
||||
usleep(usec);
|
||||
}
|
||||
|
||||
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
|
||||
WrenForeignClassMethods methods;
|
||||
methods.allocate = NULL;
|
||||
methods.finalize = NULL;
|
||||
if (strcmp(module, "main") == 0) {
|
||||
if (strcmp(className, "Window") == 0) {
|
||||
methods.allocate = C_windowAllocate;
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
WrenForeignMethodFn bindForeignMethod(
|
||||
WrenVM* vm,
|
||||
const char* module,
|
||||
const char* className,
|
||||
bool isStatic,
|
||||
const char* signature) {
|
||||
if (strcmp(module, "main") == 0) {
|
||||
if (strcmp(className, "Window") == 0) {
|
||||
if (!isStatic && strcmp(signature, "nodelay(_)") == 0) return C_nodelay;
|
||||
} else if (strcmp(className, "Ncurses") == 0) {
|
||||
if (isStatic && strcmp(signature, "cbreak()") == 0) return C_cbreak;
|
||||
if (isStatic && strcmp(signature, "noecho()") == 0) return C_noecho;
|
||||
if (isStatic && strcmp(signature, "refresh()") == 0) return C_refresh;
|
||||
if (isStatic && strcmp(signature, "getch()") == 0) return C_getch;
|
||||
if (isStatic && strcmp(signature, "mvaddch(_,_,_)") == 0) return C_mvaddch;
|
||||
if (isStatic && strcmp(signature, "endwin()") == 0) return C_endwin;
|
||||
} else if (strcmp(className, "C") == 0) {
|
||||
if (isStatic && strcmp(signature, "usleep(_)") == 0) return C_usleep;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void writeFn(WrenVM* vm, const char* text) {
|
||||
printf("%s", text);
|
||||
}
|
||||
|
||||
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
|
||||
switch (errorType) {
|
||||
case WREN_ERROR_COMPILE:
|
||||
printf("[%s line %d] [Error] %s\n", module, line, msg);
|
||||
break;
|
||||
case WREN_ERROR_STACK_TRACE:
|
||||
printf("[%s line %d] in %s\n", module, line, msg);
|
||||
break;
|
||||
case WREN_ERROR_RUNTIME:
|
||||
printf("[Runtime Error] %s\n", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *readFile(const char *fileName) {
|
||||
FILE *f = fopen(fileName, "r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
rewind(f);
|
||||
char *script = malloc(fsize + 1);
|
||||
fread(script, 1, fsize, f);
|
||||
fclose(f);
|
||||
script[fsize] = 0;
|
||||
return script;
|
||||
}
|
||||
|
||||
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
|
||||
if( result.source) free((void*)result.source);
|
||||
}
|
||||
|
||||
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
|
||||
WrenLoadModuleResult result = {0};
|
||||
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
|
||||
result.onComplete = loadModuleComplete;
|
||||
char fullName[strlen(name) + 6];
|
||||
strcpy(fullName, name);
|
||||
strcat(fullName, ".wren");
|
||||
result.source = readFile(fullName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
WrenConfiguration config;
|
||||
wrenInitConfiguration(&config);
|
||||
config.writeFn = &writeFn;
|
||||
config.errorFn = &errorFn;
|
||||
config.bindForeignClassFn = &bindForeignClass;
|
||||
config.bindForeignMethodFn = &bindForeignMethod;
|
||||
config.loadModuleFn = &loadModule;
|
||||
WrenVM* vm = wrenNewVM(&config);
|
||||
const char* module = "main";
|
||||
const char* fileName = "snake.wren";
|
||||
char *script = readFile(fileName);
|
||||
WrenInterpretResult result = wrenInterpret(vm, module, script);
|
||||
switch (result) {
|
||||
case WREN_RESULT_COMPILE_ERROR:
|
||||
printf("Compile Error!\n");
|
||||
break;
|
||||
case WREN_RESULT_RUNTIME_ERROR:
|
||||
printf("Runtime Error!\n");
|
||||
break;
|
||||
case WREN_RESULT_SUCCESS:
|
||||
break;
|
||||
}
|
||||
wrenFreeVM(vm);
|
||||
free(script);
|
||||
return 0;
|
||||
}
|
||||
109
Task/Snake/XPL0/snake.xpl0
Normal file
109
Task/Snake/XPL0/snake.xpl0
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
def Width=40, Height=25-1, \playing area including border
|
||||
StartLength = 10, \starting length of snake including head
|
||||
Morsels = 10; \number of food items constantly offered
|
||||
int Heading; \direction snake is heading
|
||||
def Up, Down, Left, Right;
|
||||
int Length, \current length of snake including head
|
||||
Score; \number of food items eaten
|
||||
char SnakeX(10000), \location of each segment including head
|
||||
SnakeY(10000), \ample room to grow
|
||||
FoodX(Morsels), FoodY(Morsels); \location of each food item
|
||||
def Black, Blue, Green, Cyan, Red, Magenta, Brown, White, \attribute colors
|
||||
Gray, LBlue, LGreen, LCyan, LRed, LMagenta, Yellow, BWhite; \EGA palette
|
||||
|
||||
proc PlaceFood(N); \Place Nth food item in playing area
|
||||
int N;
|
||||
[FoodX(N):= Ran(Width-3) + 1; \pick random location inside borders
|
||||
FoodY(N):= Ran(Height-3) + 1;
|
||||
Cursor(FoodX(N), FoodY(N)); \show food
|
||||
Attrib(Red<<4+LRed);
|
||||
ChOut(6, ^@);
|
||||
]; \PlaceFood
|
||||
|
||||
|
||||
int X, Y, I, C;
|
||||
[SetVid($01); \set 40x25 text mode
|
||||
ShowCursor(false); \turn off flashing cursor
|
||||
|
||||
Attrib(Blue<<4+LBlue); \show borders
|
||||
Cursor(0, 0);
|
||||
for X:= 0 to Width-1 do ChOut(6, ^+);
|
||||
Cursor(0, Height-1);
|
||||
for X:= 0 to Width-1 do ChOut(6, ^+);
|
||||
for Y:= 0 to Height-1 do
|
||||
[Cursor(0, Y); ChOut(6, ^+);
|
||||
Cursor(Width-1, Y); ChOut(6, ^+);
|
||||
];
|
||||
Attrib(Black<<4+White); \show initial score
|
||||
Cursor(0, 24);
|
||||
Text(6, "Score: 0");
|
||||
Score:= 0;
|
||||
|
||||
SnakeX(0):= Width/2; \start snake head at center
|
||||
SnakeY(0):= Height/2;
|
||||
Heading:= Left;
|
||||
Length:= StartLength;
|
||||
for I:= 1 to Length-1 do \segments follow head to the right
|
||||
[SnakeX(I):= SnakeX(I-1) + 1;
|
||||
SnakeY(I):= SnakeY(I-1);
|
||||
];
|
||||
for I:= 0 to Morsels-1 do PlaceFood(I); \sow some tasty food
|
||||
|
||||
\Continuously move snake
|
||||
loop \--------------------------------------------------------------------------
|
||||
[Attrib(Black<<4+White); \remove tail-end segment
|
||||
Cursor(SnakeX(Length-1), SnakeY(Length-1));
|
||||
ChOut(6, ^ );
|
||||
Attrib(Green<<4+Yellow); \add segment at head location
|
||||
Cursor(SnakeX(0), SnakeY(0));
|
||||
ChOut(6, ^#);
|
||||
|
||||
\Shift coordinates toward tail (+1 in case a segment gets added)
|
||||
for I:= Length downto 1 do \segment behind head gets head's coords
|
||||
[SnakeX(I):= SnakeX(I-1);
|
||||
SnakeY(I):= SnakeY(I-1);
|
||||
];
|
||||
if ChkKey then \key hit--get new movement direction
|
||||
[repeat C:= ChIn(1) until C # 0; \remove arrow keys' prefix byte
|
||||
case C of
|
||||
$1B: exit; \Escape, and scan codes for arrow keys
|
||||
$48: if Heading # Down then Heading:= Up;
|
||||
$50: if Heading # Up then Heading:= Down;
|
||||
$4B: if Heading # Right then Heading:= Left;
|
||||
$4D: if Heading # Left then Heading:= Right
|
||||
other []; \ignore any other keystrokes
|
||||
];
|
||||
case Heading of \move head to its new location
|
||||
Up: SnakeY(0):= SnakeY(0)-1;
|
||||
Down: SnakeY(0):= SnakeY(0)+1;
|
||||
Left: SnakeX(0):= SnakeX(0)-1;
|
||||
Right:SnakeX(0):= SnakeX(0)+1
|
||||
other [];
|
||||
Cursor(SnakeX(0), SnakeY(0)); \show head at its new location
|
||||
ChOut(6, ^8);
|
||||
|
||||
for I:= 0 to Morsels-1 do
|
||||
if SnakeX(0)=FoodX(I) & SnakeY(0)=FoodY(I) then
|
||||
[Score:= Score+1; \ate a morsel
|
||||
Attrib(Black<<4+White);
|
||||
Cursor(7, 24);
|
||||
IntOut(6, Score*10);
|
||||
PlaceFood(I); \replenish morsel
|
||||
Length:= Length+1; \grow snake one segment
|
||||
I:= Morsels; \over eating can be bad--quit for loop
|
||||
Sound(1, 1, 1500); \BURP!
|
||||
Sound(1, 1, 1000);
|
||||
];
|
||||
if I = Morsels then Sound(0, 2, 1); \no sound adds delay of 2/18th second
|
||||
|
||||
if SnakeX(0)=0 or SnakeX(0)=Width-1 or
|
||||
SnakeY(0)=0 or SnakeY(0)=Height-1 then
|
||||
quit; \snake hit border--game over
|
||||
for I:= 1 to Length-1 do
|
||||
if SnakeX(0)=SnakeX(I) & SnakeY(0)=SnakeY(I) then
|
||||
quit; \snake bit itself--game over
|
||||
]; \loop -----------------------------------------------------------------------
|
||||
for I:= 1 to 8 do Sound(1, 1, 4000*I); \death dirge
|
||||
Sound(0, 36, 1); \pause 2 seconds to see result
|
||||
OpenI(1); \flush any pending keystrokes
|
||||
]
|
||||
89
Task/Snake/ZX-Spectrum-Basic/snake.basic
Normal file
89
Task/Snake/ZX-Spectrum-Basic/snake.basic
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
10 FOR i=0 TO 7
|
||||
20 READ bits
|
||||
30 POKE USR "L"+i,bits
|
||||
40 NEXT i
|
||||
50 FOR i=0 TO 7
|
||||
60 READ bits
|
||||
70 POKE USR "R"+i,bits
|
||||
80 NEXT i
|
||||
90 FOR i=0 TO 7
|
||||
100 READ bits
|
||||
110 POKE USR "P"+i,bits
|
||||
120 NEXT i
|
||||
130 RESTORE 740
|
||||
140 FOR i=7 TO 0 STEP -1
|
||||
150 READ bits
|
||||
160 POKE USR "D"+i,bits
|
||||
170 NEXT i
|
||||
180 FOR i=0 TO 7
|
||||
190 READ bits
|
||||
200 POKE USR "F"+i, bits
|
||||
210 NEXT i
|
||||
220 PAPER 0
|
||||
230 CLS
|
||||
240 LET snakex=19
|
||||
250 LET snakey=15
|
||||
260 LET dx=-1
|
||||
270 LET dy=0
|
||||
280 LET s$=CHR$ 15+CHR$ 20+CHR$ 15+CHR$ 21
|
||||
290 LET foodx=INT (RND*32)
|
||||
300 LET foody=INT (RND*22)
|
||||
310 IF SCREEN$ (foody,foodx)<>" " THEN GO TO 290
|
||||
320 INK 2
|
||||
330 PRINT AT foody,foodx;CHR$ 149
|
||||
340 INK 4
|
||||
350 INVERSE 1
|
||||
360 PRINT AT CODE s$,CODE s$(1);"#"
|
||||
370 INVERSE 0
|
||||
380 IF INKEY$="q" AND dy=0 THEN LET dx=0: LET dy=-1
|
||||
390 IF INKEY$="a" AND dy=0 THEN LET dx=0: LET dy=1
|
||||
400 IF INKEY$="o" AND dx=0 THEN LET dx=-1: LET dy=0
|
||||
410 IF INKEY$="p" AND dx=0 THEN LET dx=1: LET dy=0
|
||||
420 IF dx=-1 THEN PRINT AT snakey,snakex;CHR$ 155
|
||||
430 IF dx=1 THEN PRINT AT snakey,snakex;CHR$ 161
|
||||
440 IF dy=1 THEN PRINT AT snakey,snakex;CHR$ 159
|
||||
450 IF dy=-1 THEN PRINT AT snakey,snakex;CHR$ 147
|
||||
460 LET s$=CHR$ snakey+CHR$ snakex+s$
|
||||
470 IF snakex=foodx AND snakey=foody THEN GO TO 290
|
||||
480 PRINT AT CODE s$(LEN s$-1),CODE s$(LEN s$);" "
|
||||
490 LET s$=s$( TO LEN s$-2)
|
||||
500 LET snakex=snakex+dx
|
||||
510 LET snakey=snakey+dy
|
||||
520 IF snakex=-1 THEN LET snakex=31
|
||||
530 IF snakex=32 THEN LET snakex=0
|
||||
540 IF snakey=-1 THEN LET snakey=21
|
||||
550 IF snakey=22 THEN LET snakey=0
|
||||
560 IF SCREEN$ (snakey,snakex)="#" THEN STOP
|
||||
570 GO TO 340
|
||||
580 DATA BIN 00001111
|
||||
590 DATA BIN 00111111
|
||||
600 DATA BIN 01110011
|
||||
610 DATA BIN 11110011
|
||||
620 DATA BIN 11111111
|
||||
630 DATA BIN 01111111
|
||||
640 DATA BIN 00000111
|
||||
650 DATA BIN 00011111
|
||||
660 DATA BIN 11110000
|
||||
670 DATA BIN 11111100
|
||||
680 DATA BIN 11001110
|
||||
690 DATA BIN 11001111
|
||||
700 DATA BIN 11111111
|
||||
710 DATA BIN 11111110
|
||||
720 DATA BIN 11100000
|
||||
730 DATA BIN 11111000
|
||||
740 DATA BIN 00011000
|
||||
750 DATA BIN 00111100
|
||||
760 DATA BIN 01111100
|
||||
770 DATA BIN 01111101
|
||||
780 DATA BIN 11001101
|
||||
790 DATA BIN 11001111
|
||||
800 DATA BIN 11111111
|
||||
810 DATA BIN 11111111
|
||||
820 DATA BIN 00000100
|
||||
830 DATA BIN 00001000
|
||||
840 DATA BIN 01101011
|
||||
850 DATA BIN 11111100
|
||||
860 DATA BIN 11111100
|
||||
870 DATA BIN 11111100
|
||||
880 DATA BIN 01111111
|
||||
890 DATA BIN 00110110
|
||||
Loading…
Add table
Add a link
Reference in a new issue