// Game state and manipulation of it
/**
* Represents a complete game state used by game
*/
class GameState {
constructor() {
this.saved_games = []
this.ranking = []
this.user_levels = []
this.paused_user_levels = []
this.next_user_level_index = 0
}
}
/**
* Represents progress of passing all levels from Module 2
*/
class Game {
/**
*
* @param {string} name
* @param {Level} level
*/
constructor(name, level) {
this.name = name
this.level = level
this.score = 0
}
}
/** Creates independent clone of the game
*
* @param {Game} game
*/
function clone_game(game) {
let obj = new Game(game.name, clone_level(game.level))
obj.score = game.score
return obj
}
class RankingEntry {
/**
*
* @param {string} name
* @param {number} score
*/
constructor(name, score) {
this.name = name
this.score = score
}
}
/**
* Splits level by set difficulty.
* If level's difficulty is undefined it's ignored
*
* @param {Level[]} levels Array of levels to split
* @return {LevelsByDiffcutly}
*/
function split_levels_by_difficulty(levels) {
return {
easy: levels.filter(e => e.difficulty == EASY),
medium: levels.filter(e => e.difficulty == MEDIUM),
hard: levels.filter(e => e.difficulty == HARD),
}
}
/** Removes game from saved and inserts score into ranking
* @param {Game} game
* @param {GameState} game_state
*/
function move_game_to_ranking(game, game_state) {
let ranking_entry = new RankingEntry(game.name, game.score)
remove_saved_game(game, game_state)
insert_into_ranking(ranking_entry, game_state.ranking)
}
/** Saves game into game_state
*
* @param {Game} game
* @param {GameState} game_state
*/
function save_game(game, game_state) {
game = clone_game(game)
let index = get_saved_game_index_by_name(game.name, game_state)
if (index == undefined)
game_state.saved_games.push(game)
else
game_state.saved_games[index] = game
}
/**
* Removes given game from game state if present
* @param {Game} game
* @param {GameState} game_state
*/
function remove_saved_game(game, game_state) {
game_index = get_saved_game_index_by_name(game.name, game_state)
if (game_index != undefined)
game_state.saved_games.splice(game_index, 1)
}
function get_saved_game_index_by_name(name, game_state) {
for (let i = 0; i < game_state.saved_games.length; i++)
if (name == game_state.saved_games[i].name)
return i
}
/**
* Inserts given entry into ranking
* @param {RankingEntry} entry
* @param {RankingEntry[]} ranking
*/
function insert_into_ranking(entry, ranking) {
ranking.push(entry)
ranking.sort((a, b) => a.score < b.score)
}
/**
* Removes given entry from ranking
* @param {RankingEntry} entry
* @param {RankingEntry[]} ranking
*/
function remove_from_ranking(entry, ranking) {
let index = ranking.indexOf(entry)
ranking.splice(index, 1)
}
/** Saves level created by user and sets its paused state
*
* @param {Level} level
* @param {GameState} game_state
*/
function save_user_level(level, game_state) {
if (level.index == undefined)
save_new_user_level(level, game_state)
else {
for (let i = 0; i < game_state.user_levels.length; i++)
if (game_state.user_levels[i].index == level.index)
game_state.user_levels[i] = clone_level(level)
save_paused_user_level(level, game_state)
}
}
/** Saves paused level created by user
*
* @param {Level} level
* @param {GameState} game_state
*/
function save_paused_user_level(level, game_state) {
level = clone_level(level)
for (let i = 0; i < game_state.paused_user_levels.length; i++)
if (game_state.paused_user_levels[i].index == level.index)
game_state.paused_user_levels[i] = level
}
/** Creates new level in game_state
* Sets provided level index
*
* @param {Level} level
* @param {GameState} game_state
*/
function save_new_user_level(level, game_state) {
level.index = game_state.next_user_level_index
level = clone_level(level)
game_state.next_user_level_index += 1
game_state.user_levels.push(level)
game_state.paused_user_levels.push(level)
}
/** Removes level from levels created by user
* and from paused levels
*
* @param {Level} level
* @param {GameState} game_state
*/
function remove_user_level(level, game_state) {
let index = undefined
for (let i = 0; i < game_state.user_levels.length; i++)
if (game_state.user_levels[i].index == level.index)
index = i
if (index != undefined)
game_state.user_levels.splice(index, 1)
remove_paused_user_level(level, game_state)
}
/** Removes level from paused levels created by user
*
* @param {Level} level
* @param {GameState} game_state
*/
function remove_paused_user_level(level, game_state) {
let index = undefined
for (let i = 0; i < game_state.paused_user_levels.length; i++)
if (game_state.paused_user_levels[i].index == level.index)
index = i
if (index != undefined)
game_state.paused_user_levels.splice(index, 1)
}
/** Returns user level by given index.
* Level is presented in the state it was saved in editor.
* IOW, as it was never played on
* @param {number} index
* @param {GameState} game_state
*/
function get_user_level_by_index(index, game_state) {
for (let level of game_state.user_levels)
if (level.index == index)
return level
}
/** Returns user level by given name
* Level is presented in the state it was saved in editor,
* IOW, as it was never played on
* @param {string} name
* @param {GameState} game_state
*/
function get_user_level_by_name(name, game_state) {
for (let level of game_state.user_levels)
if (level.name = name)
return level
}
class BasicGameSaver {
constructor(game, game_state) {
this.game = game;
this.game_state = game_state
}
save_game(game) {
save_game(game, this.game_state)
save_game_state(this.game_state)
}
save_level(level) {
this.game.level = level
this.save_game(this.game)
}
finish_game(game) {
move_game_to_ranking(game, this.game_state)
save_game_state(this.game_state)
}
}