finish tetris.nas

This commit is contained in:
ValKmjolnir 2022-02-21 17:10:13 +08:00
parent 984deed883
commit 9456a903d7
4 changed files with 111 additions and 47 deletions

View File

@ -108,7 +108,7 @@ __CAUTION__: If want to use the release zip/tar.gz file to build the interpreter
Also remember to use g++ or clang++.(`mingw-w64` in __`Windows`__) Also remember to use g++ or clang++.(`mingw-w64` in __`Windows`__)
> [cpp compiler] -std=c++11 -O3 main.cpp -o nasal.exe -fno-exceptions > [cpp compiler] -std=c++11 -O3 main.cpp -o nasal.exe -fno-exceptions -static
Or use this in __`linux/macOS/Unix`__ Or use this in __`linux/macOS/Unix`__

View File

@ -4,7 +4,7 @@
#include <conio.h> #include <conio.h>
#else #else
#include <fcntl.h> #include <fcntl.h>
#include <termio.h> #include <termios.h>
#endif #endif
#ifndef _WIN32 #ifndef _WIN32

View File

@ -9,7 +9,7 @@ libkey.so: keyboard.cpp
clang++ -c -O3 keyboard.cpp -fPIC -o keyboard.o clang++ -c -O3 keyboard.cpp -fPIC -o keyboard.o
clang++ -shared -o libkey.so keyboard.o clang++ -shared -o libkey.so keyboard.o
libkey.dll: keyboard.cpp libkey.dll: keyboard.cpp
g++ -c -O3 keyboard.cpp -fPIC -o keyboard.o g++ -c -O3 keyboard.cpp -fPIC -o keyboard.o -static
g++ -shared -o libkey.dll keyboard.o g++ -shared -o libkey.dll keyboard.o -static
clean: clean:
rm *.o *.so *.dll *.dylib rm *.o *.so *.dll *.dylib

View File

