mirror of
https://github.com/Kugelschieber/breach.git
synced 2026-01-18 12:00:25 +00:00
Started work on matrix generation
This commit is contained in:
146
package-lock.json
generated
146
package-lock.json
generated
@@ -1233,6 +1233,11 @@
|
|||||||
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
|
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/seedrandom": {
|
||||||
|
"version": "2.4.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.28.tgz",
|
||||||
|
"integrity": "sha512-SMA+fUwULwK7sd/ZJicUztiPs8F1yCPwF3O23Z9uQ32ME5Ha0NmDK9+QTsYE4O2tHXChzXomSWWeIhCnoN1LqA=="
|
||||||
|
},
|
||||||
"@types/serve-static": {
|
"@types/serve-static": {
|
||||||
"version": "1.13.8",
|
"version": "1.13.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
|
||||||
@@ -1767,26 +1772,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fork-ts-checker-webpack-plugin-v5": {
|
|
||||||
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
|
|
||||||
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@babel/code-frame": "^7.8.3",
|
|
||||||
"@types/json-schema": "^7.0.5",
|
|
||||||
"chalk": "^4.1.0",
|
|
||||||
"cosmiconfig": "^6.0.0",
|
|
||||||
"deepmerge": "^4.2.2",
|
|
||||||
"fs-extra": "^9.0.0",
|
|
||||||
"memfs": "^3.1.2",
|
|
||||||
"minimatch": "^3.0.4",
|
|
||||||
"schema-utils": "2.7.0",
|
|
||||||
"semver": "^7.3.2",
|
|
||||||
"tapable": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||||
@@ -1888,18 +1873,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema-utils": {
|
|
||||||
"version": "2.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
|
||||||
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/json-schema": "^7.0.4",
|
|
||||||
"ajv": "^6.12.2",
|
|
||||||
"ajv-keywords": "^3.4.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"slash": {
|
"slash": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||||
@@ -2205,16 +2178,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"json5": {
|
|
||||||
"version": "2.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
|
|
||||||
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"minimist": "^1.2.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jsonfile": {
|
"jsonfile": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
@@ -2224,18 +2187,6 @@
|
|||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loader-utils": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"big.js": "^5.2.2",
|
|
||||||
"emojis-list": "^3.0.0",
|
|
||||||
"json5": "^2.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@@ -2391,18 +2342,6 @@
|
|||||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"vue-loader-v16": {
|
|
||||||
"version": "npm:vue-loader@16.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.1.1.tgz",
|
|
||||||
"integrity": "sha512-wz/+HFg/3SBayHWAlZXARcnDTl3VOChrfW9YnxvAweiuyKX/7IGx1ad/4yJHmwhgWlOVYMAbTiI7GV8G33PfGQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"chalk": "^4.1.0",
|
|
||||||
"hash-sum": "^2.0.0",
|
|
||||||
"loader-utils": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
@@ -6935,6 +6874,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fork-ts-checker-webpack-plugin-v5": {
|
||||||
|
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/code-frame": "^7.8.3",
|
||||||
|
"@types/json-schema": "^7.0.5",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"cosmiconfig": "^6.0.0",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"fs-extra": "^9.0.0",
|
||||||
|
"memfs": "^3.1.2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"schema-utils": "2.7.0",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"tapable": "^1.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"schema-utils": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/json-schema": "^7.0.4",
|
||||||
|
"ajv": "^6.12.2",
|
||||||
|
"ajv-keywords": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||||
@@ -12925,6 +12898,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"seedrandom": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
|
||||||
|
},
|
||||||
"select-hose": {
|
"select-hose": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
||||||
@@ -15089,6 +15067,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vue-loader-v16": {
|
||||||
|
"version": "npm:vue-loader@16.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.1.2.tgz",
|
||||||
|
"integrity": "sha512-8QTxh+Fd+HB6fiL52iEVLKqE9N1JSlMXLR92Ijm6g8PZrwIxckgpqjPDWRP5TWxdiPaHR+alUWsnu1ShQOwt+Q==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"hash-sum": "^2.0.0",
|
||||||
|
"loader-utils": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"json5": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"minimist": "^1.2.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"loader-utils": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"big.js": "^5.2.2",
|
||||||
|
"emojis-list": "^3.0.0",
|
||||||
|
"json5": "^2.1.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-style-loader": {
|
"vue-style-loader": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
"testURL": "http://localhost/"
|
"testURL": "http://localhost/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/seedrandom": "^2.4.28",
|
||||||
|
"seedrandom": "^3.0.5",
|
||||||
"vue": "^3.0.0"
|
"vue": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
24
src/game/MatrixGeneration.test.ts
Normal file
24
src/game/MatrixGeneration.test.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import "jest"
|
||||||
|
import seedrandom from "seedrandom";
|
||||||
|
import {generateGameConfig} from "./MatrixGeneration";
|
||||||
|
import GameConfiguration from "./GameConfiguration";
|
||||||
|
|
||||||
|
describe("MatrixGen", () => {
|
||||||
|
|
||||||
|
test("random generator works", () => {
|
||||||
|
const seededRNG = seedrandom("Testseed");
|
||||||
|
expect(seededRNG()).toEqual(0.026130760816951273);
|
||||||
|
expect(seededRNG()).toEqual(0.24232428305919648);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("basic game config creation", () =>{
|
||||||
|
const gameConfig : GameConfiguration = generateGameConfig(1, "Testseed");
|
||||||
|
expect(gameConfig).not.toBeNull;
|
||||||
|
expect(gameConfig.matrix).not.toBeNull;
|
||||||
|
console.log(gameConfig.matrix);
|
||||||
|
expect(gameConfig.maxBufferLength).not.toBeNull;
|
||||||
|
expect(gameConfig.sequences).not.toBeNull;
|
||||||
|
console.log(gameConfig.sequences);
|
||||||
|
expect(gameConfig.timeout).not.toBeNull;
|
||||||
|
});
|
||||||
|
});
|
||||||
252
src/game/MatrixGeneration.ts
Normal file
252
src/game/MatrixGeneration.ts
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
import GameConfiguration from "./GameConfiguration";
|
||||||
|
|
||||||
|
import seedrandom from "seedrandom";
|
||||||
|
|
||||||
|
const minMatrixSize = 3;
|
||||||
|
const maxMatrixSize = 8;
|
||||||
|
|
||||||
|
const minNumberSequences = 2;
|
||||||
|
const maxNumberSequences = 7;
|
||||||
|
const minSequenceLength = 2;
|
||||||
|
|
||||||
|
const minBufferSize = 4;
|
||||||
|
const maxBufferSize = 8;
|
||||||
|
|
||||||
|
const stepsUntilMatrixSizeIncreased = 10;
|
||||||
|
const stepsUntilSequenceNumberIncreased = 3;
|
||||||
|
|
||||||
|
const defaultTimeout = 60_000;
|
||||||
|
|
||||||
|
//TODO see how many different values are there
|
||||||
|
//TODO see how the possible values are defined
|
||||||
|
const numberDifferentMatrixValues = 5;
|
||||||
|
const matrixValues = ["A0", "E9", "4C", "8B", "6F"];
|
||||||
|
const emptyMatrixValue = " ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a game configuration for the current level given the seed which is used
|
||||||
|
* for the PRNG.
|
||||||
|
*
|
||||||
|
* The generated game configuration, see {@link GameConfiguration}, contains
|
||||||
|
* a matrix with random values with a size which corresponds to the current level,
|
||||||
|
* the sequences which are generated randomly and have to be found in the matrix,
|
||||||
|
* the length of the buffer which contains the chosen values from the matrix,
|
||||||
|
* the timeout which is the time a user has to solve the current level.
|
||||||
|
*
|
||||||
|
* @param level The current game level (corresponds directly to the difficulty)
|
||||||
|
* @param seed The seed used to compute the random values of the marix and sequences
|
||||||
|
*/
|
||||||
|
export function generateGameConfig(level: number, seed: string): GameConfiguration {
|
||||||
|
if (level < 1) {
|
||||||
|
throw new RangeError("The level has to be at least 1.");
|
||||||
|
}
|
||||||
|
//the levels probably start at 1, however starting with 0 makes things smoother here
|
||||||
|
level--;
|
||||||
|
|
||||||
|
const seededRNG = seedrandom(seed);
|
||||||
|
const matrixSize: number = getMatrixSize(level);
|
||||||
|
const numberOfSequences: number = getNumberOfSequences(level);
|
||||||
|
|
||||||
|
const matrix: string[] = generateRandomMatrix(matrixSize, seededRNG);
|
||||||
|
const maxBufferLength: number = computeMaxBufferLength(level);
|
||||||
|
const sequences: string[][] = generateSequences(matrix, numberOfSequences, maxBufferLength, seededRNG);
|
||||||
|
const result: GameConfiguration = {
|
||||||
|
matrix: matrix,
|
||||||
|
sequences: sequences,
|
||||||
|
maxBufferLength: maxBufferLength,
|
||||||
|
timeout: defaultTimeout
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeMaxBufferLength(level: number): number {
|
||||||
|
//TODO not sure what might be a good idea
|
||||||
|
//see getNumberOfSequences: every time the number of sequences is increased,
|
||||||
|
//the buffer size is set to the minimum
|
||||||
|
//if the number of sequences is not increased, the buffer length is increased
|
||||||
|
let result: number = minBufferSize;
|
||||||
|
|
||||||
|
if (matrixSizeWasIncreased(level)) {
|
||||||
|
//currently it was still possible to increase the matrix size every x level
|
||||||
|
const intervalLevel: number = level % stepsUntilMatrixSizeIncreased;
|
||||||
|
result += intervalLevel % stepsUntilSequenceNumberIncreased;
|
||||||
|
result = Math.min(result, maxBufferSize);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//the matrix size could not be increased anymore, therefore the number of
|
||||||
|
//the maximum buffer length has to be changed differently
|
||||||
|
result = maxBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateSequences(matrix: string[], numberOfSequences: number, maxBufferLength: number, seededRNG: seedrandom.prng): string[][] {
|
||||||
|
const result: string[][] = new Array(numberOfSequences);
|
||||||
|
for (let i = 0; i < numberOfSequences; i++) {
|
||||||
|
const currentSequenceLength: number = getRandomInt(minSequenceLength, maxBufferLength, seededRNG);
|
||||||
|
result[i] = new Array(currentSequenceLength);
|
||||||
|
fillSequence(result[i], matrix, seededRNG);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillSequence(sequence: string[], matrix: string[], seededRNG: seedrandom.prng): void {
|
||||||
|
const matrixSize = Math.sqrt(matrix.length);
|
||||||
|
const matrixCopy: string[] = Object.assign([], matrix);
|
||||||
|
const sequenceLength = sequence.length;
|
||||||
|
|
||||||
|
let currentLineNumber = 0;
|
||||||
|
let currentColumnNumber = 0;
|
||||||
|
let searchInLine = true;
|
||||||
|
//always start in the first line
|
||||||
|
for (let i = 0; i < sequenceLength; i++) {
|
||||||
|
let matrixIndex = -1;
|
||||||
|
if (searchInLine) {
|
||||||
|
while (matrixIndex == -1) {
|
||||||
|
currentColumnNumber = getRandomInt(0, matrixSize - 1, seededRNG);
|
||||||
|
matrixIndex = getMatrixIndex(matrixSize, currentLineNumber, currentColumnNumber);
|
||||||
|
if (matrixCopy[matrixIndex] == emptyMatrixValue) {
|
||||||
|
matrixIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < sequenceLength - 1 && numberValuesLeftColumn(matrixCopy, currentColumnNumber) < 2) {
|
||||||
|
//there needs to be 2 values left in the chosen column
|
||||||
|
//one for the current sequence value and one for the next
|
||||||
|
matrixIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
searchInLine = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (matrixIndex == -1) {
|
||||||
|
currentLineNumber = getRandomInt(0, matrixSize - 1, seededRNG);
|
||||||
|
|
||||||
|
matrixIndex = getMatrixIndex(matrixSize, currentLineNumber, currentColumnNumber);
|
||||||
|
if (matrixCopy[matrixIndex] == emptyMatrixValue) {
|
||||||
|
matrixIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ensure the chosen column has values left which can be selected
|
||||||
|
if (i < sequenceLength - 1 && numberValuesLeftLine(matrixCopy, currentLineNumber) < 2) {
|
||||||
|
//there needs to be 2 values left in the chosen line
|
||||||
|
//one for the current sequence value and one for the next
|
||||||
|
matrixIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
searchInLine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrixIndex = getMatrixIndex(matrixSize, currentLineNumber, currentColumnNumber);
|
||||||
|
sequence[i] = matrix[matrixIndex];
|
||||||
|
matrixCopy[matrixIndex] = emptyMatrixValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function numberValuesLeftColumn(matrixCopy: string[], columnNumber: number): number {
|
||||||
|
const matrixSize = Math.sqrt(matrixCopy.length);
|
||||||
|
let valuesLeft = 0;
|
||||||
|
for (let i = 0; i < matrixSize; i++) {
|
||||||
|
const matrixIndex = getMatrixIndex(matrixSize, i, columnNumber);
|
||||||
|
if (matrixCopy[matrixIndex] != emptyMatrixValue) {
|
||||||
|
valuesLeft++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
function numberValuesLeftLine(matrixCopy: string[], lineNumber: number): number {
|
||||||
|
const matrixSize = Math.sqrt(matrixCopy.length);
|
||||||
|
let valuesLeft = 0;
|
||||||
|
for (let i = 0; i < matrixSize; i++) {
|
||||||
|
const matrixIndex = getMatrixIndex(matrixSize, lineNumber, i);
|
||||||
|
if (matrixCopy[matrixIndex] != emptyMatrixValue) {
|
||||||
|
valuesLeft++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMatrixIndex(matrixSize: number, lineNumber: number, columnNumber: number): number {
|
||||||
|
return (lineNumber * matrixSize) + columnNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRandomMatrix(matrixSize: number, seededRNG: seedrandom.prng): string[] {
|
||||||
|
const result: string[] = new Array(matrixSize * matrixSize);
|
||||||
|
|
||||||
|
for (let i = 0; i < (matrixSize * matrixSize); i++) {
|
||||||
|
result[i] = randomValue(seededRNG);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random integer in the given interval. Both interval limits are inclusive
|
||||||
|
*
|
||||||
|
* @param min The minimum number to be returned (inclusive)
|
||||||
|
* @param max The maximum number to be returned (inclusive)
|
||||||
|
* @param seededRNG The PRNG given by seedrandom
|
||||||
|
*/
|
||||||
|
function getRandomInt(min: number, max: number, seededRNG: seedrandom.prng): number {
|
||||||
|
//taken from https://stackoverflow.com/questions/1527803/generating-random-whole-numbers-in-javascript-in-a-specific-range
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(seededRNG() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomValue(seededRNG: seedrandom.prng): string {
|
||||||
|
return matrixValues[getRandomInt(0, numberDifferentMatrixValues - 1, seededRNG)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase the matrix size every x levels up to a maximum size
|
||||||
|
*
|
||||||
|
* x is defined in StepsUntilMatrixSizeIncreased
|
||||||
|
*
|
||||||
|
* @param level The current game level (corresponds directly to the difficulty)
|
||||||
|
*/
|
||||||
|
//TODO see if this is a clever way to increase the matrix size
|
||||||
|
function getMatrixSize(level: number): number {
|
||||||
|
const size: number = minMatrixSize + Math.floor(level / stepsUntilMatrixSizeIncreased);
|
||||||
|
return Math.min(size, maxMatrixSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the number of sequences for the given level.
|
||||||
|
*
|
||||||
|
* @param level The current game level (corresponds directly to the difficulty)
|
||||||
|
*/
|
||||||
|
//TODO It would suffice to give the level as param, as the matrix size can be computed
|
||||||
|
//What is the best practice in this context?
|
||||||
|
function getNumberOfSequences(level: number): number {
|
||||||
|
//TODO not sure what might be a good idea
|
||||||
|
let result: number = minNumberSequences;
|
||||||
|
|
||||||
|
if (matrixSizeWasIncreased(level)) {
|
||||||
|
//currently it was still possible to increase the matrix size every x level
|
||||||
|
const intervalLevel: number = level % stepsUntilMatrixSizeIncreased;
|
||||||
|
result += Math.floor(intervalLevel / stepsUntilSequenceNumberIncreased);
|
||||||
|
result = Math.min(result, maxNumberSequences);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//the matrix size could not be increased anymore, therefore the number of
|
||||||
|
//sequences has to be changed differently
|
||||||
|
result = maxNumberSequences;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently it was still possible to increase the matrix size every x level
|
||||||
|
*
|
||||||
|
* @param level The current game level (corresponds directly to the difficulty)
|
||||||
|
*/
|
||||||
|
function matrixSizeWasIncreased(level: number): boolean {
|
||||||
|
return level < maxMatrixSize * (stepsUntilMatrixSizeIncreased + 1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user