the-great-game/src/cc/journeyman/the_great_game/agent/agent.clj
Simon Brooke 81ceaec950 Added ideas about scheduling daily behaviour.
All tests currently pass, but that's at least partly because a lot of the new code doesn't yet have tests.
2024-01-02 21:00:20 +00:00

112 lines
5.5 KiB
Clojure
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(ns cc.journeyman.the-great-game.agent.agent
"Anything in the game world with agency; primarily but not exclusively
characters."
(:require [cc.journeyman.the-great-game.objects.game-object :refer [ProtoObject]]
[cc.journeyman.the-great-game.objects.container :refer [ProtoContainer]]))
;;; hierarchy of needs probably gets implemented here
;;; I'm probably going to want to defprotocol stuff, to define the hierarchy
;;; of things in the gameworld; either that or drop to Java, wich I'd rather not do.
;;; attitudes - liking/disliking, attraction/repulsion, amity/hostility, trust/fear
;;; also need to live at this layer, even though dynamic change in attitudes belongs
;;; in the character layer.
(defprotocol ProtoAgent
"An object which can act in the world"
(act
[actor world circle]
"Allow `actor` to do something in this `world`, in the context of this
`circle`; return the new state of the actor if something was done, `nil`
if nothing was done. `Circle` is expected to be one of
* `:active` - actors within visual/audible range of the player
character;
* `:pending` - actors not in the active circle, but sufficiently close
to it that they may enter the active circle within a short period;
* `:background` - actors who are active in the background in order to
handle trade, news, et cetera;
* `:other` - actors who are not members of any other circle.
The `act` method *must not* have side effects; it must *only* return a
new state. If the actor's intention is to seek to change the state of
something else in the game world, it must add a representation of that
intention to the sequence which will be returned by its
`pending-intentions` method.")
(hungry? [actor world circle] "True if this actor is hungry and has no
immediate access to food.")
(pending-intentions
[actor]
"Returns a sequence of effects an actor intends, as a consequence of
acting.")
(pending-scheduled-action? [actor world circle]
"True if there is a plan in this `actor`'s
schedule which should be activated now.
NOTE THAT plans in the `daily` schedule are
NOT activated when in circles `:background`
or `:other`")
(plan-fight-or-flight [actor world circle]
"Return a plan to resolve any active threat to this
`actor` in this `world`.")
(plan-find-food [actor workd circle]
"Return a plan to find this `actor` food in this `world`.")
(plan-find-rest [actor workd circle]
"Return a plan to find this `actor` a safe place to rest, or
if in one, to actually rest, in this `world`.")
(plan-goal [actor world circle] "Return a plan to advance this `actor`
towards their personal objective, in this
world, or `nil` for default actors with no
objective.")
(plan-scheduled-action [actor workd circle]
"Return a plan taken from the schedule of this actor
for the current date and time, if any, else `nil`.")
(schedule [actor] "Return a map of scheduled actions for this `actor`.
TODO: work out the detailed format!")
(threatened? [actor world circle] "True if this `actor` is threatened in this
`world`.")
(tired? [actor world circle] "True if this `actor` needs rest."))
(defrecord Agent
;; "A default agent."
[name craft home culture]
ProtoObject
ProtoContainer
ProtoAgent
(act
Return a world like this `world `except that this `actor `has acted in it.
Circle indicates which activation circle the actor is in.
Note that this implies that a `plan `is a function of three arguments, an
actor, a world. and a circle.
[actor world circle]
(let [urgent (case circle
:other (cond
(pending-scheduled-action? actor world circle)
(plan-scheduled-action actor world circle)
(empty? (:plans actor))
(plan-goal actor world circle))
:background (cond
(threatened? actor world circle)
(plan-fight-or-flight actor world circle)
(pending-scheduled-action? actor world circle)
(plan-scheduled-action actor world circle)
(empty? (:plans actor))
(plan-goal actor world circle))
;; else
(cond
(threatened? actor world circle)
(plan-fight-or-flight actor world circle)
(hungry? actor world circle)
(plan-find-food actor world circle)
(tired? actor world circle)
(plan-find-rest actor world circle)
(pending-scheduled-action? actor world circle)
(plan-scheduled-action actor world circle)
(empty? (:plans actor))
(plan-goal actor world circle)))
a (if urgent
(assoc actor :plans (cons urgent (:plans actor)))
actor)]
(eval ((first (:plans a)) a world)))))