Skip to content

Commit

Permalink
Run gdformat.
Browse files Browse the repository at this point in the history
  • Loading branch information
fire committed Dec 28, 2023
1 parent 560700e commit 163afd8
Show file tree
Hide file tree
Showing 16 changed files with 952 additions and 170 deletions.
40 changes: 34 additions & 6 deletions addons/task_goal/core/domain.gd
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,44 @@ var _unigoal_method_dict: Dictionary = {}

var _multigoal_method_list: Array = []

func _m_verify_g(state: Dictionary, method: String, state_var: String, arg: String, desired_val: Variant, depth: int) -> Variant:

func _m_verify_g(
state: Dictionary,
method: String,
state_var: String,
arg: String,
desired_val: Variant,
depth: int
) -> Variant:
if state[state_var][arg] != desired_val:
if verbose >= 3:
print("Depth %s: method %s didn't achieve\nGoal %s[%s] = %s" % [depth, method, state_var, arg, desired_val])
print(
(
"Depth %s: method %s didn't achieve\nGoal %s[%s] = %s"
% [depth, method, state_var, arg, desired_val]
)
)
return false

if state.has("stn"):
for p in state["stn"].keys():
if not state["stn"][p].is_consistent():
if verbose >= 3:
print("Depth %s: method %s resulted in inconsistent STN for %s" % [depth, method, p])
print(
(
"Depth %s: method %s resulted in inconsistent STN for %s"
% [depth, method, p]
)
)
return false

if verbose >= 3:
print("Depth %s: method %s achieved\nGoal %s[%s] = %s" % [depth, method, state_var, arg, desired_val])
print(
(
"Depth %s: method %s achieved\nGoal %s[%s] = %s"
% [depth, method, state_var, arg, desired_val]
)
)
return []


Expand All @@ -70,7 +93,12 @@ func _m_verify_mg(state: Dictionary, method: String, multigoal: Multigoal, depth
for p in state["stn"].keys():
if not state["stn"][p].is_consistent():
if verbose >= 3:
print("Depth %s: method %s resulted in inconsistent STN for %s" % [depth, method, p])
print(
(
"Depth %s: method %s resulted in inconsistent STN for %s"
% [depth, method, p]
)
)
return false

if verbose >= 3:
Expand Down
59 changes: 46 additions & 13 deletions addons/task_goal/core/plan.gd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright (c) 2023-present. This file is part of V-Sekai https://v-sekai.org/.
# K. S. Ernest (Fire) Lee & Contributors (see .all-contributorsrc).
# plan.gd
# plan.gd
# SPDX-License-Identifier: MIT

# SPDX-FileCopyrightText: 2021 University of Maryland
Expand Down Expand Up @@ -40,6 +40,7 @@ var _next_domain_number: int = 0

const _domain_const = preload("domain.gd")


## Print domain's actions, commands, and methods. The optional 'domain'
## argument defaults to the current domain
func print_domain(domain: Object = null) -> void:
Expand Down Expand Up @@ -284,7 +285,9 @@ var verify_goals: bool = true


## Actions in HTN are atomic units of work, representing the simplest tasks that can't be further broken down. Actions often called primitives.
func _apply_action_and_continue(state: Dictionary, task1: Array, todo_list: Array, plan: Array, depth: int) -> Variant:
func _apply_action_and_continue(
state: Dictionary, task1: Array, todo_list: Array, plan: Array, depth: int
) -> Variant:
var action: Callable = current_domain._action_dict[task1[0]]
if verbose >= 2:
print("Depth %s, Action %s: " % [depth, str([action.get_method()] + task1.slice(1))])
Expand All @@ -300,11 +303,15 @@ func _apply_action_and_continue(state: Dictionary, task1: Array, todo_list: Arra
print("Task: ", task1)
print("State: ", state)
if verbose >= 2:
print("Recursive call: Not applicable action: ", str([action.get_method()] + task1.slice(1)))
print(
"Recursive call: Not applicable action: ", str([action.get_method()] + task1.slice(1))
)
return false


func _refine_task_and_continue(state: Dictionary, task1: Array, todo_list: Array, plan: Array, depth: int) -> Variant:
func _refine_task_and_continue(
state: Dictionary, task1: Array, todo_list: Array, plan: Array, depth: int
) -> Variant:
var relevant: Array = current_domain._task_method_dict[task1[0]]
if verbose >= 3:
var string_array: PackedStringArray = []
Expand All @@ -314,12 +321,14 @@ func _refine_task_and_continue(state: Dictionary, task1: Array, todo_list: Array
for method in relevant:
if verbose >= 2:
print("Depth %s, Trying method %s: " % [depth, method.get_method()])
var subtasks: Variant = method.get_object().callv(method.get_method(), [state] + task1.slice(1))
var subtasks: Variant = method.get_object().callv(
method.get_method(), [state] + task1.slice(1)
)
if subtasks is Array:
if verbose >= 3:
print("Intermediate computation: Method applicable.")
print("Depth %s, Subtasks: %s" % [depth, subtasks])

var result: Variant = seek_plan(state, subtasks + todo_list, plan, depth + 1)
if result is Array:
return result
Expand All @@ -328,7 +337,9 @@ func _refine_task_and_continue(state: Dictionary, task1: Array, todo_list: Array
return false


func _refine_unigoal_and_continue(state: Dictionary, goal1: Array, todo_list: Array, plan: Array, depth: int) -> Variant:
func _refine_unigoal_and_continue(
state: Dictionary, goal1: Array, todo_list: Array, plan: Array, depth: int
) -> Variant:
if verbose >= 3:
print("Depth %s, Goal %s: " % [depth, goal1])

Expand Down Expand Up @@ -362,7 +373,9 @@ func _refine_unigoal_and_continue(state: Dictionary, goal1: Array, todo_list: Ar
var verification = []

if verify_goals:
verification = [["_verify_g", str(method.get_method()), state_var_name, arg, val, depth]]
verification = [
["_verify_g", str(method.get_method()), state_var_name, arg, val, depth]
]
else:
verification = []

Expand All @@ -378,7 +391,9 @@ func _refine_unigoal_and_continue(state: Dictionary, goal1: Array, todo_list: Ar
return false


func _refine_multigoal_and_continue(state: Dictionary, goal1: Multigoal, todo_list: Array, plan: Array, depth: int) -> Variant:
func _refine_multigoal_and_continue(
state: Dictionary, goal1: Multigoal, todo_list: Array, plan: Array, depth: int
) -> Variant:
if verbose >= 3:
print("Depth %s, Multigoal %s: " % [depth, goal1])

Expand Down Expand Up @@ -489,7 +504,12 @@ func _item_to_string(item):
## no corresponding command definition, it uses the action definition instead.
func run_lazy_lookahead(state: Dictionary, todo_list: Array, max_tries: int = 10) -> Dictionary:
if verbose >= 1:
print("RunLazyLookahead> run_lazy_lookahead, verbose = %s, max_tries = %s" % [verbose, max_tries])
print(
(
"RunLazyLookahead> run_lazy_lookahead, verbose = %s, max_tries = %s"
% [verbose, max_tries]
)
)
print("RunLazyLookahead> initial state: %s" % [state.keys()])
print("RunLazyLookahead> To do:", todo_list)

Expand All @@ -500,12 +520,20 @@ func run_lazy_lookahead(state: Dictionary, todo_list: Array, max_tries: int = 10
print("RunLazyLookahead> %s%s call to find_plan:" % [tries, ordinals.get(tries, "")])

var plan = find_plan(state, todo_list)
if plan == null or (typeof(plan) == TYPE_ARRAY and plan.is_empty()) or (typeof(plan) == TYPE_DICTIONARY and !plan):
if (
plan == null
or (typeof(plan) == TYPE_ARRAY and plan.is_empty())
or (typeof(plan) == TYPE_DICTIONARY and !plan)
):
if verbose >= 1:
print("run_lazy_lookahead: find_plan has failed")
return state

if plan == null or (typeof(plan) == TYPE_ARRAY and plan.is_empty()) or (typeof(plan) == TYPE_DICTIONARY and !plan):
if (
plan == null
or (typeof(plan) == TYPE_ARRAY and plan.is_empty())
or (typeof(plan) == TYPE_DICTIONARY and !plan)
):
if verbose >= 1:
print("RunLazyLookahead> Empty plan => success\nafter {tries} calls to find_plan.")
if verbose >= 2:
Expand All @@ -525,7 +553,12 @@ func run_lazy_lookahead(state: Dictionary, todo_list: Array, max_tries: int = 10
state = new_state
else:
if verbose >= 1:
print("RunLazyLookahead> WARNING: action %s failed; will call find_plan." % [action_name])
print(
(
"RunLazyLookahead> WARNING: action %s failed; will call find_plan."
% [action_name]
)
)
break

if verbose >= 1 and state != null:
Expand Down
62 changes: 51 additions & 11 deletions addons/task_goal/core/simple_temporal_network.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var node_indices: Dictionary = {}

var node_index_cache = {}


func _to_string() -> String:
if resource_name.is_empty():
return "SimpleTemporalNetwork"
Expand All @@ -40,12 +41,20 @@ var outgoing_edges: Dictionary = {}
func check_overlap(new_constraint: TemporalConstraint) -> bool:
for constraint in constraints:
if constraint.resource_name == new_constraint.resource_name:
if (constraint.time_interval.x < new_constraint.time_interval.y) and (new_constraint.time_interval.x < constraint.time_interval.y):
if (
(constraint.time_interval.x < new_constraint.time_interval.y)
and (new_constraint.time_interval.x < constraint.time_interval.y)
):
return true
return false


func add_temporal_constraint(from_constraint: TemporalConstraint, to_constraint: TemporalConstraint = null, min_gap: float = 0, max_gap: float = 0) -> bool:
func add_temporal_constraint(
from_constraint: TemporalConstraint,
to_constraint: TemporalConstraint = null,
min_gap: float = 0,
max_gap: float = 0
) -> bool:
if not validate_constraints(from_constraint, to_constraint, min_gap, max_gap):
print("Failed to validate constraints")
return false
Expand Down Expand Up @@ -85,11 +94,18 @@ func update_constraints_list(constraint: TemporalConstraint, node: TemporalConst

## This function validates the constraints and returns a boolean value.
func validate_constraints(from_constraint, to_constraint, min_gap: float, max_gap: float) -> bool:
if not from_constraint or not from_constraint.get("time_interval") or not from_constraint.get("duration"):
if (
not from_constraint
or not from_constraint.get("time_interval")
or not from_constraint.get("duration")
):
print("Invalid from_constraint %s" % from_constraint)
return false

if from_constraint['duration'] > (from_constraint['time_interval'][1] - from_constraint['time_interval'][0]):
if (
from_constraint["duration"]
> (from_constraint["time_interval"][1] - from_constraint["time_interval"][0])
):
print("Duration is longer than time interval for from_constraint %s" % from_constraint)
return false

Expand All @@ -99,20 +115,29 @@ func validate_constraints(from_constraint, to_constraint, min_gap: float, max_ga
print("Invalid to_constraint %s" % to_constraint)
return false

if to_constraint['duration'] > (to_constraint['time_interval'][1] - to_constraint['time_interval'][0]):
if (
to_constraint["duration"]
> (to_constraint["time_interval"][1] - to_constraint["time_interval"][0])
):
print("Duration is longer than time interval for to_constraint %s" % to_constraint)
return false

# Check if min_gap and max_gap are valid
if typeof(min_gap) != TYPE_FLOAT or min_gap < 0 or (typeof(max_gap) != TYPE_FLOAT and max_gap != INF):
if (
typeof(min_gap) != TYPE_FLOAT
or min_gap < 0
or (typeof(max_gap) != TYPE_FLOAT and max_gap != INF)
):
print("Invalid gap values")
return false

return true


## This function adds the constraints to the list.
func add_constraints_to_list(from_constraint: TemporalConstraint, to_constraint: TemporalConstraint):
func add_constraints_to_list(
from_constraint: TemporalConstraint, to_constraint: TemporalConstraint
):
if from_constraint:
constraints.append(from_constraint)
if to_constraint:
Expand Down Expand Up @@ -153,8 +178,18 @@ func is_consistent() -> bool:
constraints.sort_custom(TemporalConstraint.sort_func)
for i in range(constraints.size()):
for j in range(i + 1, constraints.size()):
if constraints[i].time_interval.y > constraints[j].time_interval.x and constraints[i].time_interval.x < constraints[j].time_interval.y:
print("Overlapping constraints: " + str(constraints[i]) + " and " + str(constraints[j]))
if (
constraints[i].time_interval.y > constraints[j].time_interval.x
and constraints[i].time_interval.x < constraints[j].time_interval.y
):
print(
(
"Overlapping constraints: "
+ str(constraints[i])
+ " and "
+ str(constraints[j])
)
)
return false
var decompositions = enumerate_decompositions(constraints[i])
if decompositions.is_empty():
Expand All @@ -171,7 +206,6 @@ func enumerate_decompositions(vertex: TemporalConstraint) -> Array[Array]:
var leafs: Array[Array] = [[]]

if is_leaf(vertex):

leafs.append([vertex])
else:
if is_or(vertex):
Expand Down Expand Up @@ -226,5 +260,11 @@ func update_state(state: Dictionary) -> void:
for key in state:
var value = state[key]
if value is TemporalConstraint:
var constraint = TemporalConstraint.new(value.time_interval.x, value.time_interval.y, value.duration, value.temporal_qualifier, value.resource_name)
var constraint = TemporalConstraint.new(
value.time_interval.x,
value.time_interval.y,
value.duration,
value.temporal_qualifier,
value.resource_name
)
add_temporal_constraint(constraint)
14 changes: 12 additions & 2 deletions addons/task_goal/core/temporal_constraint.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@ func _init(start: int, end: int, duration: int, qualifier: TemporalQualifier, re


func _to_string() -> String:
return str({"resource_name": resource_name, "time_interval": time_interval, "duration": duration, "temporal_qualifier": temporal_qualifier})
return str(
{
"resource_name": resource_name,
"time_interval": time_interval,
"duration": duration,
"temporal_qualifier": temporal_qualifier
}
)


static func sort_func(a: TemporalConstraint, b: TemporalConstraint) -> bool:
return a.time_interval.x < b.time_interval.x or (a.time_interval.x == b.time_interval.x and a.time_interval.y < b.time_interval.y)
return (
a.time_interval.x < b.time_interval.x
or (a.time_interval.x == b.time_interval.x and a.time_interval.y < b.time_interval.y)
)
18 changes: 14 additions & 4 deletions goal_task_tests/core/test_constraints.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,32 @@ extends "res://addons/gut/test.gd"

var stn = null


func test_is_consistent_with_no_constraints() -> void:
stn = SimpleTemporalNetwork.new()
assert_true(stn.is_consistent(), "An empty STN should be consistent")


func test_is_consistent_with_one_constraint() -> void:
stn = SimpleTemporalNetwork.new()
var constraint = TemporalConstraint.new(0, 10, 5, TemporalConstraint.TemporalQualifier.AT_START, "some_resource")
var constraint = TemporalConstraint.new(
0, 10, 5, TemporalConstraint.TemporalQualifier.AT_START, "some_resource"
)
stn.add_temporal_constraint(constraint)
assert_true(stn.is_consistent(), "An STN with one constraint should be consistent")


func test_is_consistent_with_inconsistent_constraints() -> void:
stn = SimpleTemporalNetwork.new()
var constraint1 = TemporalConstraint.new(0, 10, 5, TemporalConstraint.TemporalQualifier.AT_START, "resource1")
var constraint2 = TemporalConstraint.new(5, 15, 10, TemporalConstraint.TemporalQualifier.AT_START, "resource2")
var constraint1 = TemporalConstraint.new(
0, 10, 5, TemporalConstraint.TemporalQualifier.AT_START, "resource1"
)
var constraint2 = TemporalConstraint.new(
5, 15, 10, TemporalConstraint.TemporalQualifier.AT_START, "resource2"
)
stn.add_temporal_constraint(constraint1)
assert_true(stn.is_consistent(), "An STN with overlapping constraints should not be consistent")
assert_false(stn.check_overlap(constraint2), "An STN with overlapping constraints should not be consistent")
assert_false(
stn.check_overlap(constraint2),
"An STN with overlapping constraints should not be consistent"
)
Loading

0 comments on commit 163afd8

Please sign in to comment.