Merge pull request #154 from hppeng-wynn/atree-assassin

assassin ability tree implementation
This commit is contained in:
hppeng-wynn 2022-07-20 09:39:47 -07:00 committed by GitHub
commit 90ce005485
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 6938 additions and 1300 deletions

View file

@ -41,8 +41,8 @@ add_spell_prop: {
// If target part does not exist, a new part is created.
behavior: Optional[str] // One of: "merge", "modify". default: merge
// merge: add if exist, make new part if not exist
// modify: change existing part. do nothing if not exist
cost: Optional[int] // change to spellcost
// modify: increment existing part. do nothing if not exist
cost: Optional[int] // change to spellcost. If the spell is not spell 1-4, this must be left empty.
multipliers: Optional[array[float, 6]] // Additive changes to spellmult (for damage spell)
power: Optional[float] // Additive change to healing power (for heal spell)
hits: Optional[Map[str, float]] // Additive changes to hits (for total entry)
@ -62,7 +62,7 @@ raw_stat: {
// string value means bind to (or create) named button
behavior: Optional[str] // One of: "merge", "modify". default: merge
// merge: add if exist, make new part if not exist
// modify: change existing part. do nothing if not exist
// modify: increment existing part. do nothing if not exist
bonuses: List[stat_bonus]
}
stat_bonus: {
@ -170,40 +170,23 @@ const atree_node = new (class extends ComputeNode {
}
node.parents = parents;
}
console.log(atree_map);
let sccs = make_SCC_graph(atree_head, atree_map.values());
let atree_topo_sort = [];
topological_sort_tree(atree_head, atree_topo_sort, new Map());
atree_topo_sort.reverse();
for (const scc of sccs) {
for (const node of scc.nodes) {
delete node.visited;
delete node.assigned;
delete node.scc;
atree_topo_sort.push(node);
}
}
console.log("Approximate topological order ability tree:");
console.log(atree_topo_sort);
return atree_topo_sort;
}
})();
/**
* Create a reverse topological sort of the tree in the result list.
* NOTE: our structure isn't a tree... it isn't even acyclic... but do it anyway i guess...
*
* https://en.wikipedia.org/wiki/Topological_sorting
* @param tree: Root of tree to sort
* @param res: Result list (reverse topological order)
* @param mark_state: Bookkeeping. Call with empty Map()
*/
function topological_sort_tree(tree, res, mark_state) {
const state = mark_state.get(tree);
if (state === undefined) {
// unmarked.
mark_state.set(tree, false); // temporary mark
for (const child of tree.children) {
topological_sort_tree(child, res, mark_state);
}
mark_state.set(tree, true); // permanent mark
res.push(tree);
}
// these cases are not needed. Case 1 does nothing, case 2 should never happen.
// else if (state === true) { return; } // permanent mark.
// else if (state === false) { throw "not a DAG"; } // temporary mark.
}
/**
* Display ability tree from topologically sorted list.
*

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -223,21 +223,15 @@ function construct_scc_graph(items_to_consider) {
let terminal_node = {
item: null,
children: [],
parents: nodes,
visited: false,
assigned: false,
scc: null
parents: nodes
};
let root_node = {
item: null,
children: nodes,
parents: [],
visited: false,
assigned: false,
scc: null
};
for (const item of items_to_consider) {
nodes.push({item: item, children: [terminal_node], parents: [root_node], visited: false, assigned: false, scc: null});
nodes.push({item: item, children: [terminal_node], parents: [root_node]});
}
// Dependency graph construction.
for (const node_a of nodes) {
@ -253,50 +247,6 @@ function construct_scc_graph(items_to_consider) {
}
}
}
const res = []
/*
* SCC graph construction.
* https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
*/
function visit(u, res) {
if (u.visited) { return; }
u.visited = true;
for (const child of u.children) {
if (!child.visited) { visit(child, res); }
}
res.push(u);
}
visit(root_node, res);
res.reverse();
const sccs = [];
function assign(node, cur_scc) {
if (node.assigned) { return; }
cur_scc.nodes.push(node);
node.scc = cur_scc;
node.assigned = true;
for (const parent of node.parents) {
assign(parent, cur_scc);
}
}
for (const node of res) {
if (node.assigned) { continue; }
const cur_scc = {
nodes: [],
children: new Set(),
parents: new Set()
};
assign(node, cur_scc);
sccs.push(cur_scc);
}
for (const scc of sccs) {
for (const node of scc.nodes) {
for (const child of node.children) {
scc.children.add(child.scc);
}
for (const parent of node.parents) {
scc.parents.add(parent.scc);
}
}
}
const sccs = make_SCC_graph(root_node, nodes);
return [root_node, terminal_node, sccs];
}

View file

@ -889,3 +889,67 @@ function make_elem(type, classlist = [], args = {}) {
}
return ret_elem;
}
/**
* Nodes must have:
* node: {
* parents: List[node]
* children: List[node]
* }
*
* This function will define: "visited, assigned, scc" properties
* Assuming a connected graph. (only one root)
*/
function make_SCC_graph(root_node, nodes) {
for (const node of nodes) {
node.visited = false;
node.assigned = false;
node.scc = null;
}
const res = []
/*
* SCC graph construction.
* https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
*/
function visit(u, res) {
if (u.visited) { return; }
u.visited = true;
for (const child of u.children) {
if (!child.visited) { visit(child, res); }
}
res.push(u);
}
visit(root_node, res);
res.reverse();
const sccs = [];
function assign(node, cur_scc) {
if (node.assigned) { return; }
cur_scc.nodes.push(node);
node.scc = cur_scc;
node.assigned = true;
for (const parent of node.parents) {
assign(parent, cur_scc);
}
}
for (const node of res) {
if (node.assigned) { continue; }
const cur_scc = {
nodes: [],
children: new Set(),
parents: new Set()
};
assign(node, cur_scc);
sccs.push(cur_scc);
}
for (const scc of sccs) {
for (const node of scc.nodes) {
for (const child of node.children) {
scc.children.add(child.scc);
}
for (const parent of node.parents) {
scc.parents.add(parent.scc);
}
}
}
return sccs;
}