puzzlescript
Version:
Play PuzzleScript games in your terminal!
189 lines • 10.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTests = void 0;
/* eslint-env jasmine */
const fs_1 = __importStar(require("fs"));
const path_1 = __importDefault(require("path"));
const engine_1 = require("../../src/engine");
const parser_1 = __importDefault(require("../../src/parser/parser"));
const recordCoverage_1 = require("../../src/recordCoverage");
const util_1 = require("../../src/util");
// import TerminalUI from '../../src/ui/terminal'
const CI_MAX_SOLUTION_LENGTH = 1000; // The length of 1 level of cyber-lasso
const SKIP_GAMES = [
'always-magnets',
'lil-purple' // "Match lengths differ. Expected 1 but found 0."
];
const describeFn = process.env.SKIP_SOLUTIONS ? describe.skip : describe;
const SOLUTION_ROOT = path_1.default.join(__dirname, '../../game-solutions/');
const solutionFiles = fs_1.default.readdirSync(SOLUTION_ROOT);
function parseEngine(code, levelNum = 0) {
const { data } = parser_1.default.parse(code);
const engine = new engine_1.GameEngine(data, new util_1.EmptyGameEngineHandler());
return { engine, data };
}
function isShort() {
return process.env.CI === 'true' || process.env.TEST_SHORT === 'true';
}
function createTests(moduloNumber, moduloTotal) {
if (process.env.SKIP_SOLUTIONS) {
describe.skip('Skipping replay tests', () => {
it.skip('skiping test');
});
console.log('Skipping Replay tests'); // tslint:disable-line:no-console
return;
}
if (isShort() && (moduloNumber === 7 || moduloNumber === 8)) {
describe.skip(`Skipping replaySolutions/${moduloNumber}.test because it causes Travis to time out`, () => {
it.skip('skipping tests');
});
return;
}
describeFn('replays levels of games', () => {
solutionFiles.forEach((solutionFilename, solutionIndex) => {
// Skip the README.md file
if (!solutionFilename.endsWith('.json')) {
return;
}
// Only run 1/10 of all the games in each spec file. This is so JEST can run them concurrently
if (solutionIndex % moduloTotal !== moduloNumber) {
return;
}
const GIST_ID = path_1.default.basename(solutionFilename).replace('.json', '');
const testTitle = `plays ${isShort() ? '*a single level*' : '_the solved levels_'} of ${GIST_ID}`;
if (SKIP_GAMES.indexOf(GIST_ID) >= 0) {
it.skip(testTitle, () => { });
return;
}
it(testTitle, () => __awaiter(this, void 0, void 0, function* () {
const gistFilename = path_1.default.join(__dirname, `../../games/${GIST_ID}/script.txt`);
const { engine, data } = parseEngine(fs_1.default.readFileSync(gistFilename, 'utf-8'));
const recordings = JSON.parse(fs_1.default.readFileSync(path_1.default.join(SOLUTION_ROOT, solutionFilename), 'utf-8')).solutions;
let numPlayed = 0;
let hasAtLeastOneSolution = 0;
// play games in reverse order because it is likely that the harder levels will fail first
for (let index = recordings.length - 1; index >= 0; index--) {
// for (let index = 0; index < recordings.length; index++) {
const recording = recordings[index];
if (!recording || !recording.solution) {
continue; // skip message-only levels or levels that do not have a solution
}
// Some games (like Fish Friend) are a bunch of dialog and do not actually need to run
// so if they only contain a "X" then skip them
const trimmedSolution = recording.solution.replace(/,/g, '').replace(/\./g, '').replace(/!/g, '');
if (trimmedSolution === 'X' || trimmedSolution === '') {
continue;
}
hasAtLeastOneSolution++;
if (isShort() && recording.solution.length > CI_MAX_SOLUTION_LENGTH) {
const msg = `CI-SKIP: Solution group: [${moduloNumber}/${moduloTotal}]. Level=${index}. Because the solution is too long: ${recording.solution.length} > ${CI_MAX_SOLUTION_LENGTH}. "${GIST_ID}"`; // tslint:disable-line:max-line-length
console.log(msg); // tslint:disable-line:no-console
continue;
}
if (isShort() && numPlayed > 0) {
break;
}
numPlayed++;
engine.setLevel(index, null /*no checkpoint*/);
// UI.setGame(engine)
const DID_NOT_WIN = 'DID_NOT_WIN';
let wonAtKeyIndex = DID_NOT_WIN;
const keypresses = recording.solution.split('');
for (let i = 0; i < keypresses.length; i++) {
const key = keypresses[i];
switch (key) {
case 'W':
engine.press(util_1.INPUT_BUTTON.UP);
break;
case 'S':
engine.press(util_1.INPUT_BUTTON.DOWN);
break;
case 'A':
engine.press(util_1.INPUT_BUTTON.LEFT);
break;
case 'D':
engine.press(util_1.INPUT_BUTTON.RIGHT);
break;
case 'X':
engine.press(util_1.INPUT_BUTTON.ACTION);
break;
case '!': // dismiss message prompt. not even a tick
continue;
case '.':
case ',':
break;
default:
throw new Error(`ERROR: Unsupported character "${key}"`);
}
let didWin = false;
// do { // loop until we are done with animations
const { didLevelChange, didWinGame } = yield engine.tick();
didWin = didWin || didWinGame || didLevelChange;
// } while(engine.hasAgain())
// if (SHOW_STEPS) {
// UI.renderScreen(false)
// }
if (didWin) {
wonAtKeyIndex = i;
break;
}
}
if (wonAtKeyIndex === DID_NOT_WIN || (wonAtKeyIndex !== keypresses.length - 1)) {
// console.error('Screendump of level')
// TerminalUI.setGameEngine(engine)
// TerminalUI.dumpScreen()
// while (engine.canUndo()) {
// engine.pressUndo()
// engine.tick()
// TerminalUI.dumpScreen()
// }
// UI.setGame(engine)
// UI.dumpScreen()
}
expect({ title: data.title, levelNumber: index, wonAtKeyIndex }).toEqual({ title: data.title, levelNumber: index, wonAtKeyIndex: keypresses.length - 1 });
}
if (hasAtLeastOneSolution > 1) {
expect(numPlayed).toBeGreaterThanOrEqual(1);
}
const coverageFilenameSuffix = `${GIST_ID}-playgame`;
const codeCoverageObj = (0, recordCoverage_1.saveCoverageFile)(data, gistFilename, (absPath) => path_1.default.relative(process.cwd(), absPath));
if ((0, fs_1.existsSync)(`coverage`)) {
(0, fs_1.writeFileSync)(`coverage/coverage-${coverageFilenameSuffix}.json`, JSON.stringify(codeCoverageObj, null, 2)); // indent by 2 chars
}
}));
});
});
}
exports.createTests = createTests;
//# sourceMappingURL=helper.js.map