This is part two of our Tetris-like clone in J series. In this part we're going to see how the ncurses
interface was created.
Creating the ncurses UI
To create the user interface we used the ncurses
UI using the api/ncurses
package. Sadly all interactions with this API makes the code look like straightforward imperative code.
Since we represented the game field using a matrix, we need a way to visualize this matrix. The next snippet shows how we used the wattr_on
and mvwprintw
functions to print each cell of the game field with the given color.
drawGame=: 3 : 0
matrix =. >{.}.y
win =. >{.y
cols =. }. $ matrix
rows =. {. $ matrix
for_row. i.rows do.
for_col. i.cols do.
value =. (<row, col) { matrix
wattr_on_ncurses_ win;(COLOR_PAIR_ncurses_ (value+1));0
mvwprintw_1_ncurses_ win; row; (2*col); ((' '))
end.
end.
)
The game loop handles user interactions and game rules . Here's how it looks:
NB. Game loop
while. 1 do.
c =. wgetch_ncurses_ vin
if. c = KEY_UP_ncurses_ do.
game =: put_in_matrix (current*_1);k;j;game
current =. rotate current
needs_refresh =. 1
elseif. c = KEY_RIGHT_ncurses_ do.
game_tmp =. put_in_matrix (current*_1);k;j;game
if. can_put_in_matrix current;k;(j + 1);game_tmp do.
game =: game_tmp
j =. j + 1
needs_refresh =. 1
end.
elseif. c = KEY_LEFT_ncurses_ do.
game_tmp =. put_in_matrix (current*_1);k;j;game
if. can_put_in_matrix (current);k;(j - 1);game_tmp do.
game =: game_tmp
j =. j - 1
needs_refresh =. 1
end.
elseif. 1 do.
if. ((seconds_from_start'') - timestamp) < 0.1 do.
continue.
else.
timestamp =. seconds_from_start''
end.
if. automove = 0 do.
game =: put_in_matrix (current*_1);k;j;game
if. can_put_in_matrix (current);(k+1);j;game do.
k =. k + 1
else.
game =: put_in_matrix (current);k;j;game
k =. 0
j =. 0
if. can_put_in_matrix current;k;j;game do.
current =. (?@$ tetriminos) {:: tetriminos
else.
mvwprintw_1_ncurses_ vin; 0; 0; ' Game over '
nodelay_ncurses_ vin ;'0'
wgetch_ncurses_ vin
exit''
end.
end.
automove =. 2
needs_refresh =. 1
else.
automove =. automove - 1
end.
end.
unget_wch_ncurses_ c
if. needs_refresh do.
game =: put_in_matrix (current);k;j;game
game =: remove_full_rows game
drawGame vin; game
wrefresh_ncurses_ vin
needs_refresh =. 0
end.
end.
The rest of the code is pure ncurses
initialization which is not that interesting. Code for this post can be found here: : https://github.com/ldfallas/jcurtris .
1 comment:
Hi! I'm sorry to be commenting off-topic, but a quick search didn't show any other way of contacting you. I'm not a bot or anything! I'm just happy to find someone who apparently shares my hobby (language exploration)! I have no idea how I could have missed you for all these years (I seriously started looking at "other languages" in 2009, two years after yourself), but I'm so glad to have found you.
My blog is over at https://klibert.pl where I write about my experiences. I have posts about J and some other languages I liked. For example, you only wrote about Scheme in the context of Haskell (from a cursory glance) and only used "real" Scheme (I presume) when explaining call/cc. I invested quite a lot of time in Racket (which was a Scheme), and my latest post is about modifying a reader to add string interpolation syntax. I'd be very happy to hear your opinion on some of my posts if you find any interesting enough to read.
Next post, which I'm currently writing, is about adding a destructuring bind (actually, simple list unpacking for now) to an Io language. I'd be very happy if you could read it before publication and share your comments with me.
I'm generally available by email via klibert.piotr user in the gmail.com domain, happy to chat anytime! :)
Post a Comment