Skip to content

Instantly share code, notes, and snippets.

@jonasgeiler
Last active March 21, 2021 04:30
Show Gist options
  • Save jonasgeiler/ed33f1352b42306b5ca450f09c90c0a5 to your computer and use it in GitHub Desktop.
Save jonasgeiler/ed33f1352b42306b5ca450f09c90c0a5 to your computer and use it in GitHub Desktop.
Solves the "Magic Tower" levels in the game "Fancade"
const fs = require('fs');
const LEVELS = JSON.parse(fs.readFileSync('./levels.json'));
let argv = process.argv.splice(2);
const FORCE_RECALC = argv.includes('-f') || argv.includes('--force');
if (FORCE_RECALC) {
argv = argv.filter(v => v !== '-f' && v !== '--force');
}
if (argv.length > 1 || argv.length === 0) {
console.log(`
USAGE
$ node dungeon-solver.js LEVEL
ARGUMENTS
LEVEL level to solve. For Magic Tower Lite it's 1-20, for Magic Tower it's the level's name like "prince"
OPTIONS
-f, --force force recalculating the solution and not using stored one
`);
process.exit(1);
}
const CURRENT_LEVEL = argv.pop();
const { floors: DUNGEON_MAP, player: PLAYER_INFO } = LEVELS[CURRENT_LEVEL];
const INITIAL_PLAYER = {
...PLAYER_INFO,
x: 5,
y: 9,
z: 0,
keys: { red: 0, green: 0, blue: 0, yellow: 0, orange: 0 },
};
// ========= //
function clone(obj) {
let copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || 'object' != typeof obj) return obj;
// Handle Array
if (obj instanceof Array) {
copy = [];
for (let i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (let attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error(`Unable to clone obj! Type "${typeof obj}" isn't supported.`);
}
function parseMap(floors) {
let map = [];
let z = 0;
for (let floor of floors) {
map[z] = [];
let y = 0;
for (let row of floor) {
map[z][y] = [];
const cols = row.split('');
let x = 0;
for (let col of cols) {
switch (col) {
// GENERAL
case '█':
map[z][y][x] = { type: 'wall' };
break;
case ' ': // SPACE
map[z][y][x] = { type: 'empty' };
break;
case 'E':
map[z][y][x] = { type: 'exit' };
break;
case 'U':
map[z][y][x] = { type: 'stairs', direction: 1 };
break;
case 'L':
map[z][y][x] = { type: 'stairs', direction: -1 };
break;
// ENDBOSSES
case 'P':
map[z][y][x] = { type: 'endboss', stats: { lives: 10, attack: 0, armor: 0 }, name: 'Prince' };
break;
// ENEMIES
case 'D':
map[z][y][x] = { type: 'enemy', stats: { lives: 180, attack: 20, armor: 5 }, name: 'Dinosaur' };
break;
case 'N':
map[z][y][x] = { type: 'enemy', stats: { lives: 100, attack: 22, armor: 2 }, name: 'Black Enemy' };
break;
case 'I':
map[z][y][x] = { type: 'enemy', stats: { lives: 65, attack: 38, armor: 14 }, name: 'Red Knight' };
break;
case 'M':
map[z][y][x] = { type: 'enemy', stats: { lives: 60, attack: 45, armor: 0 }, name: 'Redbeard Guy' };
break;
case 'Y':
map[z][y][x] = { type: 'enemy', stats: { lives: 60, attack: 18, armor: 1 }, name: 'Yellow Enemy' };
break;
case 'O':
map[z][y][x] = { type: 'enemy', stats: { lives: 50, attack: 10, armor: 5 }, name: 'Bandit' };
break;
case 'K':
map[z][y][x] = { type: 'enemy', stats: { lives: 45, attack: 25, armor: 10 }, name: 'Knight' };
break;
case 'W':
map[z][y][x] = { type: 'enemy', stats: { lives: 40, attack: 26, armor: 0 }, name: 'Wolf' };
break;
case 'G':
map[z][y][x] = { type: 'enemy', stats: { lives: 40, attack: 12, armor: 1 }, name: 'Green Enemy' };
break;
case 'S':
map[z][y][x] = { type: 'enemy', stats: { lives: 35, attack: 85, armor: 0 }, name: 'Skull' };
break;
case 'R':
map[z][y][x] = { type: 'enemy', stats: { lives: 24, attack: 11, armor: 0 }, name: 'Red Enemy' };
break;
case 'B':
map[z][y][x] = { type: 'enemy', stats: { lives: 15, attack: 10, armor: 0 }, name: 'Blue Enemy' };
break;
// ITEMS
case 'H':
map[z][y][x] = { type: 'item', add: { lives: 50, attack: 0, armor: 0 }, name: 'Medicine' };
break;
case 'A':
map[z][y][x] = { type: 'item', add: { lives: 0, attack: 0, armor: 1 }, name: 'Armor Bonus' };
break;
case 'T':
map[z][y][x] = { type: 'item', add: { lives: 0, attack: 1, armor: 0 }, name: 'Attack Bonus' };
break;
// KEYS
case '0':
map[z][y][x] = { type: 'key', color: 'red' };
break;
case '2':
map[z][y][x] = { type: 'key', color: 'green' };
break;
case '4':
map[z][y][x] = { type: 'key', color: 'blue' };
break;
case '6':
map[z][y][x] = { type: 'key', color: 'yellow' };
break;
case '8':
map[z][y][x] = { type: 'key', color: 'orange' };
break;
// DOORS
case '1':
map[z][y][x] = { type: 'door', color: 'red' };
break;
case '3':
map[z][y][x] = { type: 'door', color: 'green' };
break;
case '5':
map[z][y][x] = { type: 'door', color: 'blue' };
break;
case '7':
map[z][y][x] = { type: 'door', color: 'yellow' };
break;
case '9':
map[z][y][x] = { type: 'door', color: 'orange' };
break;
default:
console.error('Map contains unexpected character:', col);
}
x++;
}
y++;
}
z++;
}
return map;
}
function getRemainingLives(player, enemy) {
let playerLives = player.lives;
let enemyLives = enemy.lives;
while (true) {
const playerHit = Math.max(player.attack - enemy.armor, 0);
enemyLives = Math.max(enemyLives - playerHit, 0);
if (enemyLives === 0) break;
const enemyHit = Math.max(enemy.attack - player.armor, 0);
playerLives = Math.max(playerLives - enemyHit, 0);
if (playerLives === 0) break;
}
return playerLives;
}
function getAccessibleFields(map, startX, startY, startZ = 0) {
let obstacles = [];
let collectibles = [];
let doneFields = [];
function search(x, y, z) {
const field = map[z][y][x];
if (doneFields.includes(`${x},${y},${z}`)) return;
doneFields.push(`${x},${y},${z}`);
switch (field.type) {
case 'wall':
break;
case 'empty':
case 'stairs':
case 'item':
case 'key':
if (field.type === 'item' || field.type === 'key') {
collectibles.push({ x, y, z });
} else if (field.type === 'stairs') {
doneFields.push(`${x},${y},${z + field.direction}`);
z += field.direction;
}
// Continue searching...
search(x + 1, y, z);
search(x - 1, y, z);
search(x, y + 1, z);
search(x, y - 1, z);
break;
case 'exit':
case 'endboss':
case 'enemy':
case 'door':
obstacles.push({ x, y, z });
break;
default:
console.error('Unknown field type', field.type);
}
}
search(startX, startY, startZ);
//console.log(`Search at ${startX}, ${startY}, ${startZ} ->`, collectibles, obstacles);
return [ obstacles, collectibles ];
}
// ========= //
(function run() {
if (!FORCE_RECALC && LEVELS[CURRENT_LEVEL].hasOwnProperty('solution')) {
return console.log(LEVELS[CURRENT_LEVEL].solution.join('\n'));
}
function solve(player, map, log = []) {
const field = map[player.z][player.y][player.x];
switch (field.type) {
case 'empty':
break;
case 'wall':
return false;
case 'exit':
log.push(`Go to EXIT at x: ${player.x}, y: ${player.y}, floor: ${player.z + 1}`);
return log;
case 'endboss':
case 'enemy':
player.lives = getRemainingLives(player, field.stats);
if (player.lives <= 0) return false;
log.push(`Attack ${field.name.toUpperCase()} at x: ${player.x}, y: ${player.y}, floor: ${player.z + 1}`);
if (field.type === 'endboss') return log;
map[player.z][player.y][player.x].type = 'empty';
break;
case 'door':
//console.log(`Trying to open ${field.color} door at ${player.x}, ${player.y} -> ${player.keys[field.color] <= 0 ? 'failed' : 'success'}`);
if (player.keys[field.color] <= 0) return false;
player.keys[field.color]--;
map[player.z][player.y][player.x].type = 'empty';
log.push(`Open ${field.color.toUpperCase()} DOOR at x: ${player.x}, y: ${player.y}, floor: ${player.z + 1}`);
break;
default:
console.error('Unknown field type', field.type);
}
const [ obstacles, collectibles ] = getAccessibleFields(map, player.x, player.y, player.z);
// Immediately take items and keys
for (let { x, y, z } of collectibles) {
const collectible = map[z][y][x];
switch (collectible.type) {
case 'item':
player.lives += collectible.add.lives;
player.attack += collectible.add.attack;
player.armor += collectible.add.armor;
map[z][y][x].type = 'empty';
log.push(`Take ${collectible.name.toUpperCase()} at x: ${x}, y: ${y}, floor: ${z + 1}`);
break;
case 'key':
player.keys[collectible.color]++;
map[z][y][x].type = 'empty';
log.push(`Take ${collectible.color.toUpperCase()} KEY at x: ${x}, y: ${y}, floor: ${z + 1}`);
break;
default:
console.error('Unknown field type', field.type);
}
}
// Doors, Enemies and Exits are considered obstacles
for (let { x, y, z } of obstacles) {
const result = solve({ ...clone(player), x, y, z }, clone(map), clone(log));
if (result) return result;
}
}
const parsedMap = parseMap(DUNGEON_MAP);
if (parsedMap[INITIAL_PLAYER.z][INITIAL_PLAYER.y][INITIAL_PLAYER.x].type !== 'empty') return console.error('Player needs to start on an empty tile!');
const result = solve(INITIAL_PLAYER, parsedMap);
if (!result) return console.warn('No solutions found!');
console.log(result.join('\n'));
let updatedLevels = LEVELS;
updatedLevels[CURRENT_LEVEL].solution = result;
fs.writeFileSync('./levels.json', JSON.stringify(updatedLevels, null, '\t'));
})();
{
"1": {
"player": {
"lives": 50,
"attack": 1,
"armor": 1
},
"floors": [
[
"███████████",
"████ █E █",
"████ B █",
"█████ █████",
"█████H█████",
"█████A█████",
"█████T█████",
"█████ █████",
"████ ████",
"████ ████",
"███████████"
]
],
"solution": [
"Take ATTACK BONUS at x: 5, y: 6, floor: 1",
"Take ARMOR BONUS at x: 5, y: 5, floor: 1",
"Take MEDICINE at x: 5, y: 4, floor: 1",
"Attack BLUE ENEMY at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"2": {
"player": {
"lives": 100,
"attack": 2,
"armor": 2
},
"floors": [
[
"███████████",
"████ E ████",
"████ ████",
"█████1█████",
"█ █ █ █",
"█0 5 B 4█",
"█ █ █ █",
"█████ █████",
"████ ████",
"████ ████",
"███████████"
]
],
"solution": [
"Attack BLUE ENEMY at x: 7, y: 5, floor: 1",
"Take BLUE KEY at x: 9, y: 5, floor: 1",
"Open BLUE DOOR at x: 3, y: 5, floor: 1",
"Take RED KEY at x: 1, y: 5, floor: 1",
"Open RED DOOR at x: 5, y: 3, floor: 1",
"Go to EXIT at x: 5, y: 1, floor: 1"
]
},
"3": {
"player": {
"lives": 50,
"attack": 3,
"armor": 3
},
"floors": [
[
"███████████",
"████ █E █",
"████ R █",
"█████5█████",
"█T █ █ █",
"█ 4█",
"█A █ █ █",
"█████ █████",
"████ ████",
"████ ████",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 9, y: 5, floor: 1",
"Take ARMOR BONUS at x: 1, y: 6, floor: 1",
"Take ATTACK BONUS at x: 1, y: 4, floor: 1",
"Open BLUE DOOR at x: 5, y: 3, floor: 1",
"Attack RED ENEMY at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"4": {
"player": {
"lives": 50,
"attack": 3,
"armor": 3
},
"floors": [
[
"███████████",
"████ █E █",
"████ G █",
"█████ █████",
"█T █ █ A█",
"█T 9 9 A█",
"█T █ █ A█",
"█████ █████",
"████H 8████",
"████ ████",
"███████████"
]
],
"solution": [
"Take ORANGE KEY at x: 6, y: 8, floor: 1",
"Take MEDICINE at x: 4, y: 8, floor: 1",
"Open ORANGE DOOR at x: 3, y: 5, floor: 1",
"Take ATTACK BONUS at x: 1, y: 5, floor: 1",
"Take ATTACK BONUS at x: 1, y: 6, floor: 1",
"Take ATTACK BONUS at x: 1, y: 4, floor: 1",
"Attack GREEN ENEMY at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"5": {
"player": {
"lives": 100,
"attack": 3,
"armor": 3
},
"floors": [
[
"███████████",
"█████ G █",
"█ ██ E█",
"█ █ █ 55 █",
"█R█5███████",
"█ ███████",
"██ ████████",
"██ 5 █ 4█",
"██ █ █",
"██ B █ 4█",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 9, y: 9, floor: 1",
"Take BLUE KEY at x: 9, y: 7, floor: 1",
"Attack BLUE ENEMY at x: 3, y: 9, floor: 1",
"Attack RED ENEMY at x: 1, y: 4, floor: 1",
"Open BLUE DOOR at x: 6, y: 3, floor: 1",
"Open BLUE DOOR at x: 7, y: 3, floor: 1",
"Go to EXIT at x: 9, y: 2, floor: 1"
]
},
"6": {
"player": {
"lives": 50,
"attack": 2,
"armor": 2
},
"floors": [
[
"███████████",
"████ █E █",
"████ R █",
"█████ █████",
"█A █ █ H█",
"█ 9 9 █",
"█A █ █ H█",
"█████ █████",
"████ 8████",
"████ ████",
"███████████"
]
],
"solution": [
"Take ORANGE KEY at x: 6, y: 8, floor: 1",
"Open ORANGE DOOR at x: 7, y: 5, floor: 1",
"Take MEDICINE at x: 9, y: 6, floor: 1",
"Take MEDICINE at x: 9, y: 4, floor: 1",
"Attack RED ENEMY at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"7": {
"player": {
"lives": 100,
"attack": 2,
"armor": 2
},
"floors": [
[
"███████████",
"████ █E █",
"████ R █",
"█████1█████",
"█A █ █ H█",
"█ B5 5B █",
"█T █ █ 0█",
"█████ █████",
"████4 4████",
"████ ████",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 6, y: 8, floor: 1",
"Take BLUE KEY at x: 4, y: 8, floor: 1",
"Open BLUE DOOR at x: 7, y: 5, floor: 1",
"Open BLUE DOOR at x: 3, y: 5, floor: 1",
"Attack BLUE ENEMY at x: 2, y: 5, floor: 1",
"Take ATTACK BONUS at x: 1, y: 6, floor: 1",
"Take ARMOR BONUS at x: 1, y: 4, floor: 1",
"Attack BLUE ENEMY at x: 8, y: 5, floor: 1",
"Take RED KEY at x: 9, y: 6, floor: 1",
"Take MEDICINE at x: 9, y: 4, floor: 1",
"Open RED DOOR at x: 5, y: 3, floor: 1",
"Attack RED ENEMY at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"8": {
"player": {
"lives": 100,
"attack": 4,
"armor": 4
},
"floors": [
[
"███████████",
"████ █E █",
"████ O █",
"█████ █████",
"█H █ █ H█",
"█ 5 5 █",
"█H █ █ H█",
"██6██ ██5██",
"█T █4 4█ A█",
"█TT█ █AA█",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 6, y: 8, floor: 1",
"Take BLUE KEY at x: 4, y: 8, floor: 1",
"Open BLUE DOOR at x: 7, y: 5, floor: 1",
"Take MEDICINE at x: 9, y: 6, floor: 1",
"Take MEDICINE at x: 9, y: 4, floor: 1",
"Open BLUE DOOR at x: 3, y: 5, floor: 1",
"Take MEDICINE at x: 1, y: 6, floor: 1",
"Take YELLOW KEY at x: 2, y: 7, floor: 1",
"Take ATTACK BONUS at x: 1, y: 8, floor: 1",
"Take ATTACK BONUS at x: 1, y: 9, floor: 1",
"Take ATTACK BONUS at x: 2, y: 9, floor: 1",
"Take MEDICINE at x: 1, y: 4, floor: 1",
"Attack BANDIT at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"9": {
"player": {
"lives": 65,
"attack": 8,
"armor": 8
},
"floors": [
[
"███████████",
"████ █E █",
"████ Y █",
"█████ █████",
"█T █ █ A█",
"█TG GA█",
"█T █ █ A█",
"█████ █████",
"████ ████",
"████ ████",
"███████████"
]
],
"solution": [
"Attack GREEN ENEMY at x: 8, y: 5, floor: 1",
"Take ARMOR BONUS at x: 9, y: 5, floor: 1",
"Take ARMOR BONUS at x: 9, y: 6, floor: 1",
"Take ARMOR BONUS at x: 9, y: 4, floor: 1",
"Attack GREEN ENEMY at x: 2, y: 5, floor: 1",
"Take ATTACK BONUS at x: 1, y: 5, floor: 1",
"Take ATTACK BONUS at x: 1, y: 6, floor: 1",
"Take ATTACK BONUS at x: 1, y: 4, floor: 1",
"Attack YELLOW ENEMY at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"10": {
"player": {
"lives": 50,
"attack": 5,
"armor": 5
},
"floors": [
[
"███████████",
"█ B █E █",
"█ █ █",
"██ ████████",
"█ GR G █",
"█ ██ ██ █",
"█ O BR █",
"████████ ██",
"█H █ █ █",
"█H B █",
"███████████"
]
],
"solution": [
"Take MEDICINE at x: 1, y: 9, floor: 1",
"Take MEDICINE at x: 1, y: 8, floor: 1",
"Attack BLUE ENEMY at x: 8, y: 9, floor: 1",
"Attack RED ENEMY at x: 7, y: 6, floor: 1",
"Attack BLUE ENEMY at x: 6, y: 6, floor: 1",
"Attack RED ENEMY at x: 4, y: 4, floor: 1",
"Attack GREEN ENEMY at x: 3, y: 4, floor: 1",
"Attack BLUE ENEMY at x: 2, y: 1, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"11": {
"player": {
"lives": 10,
"attack": 12,
"armor": 24
},
"floors": [
[
"███████████",
"████ █E █",
"████ K █",
"█████ █████",
"█ █ █ █",
"█T 9 9 A█",
"█ █ █ █",
"█████ █████",
"████ 8████",
"████ ████",
"███████████"
]
],
"solution": [
"Take ORANGE KEY at x: 6, y: 8, floor: 1",
"Open ORANGE DOOR at x: 7, y: 5, floor: 1",
"Take ARMOR BONUS at x: 9, y: 5, floor: 1",
"Attack KNIGHT at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 8, y: 1, floor: 1"
]
},
"12": {
"player": {
"lives": 100,
"attack": 5,
"armor": 5
},
"floors": [
[
"███████████",
"█4█2█6█4█0█",
"█4█ █ █4█ █",
"█ █ █3█ █ █",
"█5█1█5█1█5█",
"█ █",
"█ █",
"██7██ ██ ██",
"█E █ █ █",
"█ █ █ 4█",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 9, y: 9, floor: 1",
"Open BLUE DOOR at x: 1, y: 4, floor: 1",
"Take BLUE KEY at x: 1, y: 2, floor: 1",
"Take BLUE KEY at x: 1, y: 1, floor: 1",
"Open BLUE DOOR at x: 9, y: 4, floor: 1",
"Take RED KEY at x: 9, y: 1, floor: 1",
"Open RED DOOR at x: 3, y: 4, floor: 1",
"Take GREEN KEY at x: 3, y: 1, floor: 1",
"Open BLUE DOOR at x: 5, y: 4, floor: 1",
"Open GREEN DOOR at x: 5, y: 3, floor: 1",
"Take YELLOW KEY at x: 5, y: 1, floor: 1",
"Open YELLOW DOOR at x: 2, y: 7, floor: 1",
"Go to EXIT at x: 1, y: 8, floor: 1"
]
},
"13": {
"player": {
"lives": 10,
"attack": 30,
"armor": 0
},
"floors": [
[
"███████████",
"█AAR5 █ E█",
"█████ S █",
"█TTR5 █ █",
"█████ █████",
"█AAR5 5RT█",
"█████ █ T█",
"█TTR5 ████",
"█████ █ 4█",
"█AAR5 44█",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 8, y: 9, floor: 1",
"Take BLUE KEY at x: 9, y: 9, floor: 1",
"Take BLUE KEY at x: 9, y: 8, floor: 1",
"Open BLUE DOOR at x: 7, y: 5, floor: 1",
"Attack RED ENEMY at x: 8, y: 5, floor: 1",
"Take ATTACK BONUS at x: 9, y: 5, floor: 1",
"Take ATTACK BONUS at x: 9, y: 6, floor: 1",
"Open BLUE DOOR at x: 4, y: 7, floor: 1",
"Open BLUE DOOR at x: 4, y: 3, floor: 1",
"Attack RED ENEMY at x: 3, y: 7, floor: 1",
"Take ATTACK BONUS at x: 2, y: 7, floor: 1",
"Take ATTACK BONUS at x: 1, y: 7, floor: 1",
"Attack RED ENEMY at x: 3, y: 3, floor: 1",
"Take ATTACK BONUS at x: 2, y: 3, floor: 1",
"Take ATTACK BONUS at x: 1, y: 3, floor: 1",
"Attack SKULL at x: 7, y: 2, floor: 1",
"Go to EXIT at x: 9, y: 1, floor: 1"
]
},
"14": {
"player": {
"lives": 1,
"attack": 15,
"armor": 9
},
"floors": [
[
"███████████",
"█A4██E██4A█",
"█ ██5██ █",
"██R██5██B██",
"█ █5█ █",
"█ █5█ █",
"█ █",
"██G██ ██O██",
"█ █ █ █",
"█A4█ █4A█",
"███████████"
]
],
"solution": [
"Attack BLUE ENEMY at x: 8, y: 3, floor: 1",
"Take ARMOR BONUS at x: 9, y: 1, floor: 1",
"Take BLUE KEY at x: 8, y: 1, floor: 1",
"Attack BANDIT at x: 8, y: 7, floor: 1",
"Take ARMOR BONUS at x: 9, y: 9, floor: 1",
"Take BLUE KEY at x: 8, y: 9, floor: 1",
"Attack RED ENEMY at x: 2, y: 3, floor: 1",
"Take ARMOR BONUS at x: 1, y: 1, floor: 1",
"Take BLUE KEY at x: 2, y: 1, floor: 1",
"Open BLUE DOOR at x: 5, y: 5, floor: 1",
"Attack GREEN ENEMY at x: 2, y: 7, floor: 1",
"Take ARMOR BONUS at x: 1, y: 9, floor: 1",
"Take BLUE KEY at x: 2, y: 9, floor: 1",
"Open BLUE DOOR at x: 5, y: 4, floor: 1",
"Open BLUE DOOR at x: 5, y: 3, floor: 1",
"Open BLUE DOOR at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 5, y: 1, floor: 1"
]
},
"15": {
"player": {
"lives": 85,
"attack": 15,
"armor": 15
},
"floors": [
[
"███████████",
"█2AA █ TT2█",
"█ █ █",
"█Y██K█W██M█",
"█5██1█5██1█",
"█ █",
"██3█ █",
"██3██ █████",
"█E █ █ 0█",
"█ █ 4█",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 9, y: 9, floor: 1",
"Take RED KEY at x: 9, y: 8, floor: 1",
"Open RED DOOR at x: 4, y: 4, floor: 1",
"Open BLUE DOOR at x: 6, y: 4, floor: 1",
"Attack WOLF at x: 6, y: 3, floor: 1",
"Take GREEN KEY at x: 9, y: 1, floor: 1",
"Take ATTACK BONUS at x: 8, y: 1, floor: 1",
"Take ATTACK BONUS at x: 7, y: 1, floor: 1",
"Open GREEN DOOR at x: 2, y: 6, floor: 1",
"Attack KNIGHT at x: 4, y: 3, floor: 1",
"Take GREEN KEY at x: 1, y: 1, floor: 1",
"Take ARMOR BONUS at x: 2, y: 1, floor: 1",
"Take ARMOR BONUS at x: 3, y: 1, floor: 1",
"Open GREEN DOOR at x: 2, y: 7, floor: 1",
"Go to EXIT at x: 1, y: 8, floor: 1"
]
},
"16": {
"player": {
"lives": 160,
"attack": 19,
"armor": 10
},
"floors": [
[
"███████████",
"█T4██E██4T█",
"█ ██5██ █",
"██K██5██Y██",
"█ █5█ █",
"█ █5█ █",
"█ █",
"██W██ ██S██",
"█ █ █ █",
"█T4█ █4T█",
"███████████"
]
],
"solution": [
"Attack SKULL at x: 8, y: 7, floor: 1",
"Take ATTACK BONUS at x: 9, y: 9, floor: 1",
"Take BLUE KEY at x: 8, y: 9, floor: 1",
"Attack WOLF at x: 2, y: 7, floor: 1",
"Take ATTACK BONUS at x: 1, y: 9, floor: 1",
"Take BLUE KEY at x: 2, y: 9, floor: 1",
"Attack YELLOW ENEMY at x: 8, y: 3, floor: 1",
"Take ATTACK BONUS at x: 9, y: 1, floor: 1",
"Take BLUE KEY at x: 8, y: 1, floor: 1",
"Attack KNIGHT at x: 2, y: 3, floor: 1",
"Take ATTACK BONUS at x: 1, y: 1, floor: 1",
"Take BLUE KEY at x: 2, y: 1, floor: 1",
"Open BLUE DOOR at x: 5, y: 5, floor: 1",
"Open BLUE DOOR at x: 5, y: 4, floor: 1",
"Open BLUE DOOR at x: 5, y: 3, floor: 1",
"Open BLUE DOOR at x: 5, y: 2, floor: 1",
"Go to EXIT at x: 5, y: 1, floor: 1"
]
},
"17": {
"player": {
"lives": 55,
"attack": 13,
"armor": 13
},
"floors": [
[
"███████████",
"█H█H█H█H█H█",
"█T█A█T█A█T█",
"█ █ █ █ █ █",
"█Y█W█G█M█N█",
"█ █",
"█ █",
"██3██ ██ ██",
"█EK█ █K █",
"█ █ █ 2█",
"███████████"
]
],
"solution": [
"Attack GREEN ENEMY at x: 5, y: 4, floor: 1",
"Take ATTACK BONUS at x: 5, y: 2, floor: 1",
"Take MEDICINE at x: 5, y: 1, floor: 1",
"Attack WOLF at x: 3, y: 4, floor: 1",
"Take ARMOR BONUS at x: 3, y: 2, floor: 1",
"Take MEDICINE at x: 3, y: 1, floor: 1",
"Attack YELLOW ENEMY at x: 1, y: 4, floor: 1",
"Take ATTACK BONUS at x: 1, y: 2, floor: 1",
"Take MEDICINE at x: 1, y: 1, floor: 1",
"Attack BLACK ENEMY at x: 9, y: 4, floor: 1",
"Take ATTACK BONUS at x: 9, y: 2, floor: 1",
"Take MEDICINE at x: 9, y: 1, floor: 1",
"Attack KNIGHT at x: 8, y: 8, floor: 1",
"Take GREEN KEY at x: 9, y: 9, floor: 1",
"Open GREEN DOOR at x: 2, y: 7, floor: 1",
"Attack KNIGHT at x: 2, y: 8, floor: 1",
"Go to EXIT at x: 1, y: 8, floor: 1"
]
},
"18": {
"player": {
"lives": 80,
"attack": 13,
"armor": 13
},
"floors": [
[
"███████████",
"█H Y5 █ E█",
"█████ █ █",
"█TTW1 █ K █",
"█████ ██ ██",
"█0 G5 8█",
"█████ █████",
"█AAW1 9 00█",
"█████ █████",
"█H Y1 9440█",
"███████████"
]
],
"solution": [
"Take ORANGE KEY at x: 9, y: 5, floor: 1",
"Open ORANGE DOOR at x: 6, y: 9, floor: 1",
"Take BLUE KEY at x: 7, y: 9, floor: 1",
"Take BLUE KEY at x: 8, y: 9, floor: 1",
"Take RED KEY at x: 9, y: 9, floor: 1",
"Open RED DOOR at x: 4, y: 9, floor: 1",
"Open BLUE DOOR at x: 4, y: 5, floor: 1",
"Attack YELLOW ENEMY at x: 3, y: 9, floor: 1",
"Take MEDICINE at x: 1, y: 9, floor: 1",
"Attack GREEN ENEMY at x: 3, y: 5, floor: 1",
"Take RED KEY at x: 1, y: 5, floor: 1",
"Open RED DOOR at x: 4, y: 3, floor: 1",
"Open BLUE DOOR at x: 4, y: 1, floor: 1",
"Attack WOLF at x: 3, y: 3, floor: 1",
"Take ATTACK BONUS at x: 2, y: 3, floor: 1",
"Take ATTACK BONUS at x: 1, y: 3, floor: 1",
"Attack YELLOW ENEMY at x: 3, y: 1, floor: 1",
"Take MEDICINE at x: 1, y: 1, floor: 1",
"Attack KNIGHT at x: 8, y: 3, floor: 1",
"Go to EXIT at x: 9, y: 1, floor: 1"
]
},
"19": {
"player": {
"lives": 20,
"attack": 8,
"armor": 8
},
"floors": [
[
"███████████",
"█ █ E █ █",
"████ ████",
"█ █",
"█N███Y███N█",
"█ K W M O █",
"█H█T█R█A█H█",
"█ B M G K █",
"█O█W█ █B█G█",
"█ R W █",
"███████████"
]
],
"solution": [
"Attack BLUE ENEMY at x: 7, y: 8, floor: 1",
"Take ARMOR BONUS at x: 7, y: 6, floor: 1",
"Attack BANDIT at x: 8, y: 5, floor: 1",
"Take MEDICINE at x: 9, y: 6, floor: 1",
"Attack RED ENEMY at x: 2, y: 9, floor: 1",
"Attack RED ENEMY at x: 5, y: 6, floor: 1",
"Attack BANDIT at x: 1, y: 8, floor: 1",
"Take MEDICINE at x: 1, y: 6, floor: 1",
"Attack YELLOW ENEMY at x: 5, y: 4, floor: 1",
"Attack BLUE ENEMY at x: 2, y: 7, floor: 1",
"Take ATTACK BONUS at x: 3, y: 6, floor: 1",
"Go to EXIT at x: 5, y: 1, floor: 1"
]
},
"20": {
"player": {
"lives": 115,
"attack": 13,
"armor": 15
},
"floors": [
[
"███████████",
"█ H H █",
"█5█M█5█N█5█",
"█T█T█T█T█T█",
"█K█5█G█5█Y█",
"█ █",
"█S█I█ 44█K█",
"█4█4█ ███K█",
"█D█W█ █E█K█",
"█ 7 █6█",
"███████████"
]
],
"solution": [
"Take BLUE KEY at x: 6, y: 6, floor: 1",
"Take BLUE KEY at x: 7, y: 6, floor: 1",
"Attack YELLOW ENEMY at x: 9, y: 4, floor: 1",
"Take ATTACK BONUS at x: 9, y: 3, floor: 1",
"Open BLUE DOOR at x: 3, y: 4, floor: 1",
"Take ATTACK BONUS at x: 3, y: 3, floor: 1",
"Open BLUE DOOR at x: 9, y: 2, floor: 1",
"Take MEDICINE at x: 6, y: 1, floor: 1",
"Take MEDICINE at x: 4, y: 1, floor: 1",
"Attack WOLF at x: 3, y: 8, floor: 1",
"Take BLUE KEY at x: 3, y: 7, floor: 1",
"Open BLUE DOOR at x: 1, y: 2, floor: 1",
"Take ATTACK BONUS at x: 1, y: 3, floor: 1",
"Attack GREEN ENEMY at x: 5, y: 4, floor: 1",
"Take ATTACK BONUS at x: 5, y: 3, floor: 1",
"Attack KNIGHT at x: 9, y: 6, floor: 1",
"Attack KNIGHT at x: 9, y: 7, floor: 1",
"Attack KNIGHT at x: 9, y: 8, floor: 1",
"Take YELLOW KEY at x: 9, y: 9, floor: 1",
"Open YELLOW DOOR at x: 6, y: 9, floor: 1",
"Go to EXIT at x: 7, y: 8, floor: 1"
]
},
"prince": {
"player": {
"lives": 100,
"attack": 3,
"armor": 3
},
"floors": [
[
"███████████",
"█ ███HHH█",
"█ U 5T4A█",
"█ █ █T0A█",
"█████ █████",
"█ █",
"█ ███████ █",
"█R█ B █G█",
"█ █ █ █",
"█████ █████",
"███████████"
],
[
"███████████",
"█ ███████",
"█ L 4███",
"█ █ █████",
"█████ █████",
"█T██ B ██A█",
"█T9 9A█",
"█T██ ██A█",
"█████ █████",
"█████U█████",
"███████████"
],
[
"███████████",
"████ ████",
"██H█ U █8██",
"██R█ O █3██",
"█ ██ ██ █",
"█ B5 █",
"█ ██ ██ █",
"██1█ █3██",
"██2█ L █6██",
"████ ████",
"███████████"
],
[
"███████████",
"████ █4██",
"█ R L █4██",
"█R██ █B██",
"█ ███ ██ ██",
"█R R█ ██",
"███ █5██ ██",
"██ R█H██B██",
"██U████AAA█",
"███████AAA█",
"███████████"
],
[
"███████████",
"█ HHH █",
"██1█████1██",
"█TT█ █AA█",
"█TT█ P █AA█",
"█T █ █ A█",
"██9██7██9██",
"█ █",
"█ LU ██████",
"█ G 80█",
"███████████"
],
[
"███████████",
"███6 █████",
"█████ █████",
"███ K ███",
"███ █ █ ███",
"███ ███",
"█████5█████",
"██ ██",
"██ L ██",
"███████████",
"███████████"
]
],
"solution": [
"Attack BLUE ENEMY at x: 5, y: 7, floor: 1",
"Attack RED ENEMY at x: 1, y: 7, floor: 1",
"Take BLUE KEY at x: 7, y: 2, floor: 2",
"Open BLUE DOOR at x: 6, y: 2, floor: 1",
"Take ATTACK BONUS at x: 7, y: 2, floor: 1",
"Take BLUE KEY at x: 8, y: 2, floor: 1",
"Take ARMOR BONUS at x: 9, y: 2, floor: 1",
"Take ARMOR BONUS at x: 9, y: 3, floor: 1",
"Take RED KEY at x: 8, y: 3, floor: 1",
"Take ATTACK BONUS at x: 7, y: 3, floor: 1",
"Take MEDICINE at x: 9, y: 1, floor: 1",
"Take MEDICINE at x: 8, y: 1, floor: 1",
"Take MEDICINE at x: 7, y: 1, floor: 1",
"Attack BLUE ENEMY at x: 5, y: 5, floor: 2",
"Open BLUE DOOR at x: 3, y: 5, floor: 3",
"Attack GREEN ENEMY at x: 9, y: 7, floor: 1",
"Attack BLUE ENEMY at x: 2, y: 5, floor: 3",
"Open RED DOOR at x: 2, y: 7, floor: 3",
"Take GREEN KEY at x: 2, y: 8, floor: 3",
"Open GREEN DOOR at x: 8, y: 3, floor: 3",
"Take ORANGE KEY at x: 8, y: 2, floor: 3",
"Attack RED ENEMY at x: 2, y: 3, floor: 3",
"Take MEDICINE at x: 2, y: 2, floor: 3",
"Open ORANGE DOOR at x: 2, y: 6, floor: 2",
"Take ATTACK BONUS at x: 1, y: 6, floor: 2",
"Take ATTACK BONUS at x: 1, y: 7, floor: 2",
"Take ATTACK BONUS at x: 1, y: 5, floor: 2",
"Attack BANDIT at x: 5, y: 3, floor: 3",
"Attack RED ENEMY at x: 2, y: 2, floor: 4",
"Attack BLUE ENEMY at x: 8, y: 7, floor: 4",
"Take ARMOR BONUS at x: 8, y: 8, floor: 4",
"Take ARMOR BONUS at x: 9, y: 8, floor: 4",
"Take ARMOR BONUS at x: 9, y: 9, floor: 4",
"Take ARMOR BONUS at x: 8, y: 9, floor: 4",
"Take ARMOR BONUS at x: 7, y: 9, floor: 4",
"Take ARMOR BONUS at x: 7, y: 8, floor: 4",
"Attack RED ENEMY at x: 1, y: 3, floor: 4",
"Attack RED ENEMY at x: 1, y: 5, floor: 4",
"Attack RED ENEMY at x: 3, y: 5, floor: 4",
"Attack BLUE ENEMY at x: 8, y: 3, floor: 4",
"Take BLUE KEY at x: 8, y: 2, floor: 4",
"Take BLUE KEY at x: 8, y: 1, floor: 4",
"Open BLUE DOOR at x: 5, y: 6, floor: 4",
"Take MEDICINE at x: 5, y: 7, floor: 4",
"Attack RED ENEMY at x: 3, y: 7, floor: 4",
"Attack GREEN ENEMY at x: 5, y: 9, floor: 5",
"Take ORANGE KEY at x: 8, y: 9, floor: 5",
"Take RED KEY at x: 9, y: 9, floor: 5",
"Open ORANGE DOOR at x: 2, y: 6, floor: 5",
"Take ATTACK BONUS at x: 1, y: 5, floor: 5",
"Take ATTACK BONUS at x: 1, y: 4, floor: 5",
"Take ATTACK BONUS at x: 2, y: 4, floor: 5",
"Take ATTACK BONUS at x: 2, y: 3, floor: 5",
"Take ATTACK BONUS at x: 1, y: 3, floor: 5",
"Open RED DOOR at x: 2, y: 2, floor: 5",
"Take MEDICINE at x: 4, y: 1, floor: 5",
"Take MEDICINE at x: 5, y: 1, floor: 5",
"Take MEDICINE at x: 6, y: 1, floor: 5",
"Attack KNIGHT at x: 5, y: 3, floor: 6",
"Take YELLOW KEY at x: 3, y: 1, floor: 6",
"Open YELLOW DOOR at x: 5, y: 6, floor: 5",
"Attack PRINCE at x: 5, y: 4, floor: 5"
]
},
"// INFO": {
"0": "Red Key",
"1": "Red Door",
"2": "Green Key",
"3": "Green Door",
"4": "Blue Key",
"5": "Blue Door",
"6": "Yellow Key",
"7": "Yellow Door",
"8": "Orange Key",
"9": "Orange Door",
"U": "Stairs to upper floor",
"L": "Stairs to lower floor",
"█": "Wall",
" ": "Empty Space",
"E": "Exit",
"D": "Dinosaur",
"N": "Black Enemy",
"I": "Red Knight",
"M": "Redbeard Guy",
"Y": "Yellow Enemy",
"O": "Bandit/Outlaw",
"K": "Knight",
"W": "Wolf",
"G": "Green Enemy",
"S": "Skull",
"R": "Red Enemy",
"B": "Blue Enemy",
"H": "Health/Medicine (Green Item)",
"A": "Armor Bonus (Blue Item)",
"T": "Attack Bonus (Red Item)",
"P": "Prince",
"C": "King",
"Q": "Princess"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment