issue-5-product-gamesystems #10
@ -21,3 +21,30 @@ jobs:
|
|||||||
|
|
||||||
- name: Run e2e tests
|
- name: Run e2e tests
|
||||||
run: npm run e2e
|
run: npm run e2e
|
||||||
|
|
||||||
|
- name: ntfy-notifications-failure
|
||||||
|
uses: niniyas/ntfy-action@master
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
url: ${{ secrets.NTFY_URL }}
|
||||||
|
topic: ${{ secrets.NTFY_TOPIC }}
|
||||||
|
priority: 5
|
||||||
|
headers: '{"authorization": "${{ secrets.NTFY_HEADERS }}"}'
|
||||||
|
tags: -1,rotating_light,action,failed,
|
||||||
|
details: Workflow has failed!
|
||||||
|
icon: 'https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png'
|
||||||
|
image: true
|
||||||
|
|
||||||
|
- name: ntfy-notifications-success
|
||||||
|
uses: niniyas/ntfy-action@master
|
||||||
|
if: success()
|
||||||
|
with:
|
||||||
|
url: ${{ secrets.NTFY_URL }}
|
||||||
|
topic: ${{ secrets.NTFY_TOPIC }}
|
||||||
|
priority: 4
|
||||||
|
headers: '{"authorization": "${{ secrets.NTFY_HEADERS }}"}'
|
||||||
|
tags: +1,partying_face,action,successfully,completed
|
||||||
|
details: Workflow has been successfully completed!
|
||||||
|
icon: 'https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png'
|
||||||
|
image: true
|
||||||
|
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import * as PATH from 'path';
|
||||||
|
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||||
|
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
|
||||||
|
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
|
||||||
|
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
|
||||||
|
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import exp = require("node:constants");
|
||||||
|
import {end} from "electron-debug";
|
||||||
|
import {GamesystemTrainer} from "./GamesystemTrainer";
|
||||||
|
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {ProductStateTrainer} from "./ProductStateTrainer";
|
||||||
|
import {SimpleState} from "../../../../src/app/game-model/gamesystems/SimpleState";
|
||||||
|
test.describe('Test Create ProductStates', () => {
|
||||||
|
|
||||||
|
test("Adding already existent ProductState", async () => {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
const result = gamesystem.createState(gamesystem.states[0].innerStates);
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
expect(gamesystem.states.length).toEqual(4);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test empty inputs for ProductState Creation", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createState([])).toBeUndefined();
|
||||||
|
expect(gamesystem.states.length).toEqual(4);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test invalid inputs for ProductState Creation", async () => {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createState([ProductStateTrainer.givenUnusedInnerStates(gamesystem)[0]])).toBeUndefined();
|
||||||
|
expect(gamesystem.states.length).toEqual(4);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test ProductState Creation with foreign State", async () => {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
const simpleState = new SimpleState(ProductStateTrainer.INNERSTATE_LETTER_3);
|
||||||
|
expect(gamesystem.createState([simpleState])).toBeUndefined();
|
||||||
|
expect(gamesystem.states.length).toEqual(4);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test valid ProductStateCreation", async () => {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createState(ProductStateTrainer.givenUnusedInnerStates(gamesystem))).toBeDefined();
|
||||||
|
expect(gamesystem.states.length).toEqual(5);
|
||||||
|
})
|
||||||
|
});
|
@ -0,0 +1,51 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import {ProductStateTrainer} from "./ProductStateTrainer";
|
||||||
|
import {ProductState} from "../../../../src/app/game-model/gamesystems/ProductState";
|
||||||
|
import {SimpleGamesystem} from "../../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||||
|
test.describe('Test Create ProductTransitions', () => {
|
||||||
|
test("Test ProductTransition Creation with invalid inputs", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createTransition(null, null)).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
expect(gamesystem.createTransition(undefined, undefined)).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
|
||||||
|
expect(gamesystem.createTransition(undefined, gamesystem.states[0])).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
expect(gamesystem.createTransition(null, gamesystem.states[0])).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
|
||||||
|
expect(gamesystem.createTransition(gamesystem.states[0], undefined)).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
expect(gamesystem.createTransition(gamesystem.states[0], null)).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test ProductTransitition Creation with duplicate Transition", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createTransition(gamesystem.states[0], gamesystem.states[1])).toBeUndefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test ProductTransition Creation with foreign States", async () => {
|
||||||
|
const simpleGamesystems: SimpleGamesystem[] = [new SimpleGamesystem("Test", "Test"), new SimpleGamesystem("Test1", "Test2")];
|
||||||
|
const simpleGamesystem2: SimpleGamesystem[] = [new SimpleGamesystem("Test3", "Test"), new SimpleGamesystem("Test4", "Test2")];
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
const foreignProductState = new ProductState(simpleGamesystems);
|
||||||
|
const foreignEndProductState = new ProductState(simpleGamesystem2);
|
||||||
|
|
||||||
|
expect(gamesystem.createTransition(foreignProductState, foreignEndProductState)).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test creating SelfTransitions", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createTransition(gamesystem.states[0], gamesystem.states[0])).toBeUndefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(3);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test Valid Transition Creation", async () => {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.createTransition(gamesystem.states[1], gamesystem.states[2])).toBeDefined();
|
||||||
|
expect(gamesystem.transitions.length).toEqual(4)
|
||||||
|
})
|
||||||
|
});
|
@ -0,0 +1,37 @@
|
|||||||
|
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import * as PATH from 'path';
|
||||||
|
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||||
|
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
|
||||||
|
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
|
||||||
|
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
|
||||||
|
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import exp = require("node:constants");
|
||||||
|
import {end} from "electron-debug";
|
||||||
|
import {GamesystemTrainer} from "./GamesystemTrainer";
|
||||||
|
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {ProductStateTrainer} from "./ProductStateTrainer";
|
||||||
|
import {SimpleState} from "../../../../src/app/game-model/gamesystems/SimpleState";
|
||||||
|
test.describe('Test Check Equal of Innerstates', () => {
|
||||||
|
|
||||||
|
test("Test invalid input for equal checking", async()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.states[0].equalInnerStates(null)).toBeFalsy();
|
||||||
|
expect(gamesystem.states[0].equalInnerStates(undefined)).toBeFalsy();
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test empty input for equal checking", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.states[0].equalInnerStates([])).toBeFalsy();
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test identical inner states for equal", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.states[0].equalInnerStates(gamesystem.states[0].innerStates)).toBeTruthy();
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test slightly derivating inner states for Equal", async ()=> {
|
||||||
|
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();
|
||||||
|
expect(gamesystem.states[0].equalInnerStates(gamesystem.states[1].innerStates)).toBeFalsy();
|
||||||
|
})
|
||||||
|
});
|
@ -0,0 +1,34 @@
|
|||||||
|
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import * as PATH from 'path';
|
||||||
|
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||||
|
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
|
||||||
|
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
|
||||||
|
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
|
||||||
|
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import exp = require("node:constants");
|
||||||
|
import {end} from "electron-debug";
|
||||||
|
import {GamesystemTrainer} from "./GamesystemTrainer";
|
||||||
|
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {ProductStateTrainer} from "./ProductStateTrainer";
|
||||||
|
import {SimpleState} from "../../../../src/app/game-model/gamesystems/SimpleState";
|
||||||
|
import {ProductSystemGenerationTrainer} from "./ProductSystemGenerationTrainer";
|
||||||
|
test.describe('Test Create ProductStates', () => {
|
||||||
|
|
||||||
|
test("Test simple Binary Product State", async () => {
|
||||||
|
const gamesystem = ProductSystemGenerationTrainer.givenSimplestProductSystem();
|
||||||
|
gamesystem.generateFromChildsystems();
|
||||||
|
|
||||||
|
expect(gamesystem.states.length).toEqual(4);
|
||||||
|
expect(gamesystem.transitions.length).toEqual(5);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Test simple triple Product State", async () => {
|
||||||
|
const gamesystem = ProductSystemGenerationTrainer.givenTrippleProductSystem();
|
||||||
|
gamesystem.generateFromChildsystems();
|
||||||
|
|
||||||
|
expect(gamesystem.states.length).toEqual(8);
|
||||||
|
expect(gamesystem.transitions.length).toEqual(19)
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
import {ProductGamesystem} from "../../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {SimpleGamesystem} from "../../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import {ProductState} from "../../../../src/app/game-model/gamesystems/ProductState";
|
||||||
|
import {ProductTransition} from "../../../../src/app/game-model/gamesystems/ProductTransition";
|
||||||
|
|
||||||
|
export class ProductStateTrainer {
|
||||||
|
static INNERSTATE_LETTER_1 = "A";
|
||||||
|
static INNERSTATE_LETTER_2 = "B";
|
||||||
|
static INNERSTATE_LETTER_3 = "C";
|
||||||
|
static INNERSTATE_NUMBER_1 = "1";
|
||||||
|
static INNERSTATE_NUMBER_2 = "2";
|
||||||
|
static INNERSTATE_NUMBER_3 = "3";
|
||||||
|
|
||||||
|
static LETTERS_GAMESYSTEM_NAME = "Letters";
|
||||||
|
static NUMBERS_GAMESYSTEM_NAME = "Numbers";
|
||||||
|
static PRODUCT_GAMESYSTEM_NAME = "Product Gamesystem";
|
||||||
|
|
||||||
|
static givenFullProductGamesystemWithTwoStates() {
|
||||||
|
const letter_Gamesystem = new SimpleGamesystem(this.LETTERS_GAMESYSTEM_NAME);
|
||||||
|
const letter_1 = letter_Gamesystem.createState(this.INNERSTATE_LETTER_1, "")!;
|
||||||
|
const letter_2 = letter_Gamesystem.createState(this.INNERSTATE_LETTER_2, "")!;
|
||||||
|
const number_gamesystem = new SimpleGamesystem(this.NUMBERS_GAMESYSTEM_NAME);
|
||||||
|
const number_1 = number_gamesystem.createState(this.INNERSTATE_NUMBER_1, "")!;
|
||||||
|
const number_2 = number_gamesystem.createState(this.INNERSTATE_NUMBER_2, "")!;
|
||||||
|
const productGamesystem = new ProductGamesystem(this.PRODUCT_GAMESYSTEM_NAME);
|
||||||
|
|
||||||
|
productGamesystem.states.push(new ProductState( [letter_1, number_1]));
|
||||||
|
productGamesystem.states.push(new ProductState( [letter_1, number_2]));
|
||||||
|
productGamesystem.states.push(new ProductState( [letter_2, number_1]));
|
||||||
|
productGamesystem.states.push(new ProductState( [letter_2, number_2]));
|
||||||
|
|
||||||
|
productGamesystem.transitions.push(new ProductTransition(productGamesystem.states[0], productGamesystem.states[1]))
|
||||||
|
productGamesystem.transitions.push(new ProductTransition(productGamesystem.states[0], productGamesystem.states[2]))
|
||||||
|
productGamesystem.transitions.push(new ProductTransition(productGamesystem.states[0], productGamesystem.states[3]))
|
||||||
|
|
||||||
|
productGamesystem.innerGamesystems.push(letter_Gamesystem);
|
||||||
|
productGamesystem.innerGamesystems.push(number_gamesystem);
|
||||||
|
|
||||||
|
return productGamesystem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static givenUnusedInnerStates(productGamesystem: ProductGamesystem) {
|
||||||
|
const letterGamesystem = productGamesystem.findChildSystemByName(ProductStateTrainer.LETTERS_GAMESYSTEM_NAME) as SimpleGamesystem;
|
||||||
|
const numberGamesystem = productGamesystem.findChildSystemByName(ProductStateTrainer.NUMBERS_GAMESYSTEM_NAME) as SimpleGamesystem;
|
||||||
|
|
||||||
|
const letterGamesystemState = letterGamesystem.createState(ProductStateTrainer.INNERSTATE_LETTER_3, "")!;
|
||||||
|
const numberGamesystemState = numberGamesystem.createState(ProductStateTrainer.INNERSTATE_NUMBER_3, "")!;
|
||||||
|
|
||||||
|
return [letterGamesystemState, numberGamesystemState];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import {ProductGamesystem} from "../../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {SimpleGamesystem} from "../../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||||
|
|
||||||
|
export class ProductSystemGenerationTrainer {
|
||||||
|
|
||||||
|
static PRODUCTGAMESYSTEMNAME = "ProductGamesystem";
|
||||||
|
static CHILDGAMESYSTEMNAME_LEFT = "Left Child System";
|
||||||
|
static CHILDGAMESYSTEMNAME_RIGHT = "Right Child System";
|
||||||
|
static CHILDGAMESYSTEMNAME_MIDDLE = "Middle Child System";
|
||||||
|
|
||||||
|
static LEFTCHILDSYSTEM_A_NODE_NAME = "A";
|
||||||
|
static LEFTCHILDSYSTEM_B_NODE_NAME = "B";
|
||||||
|
|
||||||
|
static RIGHTCHILDSYSTEM_A_NODE_NAME = "1";
|
||||||
|
static RIGHTCHILDSYSTEM_B_NODE_NAME = "2";
|
||||||
|
|
||||||
|
static MIDDLECHILDSYSTEM_A_NODE_NAME = "Sun";
|
||||||
|
static MIDDLECHILDSYSTEM_B_NODE_NAME = "Rain";
|
||||||
|
static givenSimplestProductSystem() {
|
||||||
|
const productsystem = new ProductGamesystem(ProductSystemGenerationTrainer.PRODUCTGAMESYSTEMNAME);
|
||||||
|
const left_childsystem = new SimpleGamesystem(ProductSystemGenerationTrainer.CHILDGAMESYSTEMNAME_LEFT);
|
||||||
|
const right_childsystem = new SimpleGamesystem(ProductSystemGenerationTrainer.CHILDGAMESYSTEMNAME_RIGHT);
|
||||||
|
|
||||||
|
left_childsystem.createTransition(left_childsystem.createState(ProductSystemGenerationTrainer.LEFTCHILDSYSTEM_A_NODE_NAME, "")!,
|
||||||
|
left_childsystem.createState(ProductSystemGenerationTrainer.LEFTCHILDSYSTEM_B_NODE_NAME, "")!);
|
||||||
|
right_childsystem.createTransition(right_childsystem.createState(ProductSystemGenerationTrainer.RIGHTCHILDSYSTEM_A_NODE_NAME, "")!,
|
||||||
|
right_childsystem.createState(ProductSystemGenerationTrainer.RIGHTCHILDSYSTEM_B_NODE_NAME, "")!);
|
||||||
|
productsystem.addChildGamesystem(left_childsystem);
|
||||||
|
productsystem.addChildGamesystem(right_childsystem);
|
||||||
|
|
||||||
|
return productsystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static givenTrippleProductSystem() {
|
||||||
|
const gamesystem = this.givenSimplestProductSystem();
|
||||||
|
const middle_childsystem = new SimpleGamesystem(this.CHILDGAMESYSTEMNAME_MIDDLE);
|
||||||
|
|
||||||
|
middle_childsystem.createTransition(middle_childsystem.createState(ProductSystemGenerationTrainer.MIDDLECHILDSYSTEM_A_NODE_NAME, "")!,
|
||||||
|
middle_childsystem.createState(ProductSystemGenerationTrainer.MIDDLECHILDSYSTEM_B_NODE_NAME, "")!);
|
||||||
|
gamesystem.addChildGamesystem(middle_childsystem);
|
||||||
|
return gamesystem;
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,8 @@ import {DeleteConfirmationDialogComponent} from "./delete-confirmation-dialog/de
|
|||||||
import {ScriptAccount} from "./game-model/scriptAccounts/ScriptAccount";
|
import {ScriptAccount} from "./game-model/scriptAccounts/ScriptAccount";
|
||||||
import {GamescriptOverviewComponent} from "./side-overviews/gamescript-overview/gamescript-overview.component";
|
import {GamescriptOverviewComponent} from "./side-overviews/gamescript-overview/gamescript-overview.component";
|
||||||
import {SimpleGamesystem} from "./game-model/gamesystems/SimpleGamesystem";
|
import {SimpleGamesystem} from "./game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import {ProductGamesystem} from "./game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {ProductState} from "./game-model/gamesystems/ProductState";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -150,10 +152,19 @@ export class AppComponent implements OnInit{
|
|||||||
const springState = season.createState("Spring", "Spring, also known as springtime, is one of the four temperate seasons, succeeding winter and preceding summer.");
|
const springState = season.createState("Spring", "Spring, also known as springtime, is one of the four temperate seasons, succeeding winter and preceding summer.");
|
||||||
const summerState = season.createState("Summer", "Summer is the hottest and brightest of the four temperate seasons, occurring after spring and before autumn. ");
|
const summerState = season.createState("Summer", "Summer is the hottest and brightest of the four temperate seasons, occurring after spring and before autumn. ");
|
||||||
|
|
||||||
season.createTransition(springState!, summerState!);
|
const sunnyState = weather.createState("Sunny", "The sun is shining. No clouds, no rain, no storm.");
|
||||||
|
const rainingState = weather.createState("Raining", "It rains")
|
||||||
|
|
||||||
this.gameModel.addGamesystem(weather)
|
season.createTransition(springState!, summerState!);
|
||||||
this.gameModel.addGamesystem(season);
|
weather.createTransition(sunnyState!, rainingState!);
|
||||||
|
|
||||||
|
const weather_season = new ProductGamesystem("Weather-Season");
|
||||||
|
weather_season.addChildGamesystem(weather);
|
||||||
|
weather_season.addChildGamesystem(season);
|
||||||
|
|
||||||
|
weather_season.createState([springState!, sunnyState!]);
|
||||||
|
|
||||||
|
this.gameModel.addGamesystem(weather_season);
|
||||||
}
|
}
|
||||||
|
|
||||||
openScriptAccountsOverview() {
|
openScriptAccountsOverview() {
|
||||||
|
@ -51,6 +51,9 @@ import {
|
|||||||
SimpleTransitionEditorComponent
|
SimpleTransitionEditorComponent
|
||||||
} from "./editor/gamesystem-editor/transition-editor/simple-transition-editor/simple-transition-editor.component";
|
} from "./editor/gamesystem-editor/transition-editor/simple-transition-editor/simple-transition-editor.component";
|
||||||
import {MatOption, MatSelect} from "@angular/material/select";
|
import {MatOption, MatSelect} from "@angular/material/select";
|
||||||
|
import {
|
||||||
|
ProductGamesystemEditorComponent
|
||||||
|
} from "./editor/gamesystem-editor/product-gamesystem-editor/product-gamesystem-editor.component";
|
||||||
|
|
||||||
// AoT requires an exported function for factories
|
// AoT requires an exported function for factories
|
||||||
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||||
@ -121,7 +124,8 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
|
|||||||
MatCheckbox,
|
MatCheckbox,
|
||||||
MatSelect,
|
MatSelect,
|
||||||
MatOption,
|
MatOption,
|
||||||
MatHint
|
MatHint,
|
||||||
|
ProductGamesystemEditorComponent
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<mat-tab-group>
|
<mat-tab-group [(selectedIndex)]="activeTab">
|
||||||
<mat-tab *ngFor="let modelComponent of gameModelComponents">
|
<mat-tab *ngFor="let modelComponent of gameModelComponents">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<mat-icon class="example-tab-icon unsaved" *ngIf="modelComponent.type === ModelComponentType.SCRIPTACCOUNT" [ngClass]="modelComponent.unsaved? 'unsaved':'saved'">inventory_2</mat-icon>
|
<mat-icon class="example-tab-icon unsaved" *ngIf="modelComponent.type === ModelComponentType.SCRIPTACCOUNT" [ngClass]="modelComponent.unsaved? 'unsaved':'saved'">inventory_2</mat-icon>
|
||||||
@ -11,7 +11,8 @@
|
|||||||
<app-script-account-editor *ngIf="modelComponent.type === ModelComponentType.SCRIPTACCOUNT"
|
<app-script-account-editor *ngIf="modelComponent.type === ModelComponentType.SCRIPTACCOUNT"
|
||||||
[scriptAccount]="convertModelComponentToScriptAccount(modelComponent)"></app-script-account-editor>
|
[scriptAccount]="convertModelComponentToScriptAccount(modelComponent)"></app-script-account-editor>
|
||||||
<app-gamesystem-editor *ngIf="modelComponent.type == ModelComponentType.GAMESYTEM"
|
<app-gamesystem-editor *ngIf="modelComponent.type == ModelComponentType.GAMESYTEM"
|
||||||
[gamesystem]="convertModelComponentToGamesystem(modelComponent)"></app-gamesystem-editor>
|
[gamesystem]="convertModelComponentToGamesystem(modelComponent)"
|
||||||
|
(onOpenGamesystemEditor)="openGameModelComponent($event)"></app-gamesystem-editor>
|
||||||
|
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
|
@ -15,10 +15,14 @@ import {Transition} from "../game-model/gamesystems/Transition";
|
|||||||
export class EditorComponent {
|
export class EditorComponent {
|
||||||
gameModelComponents: ModelComponent[] = [];
|
gameModelComponents: ModelComponent[] = [];
|
||||||
@Output("onModelNameUpdate") onModelNameUpdateEmitter = new EventEmitter<boolean>();
|
@Output("onModelNameUpdate") onModelNameUpdateEmitter = new EventEmitter<boolean>();
|
||||||
|
activeTab: number = this.gameModelComponents.length;
|
||||||
|
|
||||||
openGameModelComponent(gameModelComponent: ModelComponent) {
|
openGameModelComponent(gameModelComponent: ModelComponent) {
|
||||||
if(!this.gameModelComponents.includes(gameModelComponent)) {
|
if(!this.gameModelComponents.includes(gameModelComponent)) {
|
||||||
this.gameModelComponents.push(gameModelComponent);
|
this.gameModelComponents.push(gameModelComponent);
|
||||||
|
this.activeTab = this.gameModelComponents.length;
|
||||||
|
} else {
|
||||||
|
this.activeTab = this.gameModelComponents.findIndex(component => component.componentName === gameModelComponent.componentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1,3 @@
|
|||||||
<app-simple-gamesystem-editor *ngIf="isSimpleGamesystem()" [simpleGamesystem]="convertGamesystemToSimpleGamesystem()"></app-simple-gamesystem-editor>
|
<app-simple-gamesystem-editor *ngIf="isSimpleGamesystem()" [simpleGamesystem]="convertGamesystemToSimpleGamesystem()"></app-simple-gamesystem-editor>
|
||||||
|
<app-product-gamesystem-editor *ngIf="!isSimpleGamesystem()" [gamesystem]="convertGamesystemToProductGamesystem()"
|
||||||
|
(onOpenGamesystemEditor)="onOpenGamesystemEditor($event)"></app-product-gamesystem-editor>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {Component, Input} from '@angular/core';
|
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||||
import {GameModel} from "../../game-model/GameModel";
|
import {GameModel} from "../../game-model/GameModel";
|
||||||
import {Gamesystem} from "../../game-model/gamesystems/Gamesystem";
|
import {Gamesystem} from "../../game-model/gamesystems/Gamesystem";
|
||||||
import {State} from "../../game-model/gamesystems/State";
|
import {State} from "../../game-model/gamesystems/State";
|
||||||
@ -14,6 +14,7 @@ import {ProductGamesystem} from "../../game-model/gamesystems/ProductGamesystem"
|
|||||||
export class GamesystemEditorComponent {
|
export class GamesystemEditorComponent {
|
||||||
|
|
||||||
@Input() gamesystem: Gamesystem<State<any>, Transition<any>> | undefined
|
@Input() gamesystem: Gamesystem<State<any>, Transition<any>> | undefined
|
||||||
|
@Output('onOpenGamesystemEditor') openGamesystemEmitter = new EventEmitter<SimpleGamesystem>();
|
||||||
|
|
||||||
isSimpleGamesystem() {
|
isSimpleGamesystem() {
|
||||||
return this.gamesystem instanceof SimpleGamesystem;
|
return this.gamesystem instanceof SimpleGamesystem;
|
||||||
@ -30,4 +31,8 @@ export class GamesystemEditorComponent {
|
|||||||
return this.gamesystem as ProductGamesystem;
|
return this.gamesystem as ProductGamesystem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpenGamesystemEditor(gamesystem: SimpleGamesystem) {
|
||||||
|
this.openGamesystemEmitter.emit(gamesystem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import {Gamesystem} from "../../../game-model/gamesystems/Gamesystem";
|
||||||
|
import {SimpleGamesystem} from "../../../game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import {ProductGamesystem} from "../../../game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {State} from "../../../game-model/gamesystems/State";
|
||||||
|
import {ProductState} from "../../../game-model/gamesystems/ProductState";
|
||||||
|
import {SimpleState} from "../../../game-model/gamesystems/SimpleState";
|
||||||
|
|
||||||
|
export class LeafGamesystemCalculator {
|
||||||
|
|
||||||
|
static calcLeafGeamesystems(gamesystem: Gamesystem<any, any>) {
|
||||||
|
if(gamesystem instanceof SimpleGamesystem) {
|
||||||
|
return [gamesystem];
|
||||||
|
} else {
|
||||||
|
const product_gamesystem = gamesystem as ProductGamesystem;
|
||||||
|
const leaf_gamesystems: SimpleGamesystem[] = [];
|
||||||
|
product_gamesystem.innerGamesystems.forEach(innerGamesystem => {
|
||||||
|
LeafGamesystemCalculator.calcLeafGeamesystems(innerGamesystem).forEach(leafGamesystem => leaf_gamesystems.push(leafGamesystem))
|
||||||
|
})
|
||||||
|
return leaf_gamesystems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static calcLeafStates(state: State<any>) {
|
||||||
|
if(state instanceof SimpleState) {
|
||||||
|
return [state];
|
||||||
|
} else {
|
||||||
|
const productState = state as ProductState;
|
||||||
|
const leafStates: SimpleState[] = [];
|
||||||
|
productState.innerStates.forEach(innerState => {
|
||||||
|
LeafGamesystemCalculator.calcLeafStates(innerState).forEach(leafState => leafStates.push(leafState));
|
||||||
|
})
|
||||||
|
return leafStates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
<app-product-state-editor [gamesystem]="gamesystem" (onOpenGamesystemEditor)="onOpenGamesystemEditor($event)"></app-product-state-editor>
|
||||||
|
<app-product-transition-editor [gamesystem]="gamesystem" (onOpenGamesystem)="onOpenGamesystemEditor($event)"></app-product-transition-editor>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProductGamesystemEditorComponent } from './product-gamesystem-editor.component';
|
||||||
|
|
||||||
|
describe('ProductGamesystemEditorComponent', () => {
|
||||||
|
let component: ProductGamesystemEditorComponent;
|
||||||
|
let fixture: ComponentFixture<ProductGamesystemEditorComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ProductGamesystemEditorComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ProductGamesystemEditorComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,29 @@
|
|||||||
|
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||||
|
import {ProductGamesystem} from "../../../game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {ProductStateEditorComponent} from "../state-editor/product-state-editor/product-state-editor.component";
|
||||||
|
import {SimpleGamesystem} from "../../../game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import {
|
||||||
|
ProductTransitionEditorComponent
|
||||||
|
} from "../transition-editor/product-transition-editor/product-transition-editor.component";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-gamesystem-editor',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
ProductStateEditorComponent,
|
||||||
|
ProductTransitionEditorComponent
|
||||||
|
],
|
||||||
|
templateUrl: './product-gamesystem-editor.component.html',
|
||||||
|
styleUrl: './product-gamesystem-editor.component.scss'
|
||||||
|
})
|
||||||
|
export class ProductGamesystemEditorComponent {
|
||||||
|
|
||||||
|
@Input() gamesystem: ProductGamesystem | undefined
|
||||||
|
@Output("onOpenGamesystemEditor") openGamesystemEditorEmitter = new EventEmitter<SimpleGamesystem>();
|
||||||
|
|
||||||
|
onOpenGamesystemEditor(gamesystem: SimpleGamesystem) {
|
||||||
|
this.openGamesystemEditorEmitter.emit(gamesystem);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
<table mat-table [dataSource]="datasource" class="mat-elevation-z8">
|
||||||
|
<ng-container *ngFor="let col of displayedColumns; let i = index" [matColumnDef]="col">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>{{col}}</th>
|
||||||
|
<td mat-cell *matCellDef="let state">
|
||||||
|
<a *ngIf="i < displayedColumns.length-1" role="button" (click)="clickOnInnerState(i)" [matTooltip]="getLeafState(state, i).stateDescription">{{getLeafState(state, i).stateLabel}}</a>
|
||||||
|
<mat-icon *ngIf="i == displayedColumns.length-1">
|
||||||
|
{{state.initial? 'done':'close'}}
|
||||||
|
</mat-icon>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
@ -0,0 +1,7 @@
|
|||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-Initial {
|
||||||
|
width: 32px;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProductStateEditorComponent } from './product-state-editor.component';
|
||||||
|
|
||||||
|
describe('ProductStateEditorComponent', () => {
|
||||||
|
let component: ProductStateEditorComponent;
|
||||||
|
let fixture: ComponentFixture<ProductStateEditorComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ProductStateEditorComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ProductStateEditorComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,82 @@
|
|||||||
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
|
import {ProductGamesystem} from "../../../../game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import {
|
||||||
|
MatCell, MatCellDef,
|
||||||
|
MatColumnDef, MatHeaderCell, MatHeaderCellDef,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatTable,
|
||||||
|
MatTableDataSource
|
||||||
|
} from "@angular/material/table";
|
||||||
|
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
|
||||||
|
import {State} from "../../../../game-model/gamesystems/State";
|
||||||
|
import {NgForOf, NgIf} from "@angular/common";
|
||||||
|
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
|
||||||
|
import {MatIcon} from "@angular/material/icon";
|
||||||
|
import {Gamesystem} from "../../../../game-model/gamesystems/Gamesystem";
|
||||||
|
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
|
||||||
|
import {MatTooltip} from "@angular/material/tooltip";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-state-editor',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
MatTable,
|
||||||
|
MatRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatColumnDef,
|
||||||
|
MatHeaderCell,
|
||||||
|
MatHeaderCellDef,
|
||||||
|
MatCell,
|
||||||
|
MatCellDef,
|
||||||
|
NgForOf,
|
||||||
|
NgIf,
|
||||||
|
MatIcon,
|
||||||
|
MatTooltip
|
||||||
|
],
|
||||||
|
templateUrl: './product-state-editor.component.html',
|
||||||
|
styleUrl: './product-state-editor.component.scss'
|
||||||
|
})
|
||||||
|
export class ProductStateEditorComponent implements OnInit{
|
||||||
|
|
||||||
|
@Input() gamesystem: ProductGamesystem | undefined
|
||||||
|
@Output('onOpenGamesystemEditor') openGamesystemEditorEmitter = new EventEmitter<SimpleGamesystem>();
|
||||||
|
displayedColumns: string[] = [];
|
||||||
|
datasource = new MatTableDataSource();
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.gamesystem!.generateFromChildsystems();
|
||||||
|
this.generateColumnNamesRecursively(this.gamesystem!, "");
|
||||||
|
this.displayedColumns.push('Initial');
|
||||||
|
this.datasource.data = this.gamesystem!.states;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateColumnNamesRecursively(gamesystem: ProductGamesystem, nestedColumnName: string) {
|
||||||
|
gamesystem.innerGamesystems.forEach(innerGamesystem => {
|
||||||
|
if(innerGamesystem instanceof SimpleGamesystem) {
|
||||||
|
this.displayedColumns.push(nestedColumnName + innerGamesystem.componentName);
|
||||||
|
} else {
|
||||||
|
this.generateColumnNamesRecursively(innerGamesystem as ProductGamesystem, nestedColumnName + innerGamesystem.componentName + ".");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly SimpleState = SimpleState;
|
||||||
|
|
||||||
|
getLeafState(state: State<any>, i: number) {
|
||||||
|
return LeafGamesystemCalculator.calcLeafStates(state)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
clickOnInnerState(leafIndex: number) {
|
||||||
|
const leaf_gamesystems = LeafGamesystemCalculator.calcLeafGeamesystems(this.gamesystem!);
|
||||||
|
const clicked_gamesystem = leaf_gamesystems[leafIndex];
|
||||||
|
this.openGamesystemEditorEmitter.emit(clicked_gamesystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<table mat-table [dataSource]="dataSource">
|
||||||
|
<ng-container *ngFor="let col of displayedColumns; let i = index" [matColumnDef]="col.internalName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef (dblclick)="openGamesystemEditor(i)">{{col.displayedName}}</th>
|
||||||
|
<td mat-cell *matCellDef="let transition" [matTooltip]="getLeafStateByIndex(transition, i).stateDescription" (dblclick)="openGamesystemEditor(i)">
|
||||||
|
{{getLeafStateByIndex(transition, i).stateLabel}}
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="header-row-sec-group">
|
||||||
|
<th
|
||||||
|
mat-header-cell
|
||||||
|
*matHeaderCellDef
|
||||||
|
[style.text-align]="'center'"
|
||||||
|
[attr.colspan]="numberLeafSystems"
|
||||||
|
class="start-end-col"
|
||||||
|
>
|
||||||
|
Starting State
|
||||||
|
</th>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="header-row-third-group">
|
||||||
|
<th
|
||||||
|
mat-header-cell
|
||||||
|
*matHeaderCellDef
|
||||||
|
[style.text-align]="'center'"
|
||||||
|
[attr.colspan]="numberLeafSystems"
|
||||||
|
>
|
||||||
|
Ending State
|
||||||
|
</th>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="displayedColumns.length">
|
||||||
|
<tr
|
||||||
|
mat-header-row
|
||||||
|
*matHeaderRowDef="['header-row-sec-group', 'header-row-third-group']"
|
||||||
|
></tr>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="columns;sticky:true"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: columns;"></tr>
|
||||||
|
|
||||||
|
</table>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProductTransitionEditorComponent } from './product-transition-editor.component';
|
||||||
|
|
||||||
|
describe('ProductTransitionEditorComponent', () => {
|
||||||
|
let component: ProductTransitionEditorComponent;
|
||||||
|
let fixture: ComponentFixture<ProductTransitionEditorComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ProductTransitionEditorComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ProductTransitionEditorComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,97 @@
|
|||||||
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
|
import {ProductGamesystem} from "../../../../game-model/gamesystems/ProductGamesystem";
|
||||||
|
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
|
||||||
|
import {
|
||||||
|
MatCell, MatCellDef,
|
||||||
|
MatColumnDef,
|
||||||
|
MatHeaderCell,
|
||||||
|
MatHeaderCellDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
|
||||||
|
MatTable,
|
||||||
|
MatTableDataSource
|
||||||
|
} from "@angular/material/table";
|
||||||
|
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
|
||||||
|
import {NgForOf, NgIf} from "@angular/common";
|
||||||
|
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
|
||||||
|
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
|
||||||
|
import {MatTooltip} from "@angular/material/tooltip";
|
||||||
|
|
||||||
|
class DisplayedColumnName {
|
||||||
|
displayedName: string
|
||||||
|
internalName: string
|
||||||
|
|
||||||
|
|
||||||
|
constructor(displayedName: string, internalName: string) {
|
||||||
|
this.displayedName = displayedName;
|
||||||
|
this.internalName = internalName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-transition-editor',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
MatTable,
|
||||||
|
NgForOf,
|
||||||
|
MatColumnDef,
|
||||||
|
MatHeaderCell,
|
||||||
|
MatHeaderCellDef,
|
||||||
|
MatCell,
|
||||||
|
MatCellDef,
|
||||||
|
NgIf,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatRow,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatRowDef,
|
||||||
|
MatTooltip
|
||||||
|
],
|
||||||
|
templateUrl: './product-transition-editor.component.html',
|
||||||
|
styleUrl: './product-transition-editor.component.scss'
|
||||||
|
})
|
||||||
|
export class ProductTransitionEditorComponent implements OnInit{
|
||||||
|
|
||||||
|
@Input() gamesystem: ProductGamesystem | undefined
|
||||||
|
@Output() onOpenGamesystem = new EventEmitter<SimpleGamesystem>();
|
||||||
|
|
||||||
|
dataSource = new MatTableDataSource();
|
||||||
|
displayedColumns: DisplayedColumnName[] = [];
|
||||||
|
columns: string[] = [];
|
||||||
|
numberLeafSystems: number = -1;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if(this.gamesystem != undefined) {
|
||||||
|
const leafGamesystems: SimpleGamesystem[] = LeafGamesystemCalculator.calcLeafGeamesystems(this.gamesystem);
|
||||||
|
this.displayedColumns = leafGamesystems.map(leafGamesystem => new DisplayedColumnName(leafGamesystem.componentName, leafGamesystem.componentName + "-start"));
|
||||||
|
this.displayedColumns = this.displayedColumns.concat( leafGamesystems.map(leafGamesystem => new DisplayedColumnName(leafGamesystem.componentName, leafGamesystem.componentName + "-end")));
|
||||||
|
|
||||||
|
this.numberLeafSystems = leafGamesystems.length;
|
||||||
|
this.columns = this.displayedColumns.map(column => column.internalName)
|
||||||
|
|
||||||
|
this.dataSource.data = this.gamesystem.transitions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLeafStateByIndex(transition: ProductTransition, leafIndex: number) {
|
||||||
|
let state: ProductState;
|
||||||
|
let index = leafIndex;
|
||||||
|
if(leafIndex < this.numberLeafSystems) {
|
||||||
|
state = transition.startingState
|
||||||
|
} else {
|
||||||
|
state = transition.endingState;
|
||||||
|
index = leafIndex - this.numberLeafSystems;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const leafStates = LeafGamesystemCalculator.calcLeafStates(state);
|
||||||
|
console.log(leafStates)
|
||||||
|
return leafStates[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
openGamesystemEditor(leafIndex: number) {
|
||||||
|
const leafGamesystems = LeafGamesystemCalculator.calcLeafGeamesystems(this.gamesystem!);
|
||||||
|
if(leafIndex < this.numberLeafSystems) {
|
||||||
|
this.onOpenGamesystem.emit(leafGamesystems[leafIndex])
|
||||||
|
} else {
|
||||||
|
this.onOpenGamesystem.emit(leafGamesystems[leafIndex - this.numberLeafSystems])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,6 @@ export abstract class Gamesystem<S, T> extends ModelComponent{
|
|||||||
super(gamesystemName, "", ModelComponentType.GAMESYTEM);
|
super(gamesystemName, "", ModelComponentType.GAMESYTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract createState(label: string, description: string): S|undefined;
|
|
||||||
|
|
||||||
abstract createTransition(startingState: S, endingState: S): T|undefined;
|
abstract createTransition(startingState: S, endingState: S): T|undefined;
|
||||||
|
|
||||||
abstract removeState(state: S): boolean;
|
abstract removeState(state: S): boolean;
|
||||||
|
@ -6,6 +6,7 @@ import {Transition} from "./Transition";
|
|||||||
import {SimpleState} from "./SimpleState";
|
import {SimpleState} from "./SimpleState";
|
||||||
import {SimpleGamesystem} from "./SimpleGamesystem";
|
import {SimpleGamesystem} from "./SimpleGamesystem";
|
||||||
import {GameModel} from "../GameModel";
|
import {GameModel} from "../GameModel";
|
||||||
|
import {ProductStateTrainer} from "../../../../e2e/game-model/gamesystems/productGamesystems/ProductStateTrainer";
|
||||||
|
|
||||||
export class ProductGamesystem extends Gamesystem<ProductState, ProductTransition> {
|
export class ProductGamesystem extends Gamesystem<ProductState, ProductTransition> {
|
||||||
|
|
||||||
@ -33,12 +34,25 @@ export class ProductGamesystem extends Gamesystem<ProductState, ProductTransitio
|
|||||||
return productGamesystem;
|
return productGamesystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
createState(label: string, description: string): ProductState | undefined {
|
createState(innerStates: State<any>[]): ProductState | undefined {
|
||||||
return undefined;
|
if(innerStates.length == this.innerGamesystems.length && this.findProductStateByInnerStates(innerStates)== undefined) {
|
||||||
|
const productState = new ProductState(innerStates);
|
||||||
|
this.states.push(productState);
|
||||||
|
return productState;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createTransition(startingState: ProductState, endingState: ProductState): ProductTransition | undefined {
|
createTransition(startingState: ProductState, endingState: ProductState): ProductTransition | undefined {
|
||||||
return undefined;
|
if(startingState == undefined || endingState == undefined || this.existsTransition(startingState, endingState)
|
||||||
|
|| !this.existsState(startingState) || !this.existsState(endingState) || startingState.equals(endingState)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const productTransition = new ProductTransition(startingState, endingState);
|
||||||
|
this.transitions.push(productTransition);
|
||||||
|
return productTransition;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeState(state: ProductState): boolean {
|
removeState(state: ProductState): boolean {
|
||||||
@ -49,6 +63,77 @@ export class ProductGamesystem extends Gamesystem<ProductState, ProductTransitio
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateFromChildsystems() {
|
||||||
|
//Assume that childsystems that are productsystems are already generated
|
||||||
|
const integratedSystems: Gamesystem<any, any>[] = [this.innerGamesystems[0], this.innerGamesystems[1]];
|
||||||
|
let gamesystem: ProductGamesystem = ProductGamesystem.generateFromChildsystems(this.innerGamesystems[0], this.innerGamesystems[1], false, integratedSystems);
|
||||||
|
|
||||||
|
for(let i=2; i<this.innerGamesystems.length; i++) {
|
||||||
|
integratedSystems.push(this.innerGamesystems[i]);
|
||||||
|
gamesystem = ProductGamesystem.generateFromChildsystems(gamesystem, this.innerGamesystems[i], true, integratedSystems);
|
||||||
|
}
|
||||||
|
this.states = gamesystem.states;
|
||||||
|
this.transitions = gamesystem.transitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static generateFromChildsystems(leftSystem: Gamesystem<any, any>, rightSystem: Gamesystem<any, any>, left_temp: boolean, integratedSystems: Gamesystem<any, any>[]) {
|
||||||
|
const productGamesystem = new ProductGamesystem("Temporary Gamesystem");
|
||||||
|
integratedSystems.forEach(integratedSystem => productGamesystem.addChildGamesystem(integratedSystem));
|
||||||
|
|
||||||
|
leftSystem.states.forEach(leftState => {
|
||||||
|
rightSystem.states.forEach(rightState => {
|
||||||
|
for(let i=0; i<leftState.outgoingTransitions.length; i++) {
|
||||||
|
for(let j=0; j<rightState.outgoingTransitions.length; j++) {
|
||||||
|
const startingState = productGamesystem.generateBinaryProductState(leftState, rightState, left_temp);
|
||||||
|
const endingState_right = productGamesystem.generateBinaryProductState(leftState, rightState.outgoingTransitions[j].endingState, left_temp);
|
||||||
|
const transition_right = productGamesystem.createTransition(startingState, endingState_right)!;
|
||||||
|
|
||||||
|
const endingState_left = productGamesystem.generateBinaryProductState(leftState.outgoingTransitions[i].endingState, rightState, left_temp);
|
||||||
|
const transition_left = productGamesystem.createTransition(startingState, endingState_left)!;
|
||||||
|
|
||||||
|
const endingState_left_right = productGamesystem.generateBinaryProductState(leftState.outgoingTransitions[i].endingState, rightState.outgoingTransitions[j].endingState, left_temp);
|
||||||
|
const transition_left_right = productGamesystem.createTransition(startingState, endingState_left_right)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rightState.outgoingTransitions.length == 0) {
|
||||||
|
const startingState = productGamesystem.generateBinaryProductState(leftState, rightState, left_temp);
|
||||||
|
const endingState = productGamesystem.generateBinaryProductState(leftState.outgoingTransitions[i].endingState, rightState, left_temp);
|
||||||
|
const transition = productGamesystem.createTransition(startingState, endingState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(leftState.outgoingTransitions.length == 0) {
|
||||||
|
for(let j=0; j<rightState.outgoingTransitions.length; j++) {
|
||||||
|
const startingState = productGamesystem.generateBinaryProductState(leftState, rightState, left_temp);
|
||||||
|
const endingState = productGamesystem.generateBinaryProductState(leftState, rightState.outgoingTransitions[j].endingState, left_temp);
|
||||||
|
const transition = productGamesystem.createTransition(startingState, endingState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return productGamesystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateBinaryProductState(leftInnerState: State<any>, rightInnerState: State<any>, left_temp: boolean) {
|
||||||
|
let innerStates: State<any>[] = [];
|
||||||
|
if(!left_temp) {
|
||||||
|
innerStates = [leftInnerState, rightInnerState];
|
||||||
|
} else {
|
||||||
|
const left_inner_product_state = leftInnerState as ProductState;
|
||||||
|
left_inner_product_state.innerStates.forEach(state => innerStates.push(state));
|
||||||
|
innerStates.push(rightInnerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let binary_productState = this.findProductStateByInnerStates(innerStates);
|
||||||
|
if(binary_productState == undefined) {
|
||||||
|
binary_productState = this.createState(innerStates)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
let productInitial = true;
|
||||||
|
binary_productState.innerStates.forEach(innerState => productInitial = productInitial && innerState.initial)
|
||||||
|
return binary_productState!;
|
||||||
|
}
|
||||||
|
|
||||||
addChildGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
addChildGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
||||||
this.innerGamesystems.push(gamesystem);
|
this.innerGamesystems.push(gamesystem);
|
||||||
@ -57,4 +142,30 @@ export class ProductGamesystem extends Gamesystem<ProductState, ProductTransitio
|
|||||||
private removeChildGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
private removeChildGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
||||||
this.innerGamesystems = this.innerGamesystems.filter(childSystem => childSystem != gamesystem);
|
this.innerGamesystems = this.innerGamesystems.filter(childSystem => childSystem != gamesystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findProductStateByInnerStates(innerStates: State<any>[]) {
|
||||||
|
return this.states.find(productState => productState.equalInnerStates(innerStates));
|
||||||
|
}
|
||||||
|
|
||||||
|
findChildSystemByName(gamesystemName: string) {
|
||||||
|
const gamesystemQueue: Gamesystem<State<any>, Transition<any>>[] = [];
|
||||||
|
this.innerGamesystems.forEach(gamesystem => gamesystemQueue.push(gamesystem));
|
||||||
|
|
||||||
|
while(gamesystemName.length > 0 ){
|
||||||
|
const currentGamesystem = gamesystemQueue.shift();
|
||||||
|
if(currentGamesystem!.componentName === gamesystemName) {
|
||||||
|
return currentGamesystem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private existsTransition(startingState: ProductState, endingState: ProductState) {
|
||||||
|
return this.transitions.find(transition =>
|
||||||
|
transition.startingState.equals(startingState) && transition.endingState.equals(endingState)) != undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private existsState(state: ProductState) {
|
||||||
|
return this.states.find(s => s.equals(state)) != undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,42 @@
|
|||||||
import {ProductTransition} from "./ProductTransition";
|
import {ProductTransition} from "./ProductTransition";
|
||||||
import {State} from "./State";
|
import {State} from "./State";
|
||||||
import {SimpleState} from "./SimpleState";
|
import {SimpleState} from "./SimpleState";
|
||||||
|
import {Transition} from "./Transition";
|
||||||
|
|
||||||
export class ProductState extends State<ProductTransition> {
|
export class ProductState extends State<ProductTransition> {
|
||||||
innerStates: SimpleState[] = [];
|
innerStates: State<any>[] = [];
|
||||||
|
|
||||||
|
constructor(innerStates: State<any>[]) {
|
||||||
|
super();
|
||||||
|
this.innerStates = innerStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
equalInnerStates(innerStates: State<any>[]) {
|
||||||
|
if(innerStates == undefined || this.innerStates.length != innerStates.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i=0; i<innerStates.length; i++) {
|
||||||
|
if(!this.innerStates[i].equals(innerStates[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(state: State<Transition<any>>): boolean {
|
||||||
|
if(state instanceof SimpleState || this.innerStates.length != (state as ProductState).innerStates.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i=0; i<this.innerStates.length; i++) {
|
||||||
|
if(!this.innerStates[i].equals((state as ProductState).innerStates[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,24 @@
|
|||||||
import {State} from "./State";
|
import {State} from "./State";
|
||||||
import {SimpleTransition} from "./SimpleTransition";
|
import {SimpleTransition} from "./SimpleTransition";
|
||||||
|
import {Transition} from "./Transition";
|
||||||
|
|
||||||
export class SimpleState extends State<SimpleTransition> {
|
export class SimpleState extends State<SimpleTransition> {
|
||||||
|
stateLabel: string = "";
|
||||||
|
stateDescription: string = "";
|
||||||
|
|
||||||
|
|
||||||
|
constructor(stateLabel: string, stateDescription: string) {
|
||||||
|
super();
|
||||||
|
this.stateLabel = stateLabel;
|
||||||
|
this.stateDescription = stateDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(state: State<Transition<any>>): boolean {
|
||||||
|
if(!(state instanceof SimpleState)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.stateLabel === (state as SimpleState).stateLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
import {Transition} from "./Transition";
|
import {Transition} from "./Transition";
|
||||||
|
|
||||||
export abstract class State<T extends Transition<any>> {
|
export abstract class State<T extends Transition<any>> {
|
||||||
stateLabel: string = "";
|
|
||||||
stateDescription: string = "";
|
|
||||||
incomingTransitions: T[] =[];
|
incomingTransitions: T[] =[];
|
||||||
outgoingTransitions: T[] =[];
|
outgoingTransitions: T[] =[];
|
||||||
|
|
||||||
initial: boolean = false;
|
initial: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
constructor(stateLabel: string, stateDescription: string) {
|
|
||||||
this.stateLabel = stateLabel;
|
|
||||||
this.stateDescription = stateDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
addIncomingTransition(transition: T) {
|
addIncomingTransition(transition: T) {
|
||||||
this.incomingTransitions.push(transition);
|
this.incomingTransitions.push(transition);
|
||||||
}
|
}
|
||||||
@ -29,4 +22,6 @@ export abstract class State<T extends Transition<any>> {
|
|||||||
removeOutgoingTransition(transition: T) {
|
removeOutgoingTransition(transition: T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract equals(state: State<Transition<any>>): boolean;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user