Skip to content

Commit

Permalink
✨ junk lines
Browse files Browse the repository at this point in the history
  • Loading branch information
ctcpip committed May 31, 2024
1 parent b730f3e commit c5552b1
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 36 deletions.
4 changes: 0 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
{
"eslint.validate": [
"html",
"javascript"
],
"search.exclude": {
"**/package-lock.json": true
},
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
}
Expand Down
57 changes: 49 additions & 8 deletions board.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const { shapes } = require('./shapes');
const Shape = require('./shape');
const directions = require('./directions');
const Rando = require('./rando');

const BOARD_WIDTH = 20;

// TODO: write game code above board in amber color

module.exports = class Board {
currentShape;
Expand All @@ -24,6 +29,7 @@ module.exports = class Board {
this.game = game;
this.algorithm = game.algorithm(seed);
this.playerID = playerID;
this.rando = new Rando(seed);

if (this.isMainBoard) {
this.nextBox = {};
Expand Down Expand Up @@ -199,7 +205,7 @@ module.exports = class Board {

const linePoints = this.occupiedPoints.filter(op => op[1] === y);

if (linePoints.length === 20) {
if (linePoints.length === BOARD_WIDTH) {
// line is full; clear it
erasePoints.push(...linePoints);

Expand Down Expand Up @@ -315,7 +321,7 @@ module.exports = class Board {
}

holdShape() {
if (this.currentShape.held || this.game.isPaused) {
if (this.currentShape?.held || this.game.isPaused) {
// current shape cannot be held more than once
return;
}
Expand Down Expand Up @@ -445,13 +451,48 @@ module.exports = class Board {
return Math.min(...this.occupiedPoints.map(op => op[1]));
}

receiveJunk(junkLines) { // eslint-disable-line no-unused-vars
// move all occupied points up by junkLines
// clear junkLines points
receiveJunk(junkLines) {
const erasePoints = [];

this.currentShape.drawGhost(true);

// move lines up, point by point
for (const p of this.occupiedPoints) {
const sp = this.screen.get({ x: p[0], y: p[1] });

erasePoints.push([p[0], p[1]]); // pass values of, not the ref to p, because we modify the position on the next line

p[1] -= junkLines; // update the point location

this.screen.put({ x: p[0], y: p[1], attr: sp.attr }, sp.char); // draw the point in its new location
}

// depending on whether a board's border is odd or even, affects:
// 1. where we need to calculate for the junk hole
// 2. the characters used for drawing junk shapes
const startingXIsOdd = this.left % 2 === 0;

// make junk holes align, with x chosen randomly
const holeX = this.rando.getRandomOddOrEvenNumber(this.left, this.right, startingXIsOdd);

for (let y = this.bottom - junkLines; y < this.bottom; y++) {
for (let x = this.left + 1; x < this.right; x++) {
if (x !== holeX && x !== holeX + 1) {
const p = [x, y];
this.occupiedPoints.push(p);
this.drawShapePoint(p, x - (startingXIsOdd ? 1 : 0), false, 'grey');
}
}
}

for (const ep of erasePoints) {
if (!this.isPointOccupied(ep)) {
this.screen.d(...ep, ' '); // erase the point
}
}

// make junk holes align, with x chosen randomly, except the y above the top hole must be occupied
// add to occupied points
// draw junk lines
this.currentShape.drawGhost();
this.screen.render();
}

get isMainBoard() {
Expand Down
2 changes: 1 addition & 1 deletion client.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = class NetrisseClient {
}

disconnect() {
this.ws.close(4333, JSON.stringify({ playerID: this.playerID, gameID: this.gameID }));
this.ws.close(4333, JSON.stringify({ type: this.messageTypeEnum.QUIT, playerID: this.playerID, gameID: this.gameID }));
}

sendMessage(o = {}, type) {
Expand Down
46 changes: 28 additions & 18 deletions game.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,37 @@ module.exports = class Game {
}

sendJunk(junkLines) {
if (this.boards.length === 1) {
return;
}

let lowestBoard;
let lowestBoardY = 0;

// give junk to player with the lowest board pieces

// skip main board (index 0)
for (let i = 1; i < this.boards.length; i++) {
const b = this.boards[i];

const lowestY = b.getHighestOccupiedPoint();
let toBoard;

switch (this.boards.length) {
case 1:
return;
case 2:
// if only two players, then junk lines always go to the other player
toBoard = this.boards[1];
break;
default: {
let lowestBoardY = 0;

// give junk to player with the lowest board pieces

// skip main board (index 0)
for (let i = 1; i < this.boards.length; i++) {
const b = this.boards[i];

const lowestY = b.getHighestOccupiedPoint();

if (lowestY > lowestBoardY) {
lowestBoardY = lowestY;
toBoard = b;
}
}

if (lowestY > lowestBoardY) {
lowestBoardY = lowestY;
lowestBoard = b;
break;
}
}

this.client.sendMessage({ junkLines, toPlayerID: lowestBoard.playerID }, this.client.messageTypeEnum.JUNK);
this.client.sendMessage({ junkLines, toPlayerID: toBoard.playerID }, this.client.messageTypeEnum.JUNK);
toBoard.receiveJunk(junkLines);
}
};
13 changes: 8 additions & 5 deletions netrisse.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ const NetrisseClient = require('./client');
case client.messageTypeEnum.PAUSE:
game.pause(true, message.playerID, true);
break;
case client.messageTypeEnum.QUIT:
// do something
break;
case client.messageTypeEnum.SEED:
seedFromServer = message.seed;
break;
Expand Down Expand Up @@ -148,25 +151,25 @@ const NetrisseClient = require('./client');
case 'j':
case 'J':
case 'LEFT':
board.currentShape.move(directions.LEFT);
board.currentShape?.move(directions.LEFT);
break;
case 'k':
case 'K':
case 'UP':
board.currentShape.move(directions.ROTATE_LEFT);
board.currentShape?.move(directions.ROTATE_LEFT);
break;
case 'l':
case 'L':
case 'RIGHT':
board.currentShape.move(directions.RIGHT);
board.currentShape?.move(directions.RIGHT);
break;
case ' ':
board.currentShape.move(directions.DROP);
board.currentShape?.move(directions.DROP);
break;
case 'm':
case 'M':
case 'DOWN':
board.currentShape.move(directions.DOWN);
board.currentShape?.move(directions.DOWN);
break;
case 'h':
case 'H':
Expand Down
33 changes: 33 additions & 0 deletions rando.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,39 @@ module.exports = class Rando {
return Math.floor(this.rng.random() * max);
}

/** an odd or even number between `min` (inclusive) and `max` (inclusive) */
getRandomOddOrEvenNumber(min, max, wantOdd) {
if (min > max) {
[min, max] = [max, min];
}

let randomNumber = Math.floor(this.rng.random() * (max - min + 1)) + min;
const isEven = randomNumber % 2 === 0;

if (isEven) {
if (wantOdd) {
// if the number is even, add 1 to make it odd
randomNumber += 1;
// if adding 1 is out of range, subtract 2 instead
if (randomNumber > max) {
randomNumber -= 2;
}
}
}
else {
if (!wantOdd) {
// if the number is odd, add 1 to make it even
randomNumber += 1;
// if adding 1 is out of range, subtract 2 instead
if (randomNumber > max) {
randomNumber -= 2;
}
}
}

return randomNumber;
}

random() {
return this.rng.random();
}
Expand Down
27 changes: 27 additions & 0 deletions test/rando-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const MersenneTwister = require('mersenne-twister');
const Rando = require('../rando');
const assert = require('node:assert');

const seed = new MersenneTwister().random_int();
const rando = new Rando(seed);
const max = 33;

let foundNumbers = new Set();

while (foundNumbers.size <= max) {
const odd = rando.getRandomOddOrEvenNumber(0, max, true);
const even = rando.getRandomOddOrEvenNumber(0, max, false);
foundNumbers.add(odd);
foundNumbers.add(even);
}

assert.strictEqual(foundNumbers.size, max + 1);

foundNumbers = new Set();

while (foundNumbers.size <= max) {
const n = rando.getRandomNumber(34);
foundNumbers.add(n);
}

assert.strictEqual(foundNumbers.size, max + 1);

0 comments on commit c5552b1

Please sign in to comment.