Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full drop and pause button #27

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jake Gordon and contributors
Copyright (c) 2017, 2018 Stasinos Konstantopoulos

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
60 changes: 44 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
Javascript Tetris
=================
Frustrating Tetris
==================

An HTML5 Tetris Game
An HTML5 Frustrating Tetris Game
forked from https://github.com/jakesgordon/javascript-tetris

* [play the game](http://codeincomplete.com/projects/tetris/)
* read a [blog article](http://codeincomplete.com/posts/2011/10/10/javascript_tetris/)
* view the [source](https://github.com/jakesgordon/javascript-tetris)
Added features:

>> _*SUPPORTED BROWSERS*: Chrome, Firefox, Safari, Opera and IE9+_
1. There is a probability that the current brick is dropped regardless
of what the user action was. This probability increases as the pit
gets filled up, so that the game is more likely to ignore your action
when the game is at a critical stage.

FUTURE
======
2. There is a probability that a random number (1--7) of IGNORE
actions are added to the action queue, eating up as many keystrokes
without rotating or moving the falling brick.

* menu
* animation and fx
* levels
* high scores
* touch support
* music and sound fx
Both features only kick in once there are 8 or fewer empty rows at the
top ofg the pit, and the probability that they appear increases as
fewer rows are left empty. This would normally result in minor hints
that there is something wrong as the game advances, with heightened
frequency when players enter a critical phase with little space left.


Frustration Parameters
======================

- Player frustration is only active when so many or fewer empty rows:
(l.86) frStart = 8

- The probability to apply frustration (if active, as per above) is:
(l. 455) screwPlayer = 1.0 / nEMPTY
where nEMPTY is the number of empty rows
If this kicks in, they two types are equally probable.

In order to make one more likely, we need to :
* Have different "screwPlayer" variables initialized in l. 94
* Calculate differently in l. 455
* Use different variable to activate each type of frustration
in l. 225 (ignore) and l. 238 (drop to bottom)

- If "dead key" is chosen, between 1 and 8 "ignores" are pushed into
the action queue:
(l. 229) n = Math.random(1, 8)
Each ignore actions needs one keystroke to be
shifted out, eating up the actual action.

- If "drop to bottom" is chosen, the current brick will fall all the way
to the bottom, regardless of what action was choses. No parameters here.


License
=======

[MIT](http://en.wikipedia.org/wiki/MIT_License) license.


109 changes: 94 additions & 15 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<p><canvas id="upcoming"></canvas></p>
<p>score <span id="score">00000</span></p>
<p>rows <span id="rows">0</span></p>
<!--p>empty lines <span id="debugfield">20</span></p-->
</div>
<canvas id="canvas">
Sorry, this example cannot be run because your browser does not support the &lt;canvas&gt; element
Expand Down Expand Up @@ -68,23 +69,30 @@
// game constants
//-------------------------------------------------------------------------

var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 },
DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 },
var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, SHIFT: 16, P: 80 },
// drop all the way to BOTTOM is an action
// IGNORE subsequent actions is also an action
// BUT: MAX=3 to avoid reaching these two pseudo-actions by rotation
DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, BOTTOM:4, IGNORE:5, MIN: 0, MAX: 3 },
stats = new Stats(),
canvas = get('canvas'),
ctx = canvas.getContext('2d'),
ucanvas = get('upcoming'),
uctx = ucanvas.getContext('2d'),
speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds)
paused = 0,
nx = 10, // width of tetris court (in blocks)
ny = 20, // height of tetris court (in blocks)
nu = 5; // width/height of upcoming preview (in blocks)
nu = 5, // width/height of upcoming preview (in blocks)
frStart = 8; // player frustration active when 8 or fewer empty rows

//-------------------------------------------------------------------------
// game variables (initialized during reset)
//-------------------------------------------------------------------------

