More changes
This commit is contained in:
parent
dcfc55f2b0
commit
e0b05b3aa6
324
src/js/Bingo.ts
324
src/js/Bingo.ts
@ -1,324 +0,0 @@
|
|||||||
import {
|
|
||||||
Exclude,
|
|
||||||
Expose,
|
|
||||||
Type,
|
|
||||||
instanceToPlain,
|
|
||||||
plainToClass,
|
|
||||||
plainToInstance
|
|
||||||
} from 'class-transformer';
|
|
||||||
|
|
||||||
function stringCompare(a: string, b: string) {
|
|
||||||
return a.localeCompare(b, undefined, {
|
|
||||||
sensitivity: 'accent'
|
|
||||||
}) === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BingoGame {
|
|
||||||
id!: string;
|
|
||||||
|
|
||||||
name!: string;
|
|
||||||
|
|
||||||
short_description!: string;
|
|
||||||
|
|
||||||
description!: string;
|
|
||||||
|
|
||||||
generator: 'simple' | 'srl_v5' | 'srl_v8' = 'simple';
|
|
||||||
|
|
||||||
@Type(() => BingoGoal)
|
|
||||||
goals: BingoGoal[] = [];
|
|
||||||
|
|
||||||
@Type(() => BingoGroup)
|
|
||||||
groups: BingoGroup[] = [];
|
|
||||||
|
|
||||||
constructor(id: string, name: string, short_description: string, description: string) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.short_description = short_description;
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
addGoal(goal: BingoGoal): void {
|
|
||||||
if (this.goals.some(_goal => stringCompare(_goal.name, goal.name)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.goals.push(goal);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeGoal(goal: BingoGoal): void {
|
|
||||||
this.goals = this.goals.filter(_goal => !stringCompare(_goal.name, goal.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
removeGoalByName(name: string): void {
|
|
||||||
const goal = this.goals.find(goal => stringCompare(goal.name, name));
|
|
||||||
|
|
||||||
if (goal)
|
|
||||||
this.removeGoal(goal);
|
|
||||||
}
|
|
||||||
|
|
||||||
addGroup(group: BingoGroup): void {
|
|
||||||
/*
|
|
||||||
* TODO: Right now we can do circular groups.
|
|
||||||
* 1.parent = 2, 2.parent = 1
|
|
||||||
* This will loop the objects infinitely.
|
|
||||||
* Make sure that going through the tree we don't have this problem.
|
|
||||||
*
|
|
||||||
* Option B:
|
|
||||||
* Trash idea of groups-in-groups (parent system)
|
|
||||||
* Just have groups and be done with them.
|
|
||||||
*
|
|
||||||
* Option C:
|
|
||||||
* Bring back categories so we have categories + groups.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (this.groups.some(_group => stringCompare(_group.name, group.name)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.groups.push(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeGroup(group: BingoGroup): boolean {
|
|
||||||
// Group has parent, don't delete
|
|
||||||
const isParent = this.groups.find(
|
|
||||||
_group => _group.parent && stringCompare(_group.parent.name, group.name)
|
|
||||||
);
|
|
||||||
if (isParent) {
|
|
||||||
console.error('This group is still a parent of:', isParent.name);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// One or more goals still use this group, don't delete
|
|
||||||
const isGoal = this.goals.find(
|
|
||||||
goal => goal.group && stringCompare(goal.group.name, group.name)
|
|
||||||
);
|
|
||||||
if (isGoal) {
|
|
||||||
console.error('This group is still used by:', isGoal.name);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.groups = this.groups.filter(_group => !stringCompare(_group.name, group.name));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeGroupByName(name: string): boolean {
|
|
||||||
const group = this.groups.find(group => stringCompare(group.name, name));
|
|
||||||
|
|
||||||
return group ? this.removeGroup(group) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getGroupByName(name: string): BingoGroup | undefined {
|
|
||||||
return this.groups.find(group => stringCompare(group.name, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
getGoalsByTags(...tags: string[]): BingoGoal[] {
|
|
||||||
return this.goals.filter(
|
|
||||||
goal => goal.tags.some(
|
|
||||||
_tag => tags.some(
|
|
||||||
tag => stringCompare(_tag, tag)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getGoalsByGroup(includeParents: boolean, ...groups: BingoGroup[]): BingoGoal[] {
|
|
||||||
const result: BingoGoal[] = [];
|
|
||||||
|
|
||||||
this.goals.map(goal => {
|
|
||||||
const goal_group = goal.group;
|
|
||||||
|
|
||||||
if (includeParents) {
|
|
||||||
let parent = goal_group.parent;
|
|
||||||
while (parent) {
|
|
||||||
if (groups.includes(parent)) {
|
|
||||||
result.push(goal);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = parent.parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groups.includes(goal_group)) {
|
|
||||||
result.push(goal);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandomInt(max: number): number {
|
|
||||||
return Math.floor(Math.random() * max);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BingoGoal {
|
|
||||||
// id: string; // uuid-by-string maybe? https://www.npmjs.com/package/uuid-by-string
|
|
||||||
|
|
||||||
name!: string;
|
|
||||||
|
|
||||||
@Exclude({
|
|
||||||
toPlainOnly: true
|
|
||||||
})
|
|
||||||
@Type(() => BingoGroup)
|
|
||||||
group!: BingoGroup;
|
|
||||||
|
|
||||||
tags: string[] = [];
|
|
||||||
|
|
||||||
possible_spaces: number[] = [];
|
|
||||||
|
|
||||||
constructor(name: string, group: BingoGroup) {
|
|
||||||
this.name = name;
|
|
||||||
this.group = group;
|
|
||||||
|
|
||||||
for (let i = 0; i < 25; i++) {
|
|
||||||
if (getRandomInt(2) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.possible_spaces.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Expose()
|
|
||||||
get group_id(): string {
|
|
||||||
return this.group.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
addTag(tag: string): BingoGoal {
|
|
||||||
if (this.tags.includes(tag))
|
|
||||||
return this;
|
|
||||||
|
|
||||||
this.tags.push(tag);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTag(tag: string): BingoGoal {
|
|
||||||
this.tags = this.tags.filter(_tag => !stringCompare(_tag, tag));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
setGroup(group: BingoGroup) {
|
|
||||||
this.group = group;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPossibleSpaces(possible_spaces: number[]) {
|
|
||||||
this.possible_spaces = possible_spaces;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BingoGroup {
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
// @Exclude({
|
|
||||||
// toPlainOnly: true
|
|
||||||
// })
|
|
||||||
// @Type(() => BingoGroup)
|
|
||||||
#parent?: BingoGroup;
|
|
||||||
|
|
||||||
constructor(name: string, parent?: BingoGroup | undefined) {
|
|
||||||
this.name = name;
|
|
||||||
this.#parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Exclude()
|
|
||||||
get parent(): BingoGroup | undefined {
|
|
||||||
return this.#parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Expose()
|
|
||||||
get parent_id(): string | undefined {
|
|
||||||
return this.#parent?.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
function test(): void {
|
|
||||||
const game = new BingoGame(
|
|
||||||
'yakuza_0',
|
|
||||||
'Yakuza 0',
|
|
||||||
'The funny game we used for all bingos.',
|
|
||||||
'Very long text here haha lmao'
|
|
||||||
);
|
|
||||||
|
|
||||||
const group1 = new BingoGroup('1');
|
|
||||||
const group2 = new BingoGroup('2', group1);
|
|
||||||
// group1.parent = group2;
|
|
||||||
// group2.parent = group1;
|
|
||||||
|
|
||||||
game.addGroup(group1);
|
|
||||||
game.addGroup(group2);
|
|
||||||
|
|
||||||
const jsonifiedInstance = instanceToPlain(game, {
|
|
||||||
enableCircularCheck: true
|
|
||||||
});
|
|
||||||
const fixed = JSON.parse(JSON.stringify(jsonifiedInstance));
|
|
||||||
console.log(JSON.stringify([ fixed ]));
|
|
||||||
|
|
||||||
// const group1 = new BingoGroup('1');
|
|
||||||
// const group2 = new BingoGroup('2', group1);
|
|
||||||
// const group3 = new BingoGroup('3', group2);
|
|
||||||
|
|
||||||
// game.addGroup(group1);
|
|
||||||
// game.addGroup(group2);
|
|
||||||
// game.addGroup(group3);
|
|
||||||
|
|
||||||
// const battle_group = new BingoGroup('Battle');
|
|
||||||
// const defeat_enemies = new BingoGroup('Defeat enemies on the street', battle_group);
|
|
||||||
// game.addGroup(battle_group);
|
|
||||||
// game.addGroup(defeat_enemies);
|
|
||||||
|
|
||||||
// const easy = new BingoGoal('Defeat 50 enemies on the street', group1).addTag('Easy');
|
|
||||||
// const normal = new BingoGoal('Defeat 150 enemies on the street', group2).addTag('Normal');
|
|
||||||
// const hard = new BingoGoal('Defeat 300 enemies on the street', group3).addTag('Hard');
|
|
||||||
|
|
||||||
// game.addGoal(easy);
|
|
||||||
// game.addGoal(normal);
|
|
||||||
// game.addGoal(hard);
|
|
||||||
|
|
||||||
// console.log(game.goals[0].group);
|
|
||||||
// game.groups[0].name = 'not 1';
|
|
||||||
// game.groups[0].parent = game.groups[1];
|
|
||||||
// console.log(game.goals[0].group);
|
|
||||||
|
|
||||||
// const jsonifiedInstance = instanceToPlain(game);
|
|
||||||
// const fixed = JSON.parse(JSON.stringify(jsonifiedInstance));
|
|
||||||
// console.log(JSON.stringify([ fixed ]));
|
|
||||||
// console.log(JSON.stringify(game));
|
|
||||||
|
|
||||||
// const got_group1 = game.getGroupByName('1');
|
|
||||||
// console.log(got_group1);
|
|
||||||
|
|
||||||
// const got_group3 = game.getGroupByName('3');
|
|
||||||
// console.log(got_group3);
|
|
||||||
|
|
||||||
// console.log(got_group1 === got_group3?.parent?.parent);
|
|
||||||
|
|
||||||
// const jsonifiedString = JSON.stringify(jsonifiedInstance);
|
|
||||||
// const parsedInstance: JSON = JSON.parse(jsonifiedString);
|
|
||||||
|
|
||||||
// const parsedgame = plainToClass(BingoGame, parsedInstance);
|
|
||||||
// console.log(parsedgame);
|
|
||||||
// console.log(parsedgame === game);
|
|
||||||
|
|
||||||
// const got_group1 = parsedgame.getGroupByName('1');
|
|
||||||
// console.log(got_group1);
|
|
||||||
|
|
||||||
// const got_group3 = parsedgame.getGroupByName('3');
|
|
||||||
// console.log(got_group3);
|
|
||||||
|
|
||||||
// console.log(got_group1 === got_group3?.parent?.parent);
|
|
||||||
|
|
||||||
// const json_string = '{"id":"yakuza_0","name":"Yakuza 0","description":"The funny game we used for all bingos.","generator":"simple","goals":[{"name":"Defeat 50 enemies on the street","tags":["Easy"],"group":{"name":"Defeat enemies on the street","parent":{"name":"Battle"}},"possible_spaces":[]},{"name":"Defeat 150 enemies on the street","tags":["Normal"],"group":{"name":"Defeat enemies on the street","parent":{"name":"Battle"}},"possible_spaces":[]},{"name":"Defeat 300 enemies on the street","tags":["Hard"],"group":{"name":"Defeat enemies on the street","parent":{"name":"Battle"}},"possible_spaces":[]}],"groups":[{"name":"Battle"},{"name":"Defeat enemies on the street","parent":{"name":"Battle"}}]}';
|
|
||||||
// const parsed: JSON = JSON.parse(json_string);
|
|
||||||
// const parsed_game = plainToInstance(BingoGame, parsed);
|
|
||||||
// console.log(parsed_game);
|
|
||||||
// console.log(JSON.stringify(other_game) === JSON.stringify(jsonifiedInstance));
|
|
||||||
|
|
||||||
// parsed_game.removeGroup(defeat_enemies);
|
|
||||||
// console.log(parsed_game.goals);
|
|
||||||
}
|
|
||||||
test();
|
|
@ -1,8 +1,5 @@
|
|||||||
// Example code to convert the old format to the new one
|
// Example code to convert the old format to the new one
|
||||||
|
|
||||||
import {
|
|
||||||
BingoGame, BingoGoal, BingoGroup
|
|
||||||
} from '@/js/Bingo.js';
|
|
||||||
import json from './games.json';
|
import json from './games.json';
|
||||||
import new_json from './new_games.json';
|
import new_json from './new_games.json';
|
||||||
import {
|
import {
|
||||||
@ -10,6 +7,9 @@ import {
|
|||||||
} from 'class-transformer';
|
} from 'class-transformer';
|
||||||
|
|
||||||
import markdown_text from '@/js/testmarkdown.js';
|
import markdown_text from '@/js/testmarkdown.js';
|
||||||
|
import BingoGame from '@/js/lib/BingoGame.ts';
|
||||||
|
import BingoGroup from '@/js/lib/BingoGroup.ts';
|
||||||
|
import BingoGoal from '@/js/lib/BingoGoal.ts';
|
||||||
|
|
||||||
export const games: Map<string, BingoGame> = new Map;
|
export const games: Map<string, BingoGame> = new Map;
|
||||||
|
|
||||||
@ -68,19 +68,27 @@ function run_new_format() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const group_map: Map<string, BingoGroup> = new Map;
|
const group_map: Map<string, BingoGroup> = new Map;
|
||||||
|
const group_to_group_map: Map<BingoGroup, string> = new Map;
|
||||||
for (const j_group of j_game.groups) {
|
for (const j_group of j_game.groups) {
|
||||||
let group: BingoGroup;
|
const group = new BingoGroup(j_group.name);
|
||||||
if (j_group.parent_id)
|
if (j_group.parent_id)
|
||||||
group = new BingoGroup(j_group.name, group_map.get(
|
group_to_group_map.set(group, j_group.parent_id);
|
||||||
j_group.parent_id
|
|
||||||
));
|
|
||||||
else
|
|
||||||
group = new BingoGroup(j_group.name);
|
|
||||||
|
|
||||||
group_map.set(j_group.name, group);
|
group_map.set(j_group.name, group);
|
||||||
game.addGroup(group);
|
game.addGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const [
|
||||||
|
group,
|
||||||
|
parent_id
|
||||||
|
] of group_to_group_map) {
|
||||||
|
const parent = group_map.get(parent_id);
|
||||||
|
if (!parent)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
group.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
for (const j_goal of j_game.goals) {
|
for (const j_goal of j_game.goals) {
|
||||||
const group = group_map.get(j_goal.group_id);
|
const group = group_map.get(j_goal.group_id);
|
||||||
if (!group)
|
if (!group)
|
||||||
@ -97,4 +105,4 @@ function run_new_format() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// run_new_format();
|
run_new_format();
|
||||||
|
167
src/js/lib/BingoGame.ts
Normal file
167
src/js/lib/BingoGame.ts
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
|
||||||
|
import BingoGoal from '@/js/lib/BingoGoal.ts';
|
||||||
|
import BingoGroup from '@/js/lib/BingoGroup.ts';
|
||||||
|
import type SuccessResponse from '@/js/lib/SuccessResponse.ts';
|
||||||
|
import Util from '@/js/lib/Util.ts';
|
||||||
|
import {
|
||||||
|
Type,
|
||||||
|
instanceToPlain
|
||||||
|
} from 'class-transformer';
|
||||||
|
|
||||||
|
export default class BingoGame {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
short_description: string;
|
||||||
|
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
generator: 'simple' | 'srl_v5' | 'srl_v8' = 'simple';
|
||||||
|
|
||||||
|
@Type(() => BingoGoal)
|
||||||
|
goals: BingoGoal[] = [];
|
||||||
|
|
||||||
|
@Type(() => BingoGroup)
|
||||||
|
groups: BingoGroup[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
short_description: string,
|
||||||
|
description: string
|
||||||
|
) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.short_description = short_description;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
addGoal(goal: BingoGoal): SuccessResponse {
|
||||||
|
const existingGoal = this.goals.find(g => g === goal);
|
||||||
|
if (existingGoal) {
|
||||||
|
return Util.returnSuccess(false, 'A goal with this name already exists');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.goals.push(goal);
|
||||||
|
|
||||||
|
return Util.returnSuccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeGoal(goal: BingoGoal): SuccessResponse {
|
||||||
|
const filteredGoals = this.goals.filter(g => g !== goal);
|
||||||
|
if (filteredGoals.length === this.goals.length) {
|
||||||
|
return Util.returnSuccess(false, 'Goal not found');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.goals = filteredGoals;
|
||||||
|
|
||||||
|
return Util.returnSuccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeGoalByName(name: string): SuccessResponse {
|
||||||
|
const goal = this.goals.find(g => g.name === name);
|
||||||
|
if (!goal) {
|
||||||
|
return Util.returnSuccess(false, 'Goal not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.removeGoal(goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
addGroup(group: BingoGroup): SuccessResponse {
|
||||||
|
const existingGroup = this.groups.find(g => g === group);
|
||||||
|
if (existingGroup) {
|
||||||
|
return Util.returnSuccess(false, 'A group with this name already exists');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.groups.push(group);
|
||||||
|
|
||||||
|
return Util.returnSuccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeGroup(group: BingoGroup): SuccessResponse {
|
||||||
|
const filteredGroups = this.groups.filter(g => g !== group);
|
||||||
|
if (filteredGroups.length === this.groups.length) {
|
||||||
|
return Util.returnSuccess(false, 'Group not found');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Check if any group has the given group as its parent
|
||||||
|
const hasParent = this.groups.some(g => g.parent === group);
|
||||||
|
if (hasParent) {
|
||||||
|
// Add the group back to the list of groups
|
||||||
|
this.groups.push(group);
|
||||||
|
|
||||||
|
return Util.returnSuccess(false, 'Cannot delete group as it is a parent of another group');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.groups = filteredGroups;
|
||||||
|
|
||||||
|
return Util.returnSuccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeGroupByName(name: string): SuccessResponse {
|
||||||
|
const group = this.groups.find(g => g.name === name);
|
||||||
|
if (!group) {
|
||||||
|
return Util.returnSuccess(false, 'Group not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.removeGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
getGoalsByTags(...tags: string[]): BingoGoal[] {
|
||||||
|
return this.goals.filter(goal =>
|
||||||
|
tags.some(
|
||||||
|
tag => goal.tags.some(
|
||||||
|
goalTag => Util.stringCompare(goalTag, tag)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
getGoalsByGroup(includeParents: boolean, ...groups: BingoGroup[]): BingoGoal[] {
|
||||||
|
const result: BingoGoal[] = [];
|
||||||
|
|
||||||
|
this.goals.map(goal => {
|
||||||
|
const goal_group = goal.group;
|
||||||
|
|
||||||
|
if (includeParents) {
|
||||||
|
let parent = goal_group.parent;
|
||||||
|
while (parent) {
|
||||||
|
if (groups.includes(parent)) {
|
||||||
|
result.push(goal);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groups.includes(goal_group)) {
|
||||||
|
result.push(goal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): Record<string, any> {
|
||||||
|
this.groups.sort((a, b) => {
|
||||||
|
if (!a.parent && b.parent) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.parent && !b.parent) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return instanceToPlain(this);
|
||||||
|
}
|
||||||
|
}
|
61
src/js/lib/BingoGoal.ts
Normal file
61
src/js/lib/BingoGoal.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
import type SuccessResponse from '@/js/lib/SuccessResponse.js';
|
||||||
|
import BingoGroup from './BingoGroup';
|
||||||
|
import Util from './Util';
|
||||||
|
import {
|
||||||
|
Exclude, Type, Expose
|
||||||
|
} from 'class-transformer';
|
||||||
|
|
||||||
|
export default class BingoGoal {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Exclude({
|
||||||
|
toPlainOnly: true
|
||||||
|
})
|
||||||
|
@Type(() => BingoGroup)
|
||||||
|
group: BingoGroup;
|
||||||
|
|
||||||
|
tags: string[];
|
||||||
|
|
||||||
|
possible_spaces: number[];
|
||||||
|
|
||||||
|
constructor(name: string, group: BingoGroup) {
|
||||||
|
this.name = name;
|
||||||
|
this.group = group;
|
||||||
|
this.tags = [];
|
||||||
|
this.possible_spaces = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
get group_id(): string {
|
||||||
|
return this.group.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTag(tag: string): SuccessResponse {
|
||||||
|
if (this.tags.some(
|
||||||
|
existingTag => Util.stringCompare(existingTag, tag)
|
||||||
|
)) {
|
||||||
|
return Util.returnSuccess(false, 'Tag already exists');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.tags.push(tag);
|
||||||
|
|
||||||
|
return Util.returnSuccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeTag(tag: string): SuccessResponse {
|
||||||
|
if (!this.tags.some(
|
||||||
|
existingTag => Util.stringCompare(existingTag, tag)
|
||||||
|
)) {
|
||||||
|
return Util.returnSuccess(false, 'Tag doesn\'t exist');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.tags = this.tags.filter(
|
||||||
|
existingTag => !Util.stringCompare(existingTag, tag)
|
||||||
|
);
|
||||||
|
|
||||||
|
return Util.returnSuccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/js/lib/BingoGroup.ts
Normal file
47
src/js/lib/BingoGroup.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
Expose, Exclude
|
||||||
|
} from 'class-transformer';
|
||||||
|
|
||||||
|
export default class BingoGroup {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
#parent?: BingoGroup;
|
||||||
|
|
||||||
|
constructor(name: string, parent?: BingoGroup) {
|
||||||
|
this.name = name;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Exclude()
|
||||||
|
get parent(): BingoGroup | undefined {
|
||||||
|
return this.#parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
set parent(newParent: BingoGroup | undefined) {
|
||||||
|
if (newParent === this) {
|
||||||
|
throw new Error('A BingoGroup cannot be a parent of itself.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!newParent) {
|
||||||
|
// this.#parent = undefined;
|
||||||
|
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let temp = newParent;
|
||||||
|
while (temp) {
|
||||||
|
if (temp === this) {
|
||||||
|
throw new Error('Circular reference detected.');
|
||||||
|
}
|
||||||
|
temp = temp.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#parent = newParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
get parent_id(): string | undefined {
|
||||||
|
return this.#parent?.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
21
src/js/lib/SuccessResponse.ts
Normal file
21
src/js/lib/SuccessResponse.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export default class SuccessResponse {
|
||||||
|
#success: boolean;
|
||||||
|
|
||||||
|
#message: string | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
success: boolean,
|
||||||
|
message?: string
|
||||||
|
) {
|
||||||
|
this.#success = success;
|
||||||
|
this.#message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
get success(): boolean {
|
||||||
|
return this.#success;
|
||||||
|
}
|
||||||
|
|
||||||
|
get message(): string | undefined {
|
||||||
|
return this.#message;
|
||||||
|
}
|
||||||
|
}
|
13
src/js/lib/Util.ts
Normal file
13
src/js/lib/Util.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import SuccessResponse from './SuccessResponse';
|
||||||
|
|
||||||
|
export default class Util {
|
||||||
|
static stringCompare(str1: string, str2: string): boolean {
|
||||||
|
return str1.localeCompare(str2, undefined, {
|
||||||
|
sensitivity: 'accent'
|
||||||
|
}) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static returnSuccess(success: boolean, message?: string): SuccessResponse {
|
||||||
|
return new SuccessResponse(success, message);
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@
|
|||||||
},
|
},
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true,
|
||||||
|
"allowImportingTsExtensions": true
|
||||||
},
|
},
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user