@ -1,14 +1,18 @@
import("lib.nas"); import("lib.nas");
import("module/libkey.nas"); import("./module/libkey.nas");
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=[ var blocktype=[
[0,1,2,3], [0,1,2,3 ],
[4,5,6,7], [4,5,6,7 ],
[8,9,10,11], [8,9,10,11],
[12,13], [12,13 ],
[14], [14 ],
[15,16], [15,16 ],
[17,18] [17,18 ]
]; ];
var blockshape=[ var blockshape=[
# [][] [] [][][] # [][] [] [][][]
@ -52,32 +56,45 @@ var blockshape=[
[[0,0],[0,1],[1,1],[1,2]], [[0,0],[0,1],[1,1],[1,2]],
[[0,0],[1,0],[0,1],[-1,1]] [[0,0],[1,0],[0,1],[-1,1]]
]; ];
var stick_count=0; # make sure one stick in 10 tries
var block={ var block={
x:0, x:0,
y:0, y:0,
rotate:0, rotate:0,
type:nil, type:nil,
shape:nil, shape:nil,
color:nil,
new:func(x=0,y=0){ new:func(x=0,y=0){
(me.x,me.y)=(x,y); (me.x,me.y)=(x,y);
me.rotate=0; me.rotate=0;
me.type=blocktype[rand()*size(blocktype)]; var t=int(rand()*size(blocktype));
if(t!=3){
stick_count+=1;
if(stick_count==10)
(t,stick_count)=(3,0);
}else
stick_count=0;
me.type=blocktype[t];
me.shape=blockshape[me.type[me.rotate]]; me.shape=blockshape[me.type[me.rotate]];
me.color=int(rand()*size(color));
return {parents:[block]}; return {parents:[block]};
} }
}; };
var mapgen=func(mapx,mapy){ var mapgen=func(mapx,mapy){
var score=0; var (score,gameover)=(0,0);
var (empty,unset,full)=(0,1,2); var (empty,unset,full)=(0,1,2);
if(mapx<1 or mapy<1) if(mapx<1 or mapy<1)
die("map_x or map_y must be greater than 1"); die("map_x or map_y must be greater than 1");
# use in print # use in print
var table="\e[44m "; var table="\e[32m+";
for(var i=0;i<mapx;i+=1) for(var i=0;i<mapx;i+=1)
table~=" "; table~="--";
table~=" \e[0m\n"; table~="+\e[0m\n";
# generate new map # generate new map
var map=[]; var map=[];
for(var y=0;y<mapy;y+=1){ for(var y=0;y<mapy;y+=1){
@ -90,29 +107,37 @@ var mapgen=func(mapx,mapy){
var blk=nil; var blk=nil;
var new_block=func(){ var new_block=func(){
blk=block.new(int(mapx/2),0); blk=block.new(int(mapx/2),0);
# check game end unfinished
# 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) foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset; map[blk.y+i[1]][blk.x+i[0]]=unset;
} }
new_block(); new_block(); # initialize the first block
# color print # color print
var front=[
"31","32","33","34","35","36",
"91","92","93","94","95","96",
];
var map_print=func(){ var map_print=func(){
print("\e[1;1Hscore: ",score,"\n"); var s="\e[1;1H"~table;
var s=table;
for(var y=0;y<mapy;y+=1){ for(var y=0;y<mapy;y+=1){
s~="\e[44m \e[0m"; s~="\e[32m|\e[0m";
for(var x=0;x<mapx;x+=1){ for(var x=0;x<mapx;x+=1){
s~=(map[y][x]!=empty)?"\e["~front[rand()*12]~"m██\e[0m":" "; 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[44m \e[0m\n"; s~="\e[32m|\e[0m\n";
} }
s~=table; s~=table;
print(s); print(s," score: ",score,'\n');
} }
var moveleft=func(){ var moveleft=func(){
@ -120,9 +145,10 @@ var mapgen=func(mapx,mapy){
foreach(var i;blk.shape){ foreach(var i;blk.shape){
if(x+i[0]<0) if(x+i[0]<0)
return; return;
if(map[y+i[1]][x+i[0]]==full) if(map[y+i[1]][x+i[0]]>=full)
return; return;
} }
# update block state and map
foreach(var i;blk.shape) foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty; map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.x=x; blk.x=x;
@ -136,9 +162,10 @@ var mapgen=func(mapx,mapy){
foreach(var i;blk.shape){ foreach(var i;blk.shape){
if(x+i[0]>=mapx) if(x+i[0]>=mapx)
return; return;
if(map[y+i[1]][x+i[0]]==full) if(map[y+i[1]][x+i[0]]>=full)
return; return;
} }
# update block state and map
foreach(var i;blk.shape) foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty; map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.x=x; blk.x=x;
@ -154,9 +181,11 @@ var mapgen=func(mapx,mapy){
foreach(var i;shape){ foreach(var i;shape){
if(x+i[0]>=mapx or x+i[0]<0 or y+i[1]>=mapy or y+i[1]<0) if(x+i[0]>=mapx or x+i[0]<0 or y+i[1]>=mapy or y+i[1]<0)
return; return;
if(map[y+i[1]][x+i[0]]==full) if(map[y+i[1]][x+i[0]]>=full)
return; return;
} }
# update block state and map
foreach(var i;blk.shape) foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty; map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.rotate=r; blk.rotate=r;
@ -168,21 +197,23 @@ var mapgen=func(mapx,mapy){
var fall=func(){ var fall=func(){
var (x,y)=(blk.x,blk.y+1); var (x,y)=(blk.x,blk.y+1);
# check if falls to the edge of other blocks or map
var sethere=0; var sethere=0;
foreach(var i;blk.shape){ foreach(var i;blk.shape)
if(y+i[1]>=mapy or map[y+i[1]][x+i[0]]==full){ if(y+i[1]>=mapy or map[y+i[1]][x+i[0]]>=full){
sethere=1; sethere=1;
break; break;
} }
} # set block here and generate a new block
if(sethere){ if(sethere){
foreach(var i;blk.shape) foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=full; map[blk.y+i[1]][blk.x+i[0]]=blk.color+full;
checkmap(); checkmap();
new_block(); new_block();
map_print(); map_print();
return; return;
} }
# update block state and map
foreach(var i;blk.shape) foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty; map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.y=y; blk.y=y;
@ -193,11 +224,17 @@ var mapgen=func(mapx,mapy){
var checkmap=func(){ var checkmap=func(){
for(var y=mapy-1;y>=0;y-=1){ for(var y=mapy-1;y>=0;y-=1){
for(var x=0;x<mapx;x+=1) # check if this line is full of blocks
if(map[y][x]!=full) var tmp=0;
for(var x=0;x<mapx;x+=1){
if(map[y][x]<full)
break; break;
tmp+=map[y][x];
}
# if is full, clear this line and
# all the lines above fall one block
if(x==mapx){ if(x==mapx){
score+=mapx; score+=tmp;
for(var t=y;t>=1;t-=1) for(var t=y;t>=1;t-=1)
for(var x=0;x<mapx;x+=1) for(var x=0;x<mapx;x+=1)
map[t][x]=map[t-1][x]; map[t][x]=map[t-1][x];
@ -214,47 +251,74 @@ var mapgen=func(mapx,mapy){
moveright:moveright, moveright:moveright,
rotate:rotate, rotate:rotate,
fall:fall, fall:fall,
checkmap:checkmap checkmap:checkmap,
gameover:func(){return gameover;}
}; };
} }
var main=func(){ var main=func(){
print("\ec"); # windows use chcp 65001 to output unicode
if(os.platform()=="windows")
system("chcp 65001");
print(
"\ec\e[1:1H",
"+-------------------------+\n",
"| TETRIS |\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)); rand(time(0));
var map=mapgen(mapx:15,mapy:15); var map=mapgen(mapx:12,mapy:15);
libkey.init(); libkey.init();
libkey.getch();
print("\ec");
while(1){ while(1){
# nonblock input one character
var ch=libkey.nonblock(); var ch=libkey.nonblock();
if(ch){ if(ch){
if(ch=='a'[0]) # move left if(ch=='a'[0]) # move left
map.moveleft(); map.moveleft();
elsif(ch=='d'[0]) # move right elsif(ch=='d'[0]) # move right
map.moveright(); map.moveright();
elsif(ch=='s'[0]) # rotate elsif(ch=='w'[0]) # rotate
map.rotate(); map.rotate();
elsif(ch==' '[0]) # move down elsif(ch=='s'[0]) # move down
map.fall(); map.fall();
elsif(ch=='q'[0]) elsif(ch=='q'[0]) # quit the game
break; break;
if(ch=='p'[0]){ if(ch=='p'[0]){ # pause the game
print("\rpress any key to continue..."); print("\rpress any key to continue...");
libkey.getch(); libkey.getch();
print("\r "); print("\r ");
} }
map.checkmap(); map.checkmap();
if(map.gameover())
break;
unix.sleep(0.01); unix.sleep(0.01);
} }
else{ else{
# automatically fall one block and check
map.fall(); map.fall();
map.checkmap(); map.checkmap();
unix.sleep(0.65); if(map.gameover())
break;
unix.sleep(0.5);
} }
} }
libkey.close(); libkey.close();
print("\ec\e[31ms\e[32me\e[33me \e[34my\e[35mo\e[36mu \e[94m~\e[0m\n"); 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"
);
}; };
main(); main();