Nasal-Interpreter/test/tetris.nas

347 lines
9.5 KiB
Plaintext

import.module.libkey;
var color=[
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
"\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m",
];
var blocktype=[
[0,1,2,3 ],
[4,5,6,7 ],
[8,9,10,11],
[12,13 ],
[14 ],
[15,16 ],
[17,18 ]
];
var blockshape=[
# [][] [] [][][]
# [] [] [] []
# [] [][][] [][]
[[0,0],[1,0],[0,1],[0,2]],
[[0,0],[0,1],[1,1],[2,1]],
[[0,0],[0,1],[0,2],[-1,2]],
[[0,0],[1,0],[2,0],[2,1]],
# [][] [][][] []
# [] [] [] []
# [] [][] [][][]
[[0,0],[1,0],[1,1],[1,2]],
[[0,0],[1,0],[2,0],[0,1]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[0,1],[-1,1],[-2,1]],
# [] [] [][][] []
# [][][] [][] [] [][]
# [] []
[[0,0],[0,1],[-1,1],[1,1]],
[[0,0],[0,1],[-1,1],[0,2]],
[[0,0],[-1,0],[1,0],[0,1]],
[[0,0],[0,1],[0,2],[1,1]],
# [] [][][][]
# []
# []
# []
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[1,0],[2,0],[3,0]],
# [][]
# [][]
[[0,0],[1,0],[0,1],[1,1]],
# [] [][]
# [][] [][]
# []
[[0,0],[0,1],[-1,1],[-1,2]],
[[0,0],[1,0],[1,1],[2,1]],
# [] [][]
# [][] [][]
# []
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[1,0],[0,1],[-1,1]]
];
var color_count=0;
var counter=0;
var package=[0,1,2,3,4,5,6];
var exchange=func(){
for(var i=6;i>=0;i-=1){
var index=int(i*rand());
(package[i],package[index])=(package[index],package[i]);
}
}
var block={
x:0,
y:0,
rotate:0,
type:nil,
shape:nil,
color:nil,
new:func(x=0,y=0){
(me.x,me.y)=(x,y);
me.rotate=0;
me.type=blocktype[package[counter]];
counter+=1;
if(counter==7){
exchange();
counter=0;
}
me.shape=blockshape[me.type[me.rotate]];
me.color=color_count;
color_count+=1;
if(color_count>=size(color))
color_count=0;
return {parents:[block]};
}
};
var mapgen=func(mapx,mapy){
var (score,gameover)=(0,0);
var (empty,unset,full)=(0,1,2);
if(mapx<1 or mapy<1)
die("map_x or map_y must be greater than 1");
# use in print
var line="";
for(var i=0;i<mapx;i+=1)
line~="══";
var head="\e[32m╔"~line~"╗\e[0m\n";
var tail="\e[32m╚"~line~"╝\e[0m\n";
# generate new map
var map=[];
for(var y=0;y<mapy;y+=1){
var tmp=[];
for(var x=0;x<mapx;x+=1)
append(tmp,empty);
append(map,tmp);
}
var blk=nil;
var new_block=func(){
blk=block.new(int(mapx/2),0);
# check if has enough place to place a new block
foreach(var i;blk.shape)
if(map[blk.y+i[1]][blk.x+i[0]]>=full){
gameover=1;
return;
}
# update map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
}
new_block(); # initialize the first block
# color print
var map_print=func(){
var s="\e[1;1H"~head;
for(var y=0;y<mapy;y+=1){
s~="\e[32m║\e[0m";
for(var x=0;x<mapx;x+=1){
var c=map[y][x];
if(c==empty)
s~=" ";
elsif(c==unset)
s~=color[blk.color]~"██\e[0m";
elsif(c>=full)
s~=color[c-full]~"██\e[0m";
}
s~="\e[32m║\e[0m\n";
}
s~=tail;
print(s,"\e[31ms\e[32mc\e[33mo\e[34mr\e[35me\e[36m: \e[0m",score,'\n');
}
var moveleft=func(){
var (x,y)=(blk.x-1,blk.y);
foreach(var i;blk.shape){
if(x+i[0]<0)
return;
if(map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.x=x;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var moveright=func(){
var (x,y)=(blk.x+1,blk.y);
foreach(var i;blk.shape){
if(x+i[0]>=mapx)
return;
if(map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.x=x;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var rotate=func(){
var (r,x,y)=(blk.rotate,blk.x,blk.y);
r=(r+1>=size(blk.type))?0:r+1;
var shape=blockshape[blk.type[r]];
foreach(var i;shape){
if(x+i[0]>=mapx or x+i[0]<0 or y+i[1]>=mapy or y+i[1]<0)
return;
if(map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.rotate=r;
blk.shape=shape;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var fall=func(){
var (x,y)=(blk.x,blk.y+1);
# check if falls to the edge of other blocks or map
var sethere=0;
foreach(var i;blk.shape)
if(y+i[1]>=mapy or map[y+i[1]][x+i[0]]>=full){
sethere=1;
break;
}
# set block here and generate a new block
if(sethere){
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=blk.color+full;
checkmap();
new_block();
map_print();
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.y=y;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var checkmap=func(){
var lines=1;
for(var y=mapy-1;y>=0;y-=1){
# check if this line is full of blocks
var tmp=0;
for(var x=0;x<mapx;x+=1){
if(map[y][x]<full)
break;
tmp+=map[y][x];
}
# if is full, clear this line and
# all the lines above fall one block
if(x==mapx){
score+=lines*tmp;
lines*=2;
for(var t=y;t>=1;t-=1)
for(var x=0;x<mapx;x+=1)
map[t][x]=map[t-1][x];
for(var x=0;x<mapx;x+=1)
map[0][x]=empty;
y+=1;
}
}
map_print();
}
return {
print:map_print,
moveleft:moveleft,
moveright:moveright,
rotate:rotate,
fall:fall,
checkmap:checkmap,
gameover:func(){return gameover;}
};
}
var main=func(){
# windows use chcp 65001 to output unicode
if(os.platform()=="windows")
system("chcp 65001");
print(
"\ec\e[1:1H",
"╔═════════════════════════╗\n",
"║ TETRIS ║\n",
"╠═════════════════════════╣\n",
"║ w:rotate, a:move left ║\n",
"║ s:fall, d:move right ║\n",
"║ p:pause, q:quit ║\n",
"╠═════════════════════════╣\n",
"║ press any key to start ║\n",
"╚═════════════════════════╝\n"
);
rand(time(0));
exchange();
var map=mapgen(mapx:12,mapy:18);
libkey.getch();
print("\ec");
var counter=30;
while(1){
# nonblock input one character
var ch=libkey.nonblock();
if(ch){
if(ch=='a'[0]) # move left
map.moveleft();
elsif(ch=='d'[0]) # move right
map.moveright();
elsif(ch=='w'[0]) # rotate
map.rotate();
elsif(ch=='s'[0]) # move down
map.fall();
elsif(ch=='q'[0]) # quit the game
break;
if(ch=='p'[0]){ # pause the game
print("\rpress any key to continue...");
libkey.getch();
print("\r ");
}
map.checkmap();
if(map.gameover())
break;
}
if(!counter){
# automatically fall one block and check
map.fall();
map.checkmap();
if(map.gameover())
break;
counter=30;
}
unix.sleep(0.02);
counter-=1;
}
print(
map.gameover()?
"\e[31mg\e[32ma\e[33mm\e[34me \e[35mo\e[36mv\e[94me\e[31mr \e[32m~\e[0m\n":
"\e[31ms\e[32me\e[33me \e[34my\e[35mo\e[36mu \e[94m~\e[0m\n"
);
print(
"\e[31me\e[32mn\e[33mt\e[34me\e[35mr ",
"\e[36m'\e[94mq\e[95m' ",
"\e[35mt\e[36mo \e[94mq\e[95mu\e[91mi\e[92mt\e[0m\n"
);
while(libkey.getch()!='q'[0]);
};
main();