Refactor Code for ProductGamesystem Generation
All checks were successful
E2E Testing / test (push) Successful in 2m2s

This commit is contained in:
Sebastian Böckelmann 2024-04-12 10:00:16 +02:00
parent 859f207503
commit 083d993c31
10 changed files with 308 additions and 0 deletions

View File

@ -8,10 +8,12 @@ import {SimpleGamesystem} from "./SimpleGamesystem";
import {GameModel} from "../GameModel";
import {ScriptAccountCondition} from "./conditions/ScriptAccountCondition";
import {ScriptAccountAction} from "./actions/ScriptAccountAction";
import {ProductGamesystemGenerator} from "./productSystemGenerator/ProductGamesystemGenerator";
export class ProductGamesystem extends Gamesystem<ProductState, ProductTransition> {
innerGamesystems: Gamesystem<State<any>, Transition<any>>[] = [];
productGamesystemGenerator: ProductGamesystemGenerator = new ProductGamesystemGenerator(this);
static constructFromSimpleGamesystem(simpleGamesystem: SimpleGamesystem, gameModel: GameModel) {
const productGamesystem = new ProductGamesystem(simpleGamesystem.componentName, simpleGamesystem.componentDescription);

View File

@ -0,0 +1,14 @@
import {ProductGamesystem} from "./ProductGamesystem";
import {ProductState} from "./states/ProductState";
import {ProductTransition} from "./transitions/ProductTransition";
import {Gamesystem} from "./Gamesystem";
export class ProductTemplateSystem<ReferenceTemplate> extends ProductGamesystem{
stateMap: Map<ReferenceTemplate, ProductState[]> = new Map<ReferenceTemplate, ProductState[]>();
transitionMap: Map<ReferenceTemplate, ProductTransition[]> = new Map<ReferenceTemplate, ProductTransition[]>();
}

View File

@ -0,0 +1,23 @@
import {Gamesystem} from "../Gamesystem";
import {ScriptAccountAction} from "../actions/ScriptAccountAction";
import {ScriptAccountCondition} from "../conditions/ScriptAccountCondition";
import {State} from "../states/State";
import {ProductGamesystem} from "../ProductGamesystem";
export abstract class AbstractProductGamesystemGenerator {
protected integratedSystems: Gamesystem<any, any>[] = []
prepare() {
this.integratedSystems = []
}
abstract generateFromChildsystems(ProductGamesystem: ProductGamesystem): void;
abstract generateFromBinaryChildsystems(leftSystem: Gamesystem<any, any>, rightSystem: any, left_temp: boolean): void;
abstract generateBinaryProductState(leftInnerState: State<any>, rightInnerState: State<any>, left_temp: boolean): State<any>;
}

View File

@ -0,0 +1,211 @@
import {ProductGamesystem} from "../ProductGamesystem";
import {Gamesystem} from "../Gamesystem";
import {ProductGenerationData} from "./ProductGenerationData";
import {ProductGeneratorResult} from "./ProductGeneratorResult";
import {State} from "../states/State";
import {ProductState} from "../states/ProductState";
import {ScriptAccountCondition} from "../conditions/ScriptAccountCondition";
import {ProductTransition} from "../transitions/ProductTransition";
import {Transition} from "../transitions/Transition";
import {ScriptAccountAction} from "../actions/ScriptAccountAction";
export class ProductGamesystemGenerator {
productGamesystem: ProductGamesystem
constructor(productGamesystem: ProductGamesystem) {
this.productGamesystem = productGamesystem;
}
generateFromChildsystems(): void {
if(this.productGamesystem.innerGamesystems.length < 2) return;
const leftInitialData = this.prepareChildsystemForGeneration(this.productGamesystem.innerGamesystems[0])
const rightInitialData = this.prepareChildsystemForGeneration(this.productGamesystem.innerGamesystems[1])
const initialGenerationResult = this.generateFromBinaryChildsystems(leftInitialData, rightInitialData);
for(let i=2; i<this.productGamesystem.innerGamesystems.length; i++) {
const leftData = initialGenerationResult.productGenerationData;
const rightData = this.prepareChildsystemForGeneration(this.productGamesystem.innerGamesystems[i]);
const generationResult = this.generateFromBinaryChildsystems(leftData, rightData);
this.productGamesystem.states = generationResult.states;
this.productGamesystem.transitions = generationResult.transitions;
}
}
private prepareChildsystemForGeneration(childsystem: Gamesystem<any, any>) {
if(childsystem instanceof ProductGamesystem) {
childsystem.productGamesystemGenerator.generateFromChildsystems();
}
return new ProductGenerationData(childsystem.states, childsystem.transitions)
}
private generateFromBinaryChildsystems(leftSystemData: ProductGenerationData, rightSystemData: ProductGenerationData): ProductGeneratorResult {
const generatedProductStates: ProductState[] = []
const generatedProductTransitions: ProductTransition[] = []
leftSystemData.states.forEach(leftState => {
rightSystemData.states.forEach(rightState => {
for(let i=0; i<leftState.outgoingTransitions.length; i++) {
for(let j=0; j<rightState.outgoingTransitions.length; j++) {
const startingState = this.generateBinaryProductState(leftState, rightState, generatedProductStates);
if(startingState != undefined) {
generatedProductStates.push(startingState);
const endingState_right = this.generateBinaryProductState(leftState, rightState.outgoingTransitions[j].endingState, generatedProductStates);
if(endingState_right != undefined) {
const transition_right = this.generateBinaryProductTransition(startingState, endingState_right, rightState.outgoingTransitions[j])
generatedProductTransitions.push(transition_right)
generatedProductStates.push(endingState_right)
}
const endingState_left = this.generateBinaryProductState(leftState.outgoingTransitions[i].endingState, rightState, generatedProductStates);
if(endingState_left != undefined) {
const transition = this.generateBinaryProductTransition(startingState, endingState_left, leftState.outgoingTransitions[i])
generatedProductTransitions.push(transition)
generatedProductStates.push(endingState_left)
}
const endingState_left_right = this.generateBinaryProductState(leftState.outgoingTransitions[i].endingState, rightState.outgoingTransitions[j].endingState, generatedProductStates);
if(endingState_left_right != undefined) {
const leftConditions = leftState.outgoingTransitions[i].scriptAccountConditions;
const rightConditions = rightState.outgoingTransitions[j].scriptAccountConditions;
if(!this.contradictCombinedConditions(leftConditions, rightConditions)) {
const transition = new ProductTransition(startingState, endingState_left_right)
transition.scriptAccountActions = this.generateCombinedActions(leftState.outgoingTransitions[i].scriptAccountActions, rightState.outgoingTransitions[j].scriptAccountActions);
transition.scriptAccountConditions = this.generateCombinedConditions(leftState.outgoingTransitions[i].scriptAccountConditions, rightState.outgoingTransitions[j].scriptAccountConditions);
generatedProductTransitions.push(transition)
generatedProductStates.push(endingState_left_right)
}
}
}
}
if(rightState.outgoingTransitions.length == 0) {
const startingState = this.generateBinaryProductState(leftState, rightState, generatedProductStates);
const endingState = this.generateBinaryProductState(leftState.outgoingTransitions[i].endingState, rightState, generatedProductStates);
if(startingState != undefined && endingState != undefined) {
generatedProductStates.push(startingState)
generatedProductStates.push(endingState)
const transition = this.generateBinaryProductTransition(startingState, endingState, leftState.outgoingTransitions[i])
generatedProductTransitions.push(transition)
}
}
}
if(leftState.outgoingTransitions.length == 0) {
for(let j=0; j<rightState.outgoingTransitions.length; j++) {
const startingState = this.generateBinaryProductState(leftState, rightState, generatedProductStates);
const endingState = this.generateBinaryProductState(leftState, rightState.outgoingTransitions[j].endingState, generatedProductStates);
if(startingState != undefined && endingState != undefined) {
generatedProductStates.push(startingState)
generatedProductStates.push(endingState)
const transition = this.generateBinaryProductTransition(startingState, endingState, rightState.outgoingTransitions[j]);
generatedProductTransitions.push(transition)
}
}
}
})
})
return new ProductGeneratorResult(generatedProductStates, generatedProductTransitions);
}
private generateBinaryProductTransition(startingState: ProductState, endingState: ProductState, usedTransition: Transition<any>) {
const transition = new ProductTransition(startingState, endingState);
transition.scriptAccountActions = [... usedTransition.scriptAccountActions];
transition.scriptAccountConditions = [... usedTransition.scriptAccountConditions];
return transition;
}
private generateBinaryProductState(leftState: State<any>, rightState: State<any>, generatedStates: ProductState[]): ProductState | undefined {
const combinedStateConditions: ScriptAccountCondition[] = leftState.conditions.concat(rightState.conditions);
for(let i=0; i<combinedStateConditions.length; i++) {
for(let j=0; j<combinedStateConditions.length; j++) {
if(combinedStateConditions[i].isContradicting(combinedStateConditions[j])) {
return undefined
}
}
}
const innerStates: State<any>[] = leftState.getInnerStates().concat(rightState.getInnerStates())
let binaryProductState: ProductState | undefined = this.findGeneratedProductState(innerStates, generatedStates);
if(binaryProductState == undefined) {
binaryProductState = new ProductState(innerStates);
}
binaryProductState.determineInitialProperty()
binaryProductState.conditions = combinedStateConditions;
return binaryProductState;
}
private findGeneratedProductState(innerStates: State<any>[], productStates: ProductState[]) {
return undefined
}
private generateCombinedActions(leftActions: ScriptAccountAction[], rightActions: ScriptAccountAction[]): ScriptAccountAction[] {
const combinedActions: ScriptAccountAction[] = []
for(let i=0; i<leftActions.length; i++) {
for(let j=0; j<rightActions.length; j++) {
const combinedAction = leftActions[i].combineActions(rightActions[j])
if(combinedAction == undefined) {
if(!combinedActions.includes(leftActions[i])) {
combinedActions.push(leftActions[i])
}
if(!combinedActions.includes(rightActions[j])) {
combinedActions.push(rightActions[j])
}
} else {
combinedActions.push(combinedAction)
}
}
}
return combinedActions;
}
private generateCombinedConditions(leftConditions: ScriptAccountCondition[], rightConditions: ScriptAccountCondition[]): ScriptAccountCondition[] {
const combinedConditions: ScriptAccountCondition[] = [];
for(let i=0; i<leftConditions.length; i++) {
for(let j=0; j<rightConditions.length; j++) {
const combinedCondition = leftConditions[i].combineCondition(rightConditions[j]);
if(combinedCondition == undefined) {
if(!combinedConditions.includes(leftConditions[i])) {
combinedConditions.push(leftConditions[i])
}
if(!combinedConditions.includes(rightConditions[j])) {
combinedConditions.push(rightConditions[j])
}
} else {
combinedConditions.push(combinedCondition)
}
}
}
return combinedConditions;
}
private contradictCombinedConditions(leftConditions: ScriptAccountCondition[], rightConditions: ScriptAccountCondition[]): boolean {
for(let i=0; i<leftConditions.length; i++) {
for(let j=0; j<rightConditions.length; j++) {
if(leftConditions[i].isContradicting(rightConditions[j])) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,13 @@
import {State} from "../states/State";
import {Transition} from "../transitions/Transition";
export class ProductGenerationData {
states: State<any>[]
transitions: Transition<any>[]
constructor(states: State<any>[], transitions: Transition<any>[]) {
this.states = states;
this.transitions = transitions;
}
}

View File

@ -0,0 +1,18 @@
import {ProductState} from "../states/ProductState";
import {ProductTransition} from "../transitions/ProductTransition";
import {ProductGenerationData} from "./ProductGenerationData";
export class ProductGeneratorResult {
states: ProductState[];
transitions: ProductTransition[]
constructor(states: ProductState[], transitions: ProductTransition[]) {
this.states = states;
this.transitions = transitions;
}
get productGenerationData(): ProductGenerationData {
return new ProductGenerationData(this.states, this.transitions)
}
}

View File

@ -0,0 +1,5 @@
import {AbstractProductGamesystemGenerator} from "./AbstractProductGamesystemGenerator";
export class ProductTemplateGamesystemGenerator extends AbstractProductGamesystemGenerator{
}

View File

@ -50,4 +50,18 @@ export class ProductState extends State<ProductTransition> {
return false;
}
getInnerStates(): SimpleState[] {
let innerStates: SimpleState[] = [];
this.innerStates.forEach(innerState =>
innerStates = innerStates.concat(innerState.getInnerStates())
)
return innerStates;
}
determineInitialProperty() {
this.initial = true;
this.innerStates.forEach(innerState => this.initial = this.innerStates && innerState.initial)
}
}

View File

@ -20,5 +20,10 @@ export class SimpleState extends State<SimpleTransition> {
return this.stateLabel === (state as SimpleState).stateLabel;
}
getInnerStates(): SimpleState[] {
return [this]
}
}

View File

@ -1,6 +1,7 @@
import {Transition} from "../transitions/Transition";
import {ScriptAccountCondition} from "../conditions/ScriptAccountCondition";
import {ScriptAccount} from "../../scriptAccounts/ScriptAccount";
import {SimpleState} from "./SimpleState";
export abstract class State<T extends Transition<any>> {
@ -47,4 +48,6 @@ export abstract class State<T extends Transition<any>> {
}
abstract equals(state: State<Transition<any>>): boolean;
abstract getInnerStates(): SimpleState[];
}