From 77a790298437a5124e29fb829aceb1e3dc775161 Mon Sep 17 00:00:00 2001 From: Stasinos Konstantopoulos Date: Mon, 13 Nov 2017 11:37:36 +0200 Subject: [PATCH 1/5] Added ability to drop to bottom --- index.html | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index 37d4af0..13772a9 100644 --- a/index.html +++ b/index.html @@ -68,8 +68,10 @@ // 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 }, + // drop all the way to BOTTOM is an action, but MAX=3 to avoid reaching + // it by rotation + DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, BOTTOM:4, MIN: 0, MAX: 3 }, stats = new Stats(), canvas = get('canvas'), ctx = canvas.getContext('2d'), @@ -216,11 +218,17 @@ 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; + 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; } } else if (ev.keyCode == KEY.SPACE) { @@ -277,10 +285,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; } } @@ -324,6 +333,19 @@ } } + 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() { eachblock(current.type, current.x, current.y, current.dir, function(x, y) { setBlock(x, y, current.type); From efb590a2cc91a7230e80c557f5fb6ab2928ac61d Mon Sep 17 00:00:00 2001 From: Stasinos Konstantopoulos Date: Mon, 13 Nov 2017 23:12:17 +0200 Subject: [PATCH 2/5] Randomly turn any player action into drop-to-bottom --- README.md | 27 +++++++++------------------ index.html | 23 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 9b2720e..ebd67f6 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,15 @@ -Javascript Tetris -================= +Frustrating Tetris +================== -An HTML5 Tetris Game +An HTML5 Frustrating Tetris Game - * [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) +Forked from https://github.com/jakesgordon/javascript-tetris ->> _*SUPPORTED BROWSERS*: Chrome, Firefox, Safari, Opera and IE9+_ - -FUTURE -====== - - * menu - * animation and fx - * levels - * high scores - * touch support - * music and sound fx +Added feature: 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. License @@ -25,4 +17,3 @@ License [MIT](http://en.wikipedia.org/wiki/MIT_License) license. - diff --git a/index.html b/index.html index 13772a9..af0323d 100644 --- a/index.html +++ b/index.html @@ -32,6 +32,7 @@

score 00000

rows 0

+ Sorry, this example cannot be run because your browser does not support the <canvas> element @@ -87,6 +88,8 @@ //------------------------------------------------------------------------- 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 @@ -217,7 +220,12 @@ function keydown(ev) { var handled = false; if (playing) { - switch(ev.keyCode) { + // use probability to screw player by dropping to the + // bottom regardless of key pressed by player + if( Math.random() < screwPlayer ) { + actions.push(DIR.BOTTOM); handled = true; + } + else 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; @@ -265,6 +273,7 @@ clearActions(); clearBlocks(); clearRows(); + nEMPTY = ny, clearScore(); setCurrentPiece(next); setNextPiece(); @@ -274,7 +283,7 @@ if (playing) { if (vscore < score) setVisualScore(vscore + 1); - handle(actions.shift()); + handle( actions.shift() ); dt = dt + idt; if (dt > step) { dt = dt - step; @@ -409,9 +418,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 / nEMPTY + //document.getElementById("debugfield").innerHTML = nEMPTY.toString() + " : " + screwPlayer.toString(); } } ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary From 5b8379859e42446a74112f8862c44d80aa94e250 Mon Sep 17 00:00:00 2001 From: Stasinos Konstantopoulos Date: Mon, 13 Nov 2017 23:39:43 +0200 Subject: [PATCH 3/5] Randomly ignore keystrokes --- LICENSE | 1 + README.md | 28 +++++++++++++++++++---- index.html | 67 +++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 70 insertions(+), 26 deletions(-) diff --git a/LICENSE b/LICENSE index 7d4b906..d3dd208 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jake Gordon and contributors +Copyright (c) 2017, 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 diff --git a/README.md b/README.md index ebd67f6..8679c98 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,30 @@ Frustrating Tetris An HTML5 Frustrating Tetris Game Forked from https://github.com/jakesgordon/javascript-tetris +into https://github.com/stasinos/javascript-tetris +for pull requests of fixes and new features for the normal game. + +Forked again into https://bitbucket.org/stasinos/frustretris +(private repo) for developing the "frustrating tetris" features. + + +Added features: + +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. + +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. + +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. -Added feature: 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. License diff --git a/index.html b/index.html index af0323d..43cf6e7 100644 --- a/index.html +++ b/index.html @@ -70,9 +70,10 @@ //------------------------------------------------------------------------- var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, SHIFT: 16 }, - // drop all the way to BOTTOM is an action, but MAX=3 to avoid reaching - // it by rotation - DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, BOTTOM:4, MIN: 0, MAX: 3 }, + // 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'), @@ -81,7 +82,8 @@ speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds) 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) @@ -220,24 +222,47 @@ function keydown(ev) { var handled = false; if (playing) { - // use probability to screw player by dropping to the - // bottom regardless of key pressed by player - if( Math.random() < screwPlayer ) { - actions.push(DIR.BOTTOM); handled = true; + if( (nEMPTY<=frStart) && (Math.random()0 ; --n ) { + actions.push( DIR.IGNORE ); + } + } + if( ev.keyCode == KEY.ESC ) { + lose(); handled = true; } - else 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; + else if( (nEMPTY<=frStart) && (Math.random()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; + } + } + } } else if (ev.keyCode == KEY.SPACE) { play(); @@ -427,7 +452,7 @@ } if( empty_line ) { nEMPTY = y - screwPlayer = 1.0 / nEMPTY / nEMPTY + screwPlayer = 1.0 / nEMPTY //document.getElementById("debugfield").innerHTML = nEMPTY.toString() + " : " + screwPlayer.toString(); } } From a9c4aaf4b76387b5b8e3a71ff6bae5b4b4394172 Mon Sep 17 00:00:00 2001 From: Stasinos Konstantopoulos Date: Mon, 20 Nov 2017 12:29:37 +0200 Subject: [PATCH 4/5] Documented parameters of frustration --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 8679c98..ff8dc8c 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,32 @@ 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 ======= From 33d44d1bb12acdde493ad1e5f3d37605ea7bdf46 Mon Sep 17 00:00:00 2001 From: Stasinos Konstantopoulos Date: Wed, 17 Oct 2018 11:38:46 +0300 Subject: [PATCH 5/5] Pause button --- LICENSE | 2 +- index.html | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 7d4b906..6d2b72f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jake Gordon and contributors +Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Jake Gordon and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/index.html b/index.html index 13772a9..8405d8d 100644 --- a/index.html +++ b/index.html @@ -68,7 +68,7 @@ // game constants //------------------------------------------------------------------------- - var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, SHIFT: 16 }, + 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, but MAX=3 to avoid reaching // it by rotation DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, BOTTOM:4, MIN: 0, MAX: 3 }, @@ -78,6 +78,7 @@ 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) @@ -229,6 +230,15 @@ } 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) { @@ -320,6 +330,9 @@ } function drop() { + if( paused == 0 ) { + console.log( "0" ); + if (!move(DIR.DOWN)) { addScore(10); dropPiece(); @@ -331,6 +344,7 @@ lose(); } } + } // paused } function dropMany() {