-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
200 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,30 @@ | ||
# REPLTetris.jl | ||
This started as an exercise to learn terminal rendering and key-input. | ||
Rendering is greatily improved through only rendering diffs to the last screen. | ||
This started as an exercise to learn terminal rendering and key-input. Tile-colors, scoring, button-mapping, speed and levels are in accordance to the [Tetris Guideline][1]. T-spins and wall kicks are not yet available, but will be added soon. | ||
|
||
This is a screenshot playing in the VSCode REPL: | ||
|
||
![Julia REPL Screenshot of a lost game of REPLTetris](resources/Screenshot.PNG) | ||
|
||
# Installation & Usage | ||
The package is not yet registered in Meta-Data. You will need to clone it from this site: | ||
The package is registered in Meta-Data. Simply install it using `Pkg.add`: | ||
```julia | ||
julia> Pkg.add("REPLTetris") | ||
``` | ||
|
||
After using the Package, you can start a game with `tetris()`: | ||
|
||
```julia-REPL | ||
Julia> Pkg.clone("https://github.com/ChristianKurz/REPLTetris.jl") | ||
Julia> using REPLTetris | ||
Julia> tetris() | ||
```julia | ||
julia> using REPLTetris | ||
julia> tetris() | ||
``` | ||
|
||
Game is controlled via arrow-keys and space: | ||
The game is controlled via arrow-keys, X, Z and space: | ||
- `Up`: Rotate Clockwise | ||
- `Left` / `Right` / `Down`: Move Current Tile | ||
- `Space`: Drop Current Tile to Bottom | ||
- `X`: Rotate Clockwise | ||
- `Z`: Rotate Counter Clockwise | ||
- `C`: Swap current tile with tile on hold | ||
- `CTRL-C`: Abort Game | ||
|
||
[1]: http://tetris.wikia.com/wiki/Tetris_Guideline |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
julia 0.6 | ||
Crayons | ||
Compat v0.65.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,45 @@ | ||
function checkcollision(b::Board, newtile::Tile) | ||
shape = data(newtile) | ||
x,y = newtile.location | ||
dy, dx = size(shape) .-1 | ||
x+dx <= 10 && x >= 1 && y+dy <= 20 && !any((b[newtile] .!= 0 ) .& (shape .!= 0)) && return true | ||
function checkcollision(b::Board) | ||
x,y = b.location | ||
dy, dx = size(rotatedtile(b)) .-1 | ||
x+dx <= 10 && x >= 1 && y+dy <= 20 && !any((b[] .!= 0 ) .& (rotatedtile(b) .!= 0)) | ||
end | ||
|
||
function affine!(board::Board, tile::Tile, rotation=0, translation=[0,0]) | ||
oldboard = copy(board) | ||
newtile = copy(tile) | ||
newtile.orientation -= rotation | ||
newtile.location += translation | ||
function affine!(b::Board, rotation=0, translation=[0,0]) | ||
oldboard = copy(b) | ||
|
||
board[tile] -= data(tile) | ||
if checkcollision(board,newtile) | ||
tile.orientation -= rotation | ||
tile.location[:] += translation | ||
board[tile] += data(tile) | ||
update_board!(oldboard, board) | ||
b[] -= rotatedtile(b) | ||
b.orientation -= rotation | ||
b.location += translation | ||
if checkcollision(b) | ||
b[] += rotatedtile(b) | ||
update_board!(oldboard, b) | ||
return true | ||
end | ||
board[tile] += data(tile) | ||
b.orientation += rotation | ||
b.location -= translation | ||
b[] += rotatedtile(b) | ||
return false | ||
end | ||
|
||
rot_right!(b::Board, tile::Tile) = affine!(b, tile, -1, [ 0, 0]) | ||
rot_left!(b::Board, tile::Tile) = affine!(b, tile, 1, [ 0, 0]) | ||
move_right!(b::Board, tile::Tile) = affine!(b, tile, 0, [ 1, 0]) | ||
move_left!(b::Board, tile::Tile) = affine!(b, tile, 0, [-1, 0]) | ||
drop!(b::Board, tile::Tile) = affine!(b, tile, 0, [ 0, 1]) | ||
rot_right!(b::Board) = affine!(b, -1, [ 0, 0]) | ||
rot_left!(b::Board) = affine!(b, 1, [ 0, 0]) | ||
move_right!(b::Board) = affine!(b, 0, [ 1, 0]) | ||
move_left!(b::Board) = affine!(b, 0, [-1, 0]) | ||
drop!(b::Board) = affine!(b, 0, [ 0, 1]) | ||
fast_drop!(b::Board) = (while drop!(b) end; return false) | ||
|
||
function fast_drop!(b::Board, tile::Tile) | ||
while drop!(b, tile) end | ||
return false | ||
end | ||
function hold!(b::Board) | ||
if b.allowhold | ||
oldboard = copy(b) | ||
|
||
function add_tile!(board::Board, tile::Tile) | ||
if all(board[tile] .== 0) | ||
oldboard = copy(board) | ||
board[tile] += data(tile) | ||
update_board!(oldboard, board) | ||
return true | ||
b[] -= rotatedtile(b) | ||
b.tile, b.holdtile = b.holdtile, b.tile | ||
b.orientation = 0 | ||
b.location = start_location(b.tile) | ||
b[] += rotatedtile(b) | ||
print_hold(b) | ||
b.allowhold = false | ||
|
||
update_board!(oldboard, b) | ||
end | ||
false | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,72 @@ | ||
import Base: getindex, setindex!, copy | ||
|
||
mutable struct Board | ||
data::Array{Int} | ||
score::Int | ||
level::Int | ||
lines_to_goal::Int | ||
tile::Tile | ||
location::Vector{Int} | ||
orientation::Int | ||
nexttiles::Vector{Tile} | ||
holdtile::Tile | ||
allowhold::Bool | ||
end | ||
Board() = Board(zeros(Int, 20, 10), 0, 1, 5) | ||
copy(b::Board) = Board(copy(b.data), b.score, b.level, b.lines_to_goal) | ||
Board(i=0) = Board(ones(Int, 20, 10)*i, 0, 1+i, 5, | ||
rand(Tiles)(), [4,1], 0, | ||
[rand(Tiles)() for i in 1:3], rand(Tiles)(), true) | ||
|
||
copy(b::Board) = Board(copy(b.data), b.score, b.level, b.lines_to_goal, | ||
b.tile, b.location, b.orientation, | ||
copy(b.nexttiles), b.holdtile, b.allowhold) | ||
|
||
import Base: getindex, setindex! | ||
function getindex(b::Board, tile::Tile) | ||
dy,dx = size(data(tile)) .-1 | ||
x,y = tile.location | ||
function getindex(b::Board) | ||
dy,dx = size(rotatedtile(b)) .-1 | ||
x,y = b.location | ||
return b.data[y:y+dy, x:x+dx] | ||
end | ||
function setindex!(b::Board, s::AbstractArray, tile::Tile) | ||
dy,dx = size(data(tile)) .-1 | ||
x,y = tile.location | ||
|
||
function setindex!(b::Board, s::AbstractArray) | ||
dy,dx = size(rotatedtile(b)) .-1 | ||
x,y = b.location | ||
b.data[y:y+dy, x:x+dx] = s | ||
end | ||
|
||
function delete_lines!(board::Board) | ||
oldboard = copy(board) | ||
nr_lines = 0 | ||
for i in 1:20 | ||
if all(board.data[i, :] .!= 0) | ||
board.data[2:i, :] = board.data[1:i-1, :] | ||
board.data[1,:] .= 0 | ||
nr_lines += 1 | ||
end | ||
end | ||
board.lines_to_goal -= nr_lines | ||
board.score += [0 1 3 5 8][nr_lines+1] * board.level * 100 | ||
if board.lines_to_goal ≤ 0 | ||
board.level += 1 | ||
board.lines_to_goal += board.level*5 | ||
end | ||
update_board!(oldboard, board) | ||
end | ||
rotatedtile(b::Board) = rotr90(data(b.tile), b.orientation) | ||
|
||
function blocks(i) | ||
buf = IOBuffer() | ||
block = " ◼ " | ||
if i==0 | ||
block =" ◻ " | ||
i += 8 | ||
end | ||
print(buf, Crayon(foreground = i), block ) | ||
return String(take!(buf)) | ||
function nexttile!(b::Board) | ||
push!(b.nexttiles, rand(Tiles)()) | ||
b.tile = popfirst!(b.nexttiles) | ||
end | ||
|
||
@compat function update_board!(b1::Board, b2::Board) | ||
buf = IOBuffer() | ||
for i in findall(b1.data .⊻ b2.data .!= 0) | ||
y,x = ind2sub((20,10), i) | ||
put(buf, [(3*x)-2,y], blocks(b2.data[y,x])) | ||
function add_tile!(b::Board) | ||
nexttile!(b) | ||
b.location = start_location(b.tile) | ||
b.orientation = 0 | ||
if all(b[] .== 0) | ||
oldboard = copy(b) | ||
b[] += data(b.tile) | ||
update_board!(oldboard, b) | ||
return true | ||
end | ||
if (b1.level != b2.level) || (b1.score != b2.score) | ||
cursor_move_abs(buf, [0,21]) | ||
print(buf, Crayon(foreground = 7), " Level: $(b2.level)\tScore:$(b2.score)") | ||
end | ||
print(String(take!(buf))) | ||
false | ||
end | ||
|
||
function print_tile_preview(tile::Tile) | ||
buf = IOBuffer() | ||
print(buf, Crayon(foreground = 7)) | ||
put(buf, [35, 9], string("Next Tile:")) | ||
for i in 1:4 | ||
put(buf, [35, 10+i], string(" "^15)) | ||
function delete_lines!(b::Board) | ||
oldboard = copy(b) | ||
nr_lines = 0 | ||
for i in 1:20 | ||
if all(b.data[i, :] .!= 0) | ||
b.data[2:i, :] = b.data[1:i-1, :] | ||
b.data[1,:] .= 0 | ||
nr_lines += 1 | ||
end | ||
end | ||
dt = data(tile)' | ||
_, dy = size(dt) | ||
for i in 1:dy | ||
put(buf, [35, 10+i], string(blocks.(dt[:, i])...)) | ||
b.lines_to_goal -= nr_lines | ||
b.score += [0 1 3 5 8][nr_lines+1] * b.level * 100 | ||
if b.lines_to_goal ≤ 0 | ||
b.level += 1 | ||
b.lines_to_goal += b.level*5 | ||
end | ||
print(String(take!(buf))) | ||
end | ||
update_board!(oldboard, b) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
function block(i) | ||
color = [:dark_gray, :red, :light_red, :yellow, :green, :cyan, :blue, :magenta][i+1] | ||
return string(Crayon(foreground = color), i==0 ? " □ ": " ■ ") | ||
end | ||
|
||
@compat function update_board!(old::Board, b::Board) | ||
buf = IOBuffer() | ||
for i in findall(old.data .⊻ b.data .!= 0) | ||
if VERSION < v"0.7.0-DEV.3025" | ||
y,x = ind2sub((20,10), i) | ||
else | ||
y,x = Tuple(i) | ||
end | ||
put(buf, [(3*x)-2,y], string(block.(b.data[y,x])...)) | ||
end | ||
if (old.level != b.level) || (old.score != b.score) | ||
put(buf, [3,21], :dark_gray, "Level: $(b.level)\tScore:$(b.score)") | ||
end | ||
print(String(take!(buf))) | ||
end | ||
|
||
update_board!(b::Board) = update_board!(Board(2), b) | ||
|
||
|
||
function print_preview(b::Board) | ||
buf = IOBuffer() | ||
put(buf, [33, 2], :dark_gray, string("Next Tiles:")) | ||
for (nr, tile) in enumerate(b.nexttiles) | ||
_print_tile(buf, tile, 2+(nr-1)*4) | ||
end | ||
print(String(take!(buf))) | ||
end | ||
|
||
function print_hold(b::Board) | ||
buf = IOBuffer() | ||
put(buf, [33, 16], :dark_gray, string("Hold Tile:")) | ||
_print_tile(buf, b.holdtile, 16) | ||
print(String(take!(buf))) | ||
end | ||
|
||
function _print_tile(buf, tile, x) | ||
dt = data(tile)' | ||
_, dy = size(dt) | ||
for i in 1:2 | ||
put(buf, [35, x+i+1], :dark_gray, string(" □ "^4)) | ||
i <= dy && put(buf, [35, x+i+1], string(block.(dt[:, i])...)) | ||
end | ||
end |
Oops, something went wrong.