var dx, dy, // pixel size of a single tetris block
nEMPTY = ny, // court lines that are totaly empty
screwPlayer = 0.0, // current probability to screw player
blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece'
actions, // queue of user actions (inputs)
playing, // true|false - game is in progress
Expand Down Expand Up @@ -215,13 +223,57 @@
function keydown(ev) {
var handled = false;
if (playing) {
switch(ev.keyCode) {
case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break;
case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break;
case KEY.UP: actions.push(DIR.UP); handled = true; break;
case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break;
case KEY.ESC: lose(); handled = true; break;
if( (nEMPTY<=frStart) && (Math.random()<screwPlayer) ) {
// screw player by inserting IGNORE actions.
// This is just inserted here, to be
// acted upon later when handling key events
n = Math.random( 1, 8 )
//document.getElementById("debugfield").innerHTML = "IGNORE " + n.toString();
for( ; n>0 ; --n ) {
actions.push( DIR.IGNORE );
}
}
if( ev.keyCode == KEY.ESC ) {
lose(); handled = true;
}
else if( (nEMPTY<=frStart) && (Math.random()<screwPlayer) ) {
// screw player by dropping to the
// bottom regardless of key pressed by player
actions.push( DIR.BOTTOM );
handled = true;
}
else {
if( (actions.length>0) && (actions[0]==DIR.IGNORE) ) {
//document.getElementById("debugfield").innerHTML = "DIR.IGNORE";
actions.shift();
handled = true;
}
else {
//document.getElementById("debugfield").innerHTML = "NOT DIR.IGNORE";
switch(ev.keyCode) {
case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break;
case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break;
case KEY.UP: actions.push(DIR.UP); handled = true; break;
case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break;
case KEY.SHIFT:
// special care to only push once, even if it stays pressed
if( actions[0] != DIR.BOTTOM ) {
actions.push(DIR.BOTTOM); handled = true;
}
break;
case KEY.ESC: lose(); handled = true; break;
case KEY.P:
if( paused == 1 ) {
paused = 0;
}
else {
paused = 1;
}
handled = true;
break;
}
}
}
}
else if (ev.keyCode == KEY.SPACE) {
play();
Expand Down Expand Up @@ -257,6 +309,7 @@
clearActions();
clearBlocks();
clearRows();
nEMPTY = ny,
clearScore();
setCurrentPiece(next);
setNextPiece();
Expand All @@ -266,7 +319,7 @@
if (playing) {
if (vscore < score)
setVisualScore(vscore + 1);
handle(actions.shift());
handle( actions.shift() );
dt = dt + idt;
if (dt > step) {
dt = dt - step;
Expand All @@ -277,10 +330,11 @@

function handle(action) {
switch(action) {
case DIR.LEFT: move(DIR.LEFT); break;
case DIR.RIGHT: move(DIR.RIGHT); break;
case DIR.UP: rotate(); break;
case DIR.DOWN: drop(); break;
case DIR.LEFT: move(DIR.LEFT); break;
case DIR.RIGHT: move(DIR.RIGHT); break;
case DIR.UP: rotate(); break;
case DIR.DOWN: drop(); break;
case DIR.BOTTOM: dropMany(); break;
}
}

Expand Down Expand Up @@ -311,6 +365,9 @@
}

function drop() {
if( paused == 0 ) {
console.log( "0" );

if (!move(DIR.DOWN)) {
addScore(10);
dropPiece();
Expand All @@ -322,6 +379,20 @@
lose();
}
}
} // paused
}

function dropMany() {
while( move(DIR.DOWN) ) { }
addScore(10);
dropPiece();
removeLines();
setCurrentPiece(next);
setNextPiece(randomPiece());
clearActions();
if (occupied(current.type, current.x, current.y, current.dir)) {
lose();
}
}

function dropPiece() {
Expand Down Expand Up @@ -387,9 +458,17 @@
drawPiece(ctx, current.type, current.x, current.y, current.dir);
var x, y, block;
for(y = 0 ; y < ny ; y++) {
empty_line = true
for (x = 0 ; x < nx ; x++) {
if (block = getBlock(x,y))
if (block = getBlock(x,y)) {
drawBlock(ctx, x, y, block.color);
empty_line = false
}
}
if( empty_line ) {
nEMPTY = y
screwPlayer = 1.0 / nEMPTY
//document.getElementById("debugfield").innerHTML = nEMPTY.toString() + " : " + screwPlayer.toString();
}
}
ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary
Expand Down