Skip to content

Instantly share code, notes, and snippets.

@courthead
Created September 1, 2019 21:48
Show Gist options
  • Save courthead/776f3f88c85b14d4c888ffe3d081aaef to your computer and use it in GitHub Desktop.
Save courthead/776f3f88c85b14d4c888ffe3d081aaef to your computer and use it in GitHub Desktop.
class GameTreeNode {
constructor(obj = {}) {
this.parentNode = obj.parentNode || null;
this.upNode = null;
this.rightNode = null;
this.downNode = null;
this.leftNode = null;
this.minScore = obj.parentNode ? obj.parentNode.minScore + 1 : 0;
this.score = null;
this.dir = obj.dir || null;
}
getNextNode() {
if (!this.leftNode || !this.leftNode.score) {
if (!this.leftNode) {
this.leftNode = new GameTreeNode({ parentNode: this, dir: 'l' });
}
return this.leftNode;
}
if (!this.upNode || !this.upNode.score) {
if (!this.upNode) {
this.upNode = new GameTreeNode({ parentNode: this, dir: 'u' });
}
return this.upNode;
}
if (!this.rightNode || !this.rightNode.score) {
if (!this.rightNode) {
this.rightNode = new GameTreeNode({ parentNode: this, dir: 'r' });
}
return this.rightNode;
}
if (!this.downNode || !this.downNode.score) {
if (!this.downNode) {
this.downNode = new GameTreeNode({ parentNode: this, dir: 'd' });
}
return this.downNode;
}
return this.parentNode;
}
getMoveList() {
let str = this.dir;
let node = this;
while (node.parentNode) {
if (node.parentNode.dir) {
str = `${node.parentNode.dir}${str}`;
}
node = node.parentNode;
}
return str;
}
}
class Player {
constructor() {
this.nodeExamining = null;
this.numNodesSearched = 0;
}
searchNextNode() {
this.playNodeMoveOnGame(this.nodeExamining);
if (!window.dead) {
this.nodeExamining = this.nodeExamining.getNextNode();
this.searchNextNode();
}
}
playNodeMoveOnGame(node) {
if (node.dir) {
this.dispatchMove(node.dir);
if (window.dead) {
node.score = node.minScore;
if (!this.bestNode || node.score > this.bestNode.score) {
this.bestNode = node;
console.log(`*** ${node.score}\t - ${node.getMoveList()}`); // eslint-disable-line
}
this.numNodesSearched++;
setTimeout(() => this.restartPlaying(), 0);
}
}
}
dispatchMove(dir) {
switch (dir) {
case 'u':
window.dispatchEvent(new KeyboardEvent('keyup', { keyCode: 38 }));
break;
case 'r':
window.dispatchEvent(new KeyboardEvent('keyup', { keyCode: 39 }));
break;
case 'd':
window.dispatchEvent(new KeyboardEvent('keyup', { keyCode: 40 }));
break;
case 'l':
window.dispatchEvent(new KeyboardEvent('keyup', { keyCode: 37 }));
break;
}
}
restartPlaying() {
this.resetNodeExamining();
if (window.ogMap) {
window.MAP = JSON.parse(JSON.stringify(window.ogMap));
window.dead = false;
window.myRPG = new RPG(document.getElementById('game').getContext('2d'), window.MAP, document.getElementById('score')); // eslint-disable-line
this.searchNextNode();
} else {
window.ogMap = JSON.parse(JSON.stringify(window.MAP));
this.createCustomRpg();
document.querySelector('body').innerHTML = `<canvas id="game" width="32" height="32" style="height: 89vh;image-rendering: pixelated;image-rendering: crisp-edges;">
Sorry, this game doesn't work on your browser. Please update it.
</canvas><span id="score" style="font-size: 10em;position: relative;top: -1.5em;">0</span>`;
this.restartPlaying();
}
}
resetNodeExamining() {
if (this.nodeExamining) {
while (this.nodeExamining.parentNode) {
this.nodeExamining = this.nodeExamining.parentNode;
}
} else {
this.nodeExamining = new GameTreeNode();
}
}
createCustomRpg() {
window.RPG = function (ctx, map, score) {
var _enemyLocations = [];
var _health = 1;
var over = false;
var _enemyTick = function (perferAxis) {
switch (_turnCount % 12) {
case 0:
_enemyLocations.push({x: 0, y: 0});
break;
case 3:
_enemyLocations.push({x: 0, y: 31});
break;
case 6:
_enemyLocations.push({x: 31, y: 0});
break;
case 9:
_enemyLocations.push({x: 31, y: 31});
break;
}
if (!perferAxis) perferAxis = "y";
_enemyLocations.forEach(function (enemy, index) {
var xDistance = enemy.x - _player[_currentPlayer].X;
var yDistance = enemy.y - _player[_currentPlayer].Y;
if (xDistance > 0.5) xDistance = -1;
else if (xDistance < -0.5) xDistance = 1;
else xDistance = 0;
if (yDistance > 0.5) yDistance = -1;
else if (yDistance < -0.5) yDistance = 1;
else yDistance = 0;
if ((xDistance !== 0) && (yDistance !== 0)) {
if ((_turnCount % 2) === 0) {
xDistance = 0;
} else {
yDistance = 0;
}
}
var newCoords = _putInBounds(enemy.x + xDistance, enemy.y + yDistance);
xDistance = newCoords.x;
yDistance = newCoords.y;
var conflict = false;
enemy.current = true;
for (var enemyName in _enemyLocations) {
// Ignore ourself
if (_enemyLocations[enemyName].current) continue;
if ((_enemyLocations[enemyName].x === xDistance) && (_enemyLocations[enemyName].y === yDistance)) {
conflict = true;
break;
}
}
enemy.current = false;
if (!conflict) {
enemy.x = xDistance;
enemy.y = yDistance;
}
if ((enemy.x === _player[1].X) && (enemy.y === _player[1].Y)) {
_health--;
dead = true;
if (onDeath === noop) {
over = true;
} else {
onDeath();
}
}
_enemyLocations[index] = enemy;
});
};
var _putInBounds = function (x, y) {
if (x > 31) {
x = 31;
}
if (y > 31) {
y = 31;
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
return {x: x, y: y};
};
var _player = {};
_player[1] = {
X: 16,
Y: 16
};
_player[2] = {
X: 24,
Y: 16
};
var _turnCount = 0;
var _currentPlayer = 1;
this.parseKeyPress = function (e) {
if (over) return;
var perferAxis = "y";
switch (e.keyCode) {
case 40: // Down arrow
_player[_currentPlayer].Y++;
break;
case 38: // Up arrow
_player[_currentPlayer].Y--;
break;
case 39: // Right arrow
perferAxis = "x";
_player[_currentPlayer].X++;
break;
case 37: // Left arrow
perferAxis = "x";
_player[_currentPlayer].X--;
break;
default:
return;
}
_turnCount++;
var newCoords = _putInBounds(_player[_currentPlayer].X, _player[_currentPlayer].Y);
_player[_currentPlayer].X = newCoords.x;
_player[_currentPlayer].Y = newCoords.y;
_enemyTick(perferAxis);
};
};
}
}
p = new Player()
p.restartPlaying();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment