Recent from talks
Nothing was collected or created yet.
Blackboard (design pattern)
View on WikipediaIn software engineering, the blackboard pattern is a behavioral design pattern[1] that provides a computational framework for the design and implementation of systems that integrate large and diverse specialized modules, and implement complex, non-deterministic control strategies.[2][1]
This pattern was identified by the members of the Hearsay-II project and first applied to speech recognition.[2]
Structure
[edit]The blackboard model defines three main components:
- blackboard—a structured global memory containing objects from the solution space
- knowledge sources—specialized modules with their own representation
- control component—selects, configures and executes modules.[2]
Implementation
[edit]The first step is to design the solution space (i.e. potential solutions) that leads to the blackboard structure. Then, knowledge sources are identified. These two activities are closely related.[2]
The next step is to specify the control component; it generally takes the form of a complex scheduler that makes use of a set of domain-specific heuristics to rate the relevance of executable knowledge sources.[2]

Applications
[edit]Usage-domains include:
- speech recognition
- vehicle identification and tracking
- protein structure identification
- sonar signals interpretation.[2]
Consequences
[edit]The blackboard pattern provides effective solutions for designing and implementing complex systems where heterogeneous modules have to be dynamically combined to solve a problem. This provides non-functional properties such as:
- reusability
- changeability
- robustness.[2]
The blackboard pattern allows multiple processes to work closer together on separate threads, polling and reacting when necessary.[1]
See also
[edit]References
[edit]Blackboard (design pattern)
View on GrokipediaOverview
Definition and Metaphor
The blackboard design pattern is a collaborative problem-solving architecture in artificial intelligence and software engineering, where independent modules known as knowledge sources contribute incrementally to resolving complex problems by reading from and writing to a central shared data structure called the blackboard. This pattern facilitates the integration of diverse expertise without requiring direct communication between modules, enabling opportunistic and emergent solution development. Originating in AI research, it structures systems to handle ill-defined or dynamic problems by allowing partial solutions to evolve through iterative contributions.[3] The metaphor underlying the pattern draws from a scenario of specialists gathered in a room around a large blackboard, collaboratively tackling a challenging problem; each expert observes the evolving content on the blackboard—such as partial results, hypotheses, or data—and adds their specialized insights without needing to interact directly with others. This shared workspace fosters incremental progress toward a complete solution, mirroring how the pattern's knowledge sources react to changes on the blackboard to propose refinements or extensions. The analogy emphasizes the blackboard's role as a dynamic repository that captures the evolving state of the problem, promoting flexibility and adaptability in problem-solving.[1] Key characteristics of the blackboard pattern include its support for opportunistic problem-solving, where contributions occur based on the current state rather than a fixed sequence; incremental solution building, allowing partial knowledge to accumulate toward completeness; and decoupling of knowledge from control, separating domain-specific expertise in knowledge sources from the mechanisms that orchestrate their activation. These features make the pattern particularly suited for domains requiring integration of heterogeneous reasoning methods, such as speech recognition or planning systems. The control shell, briefly, manages scheduling of knowledge sources based on blackboard events, ensuring coherent progress without centralizing all decision-making.[3]History and Origins
The blackboard design pattern originated in the early 1970s within artificial intelligence research at Carnegie Mellon University, emerging from efforts to model human-like problem-solving in complex domains such as speech understanding. It was first implemented in the Hearsay-I system around 1971–1972, which demonstrated connected-speech recognition, and evolved significantly in the Hearsay-II system (developed between 1971 and 1976) as part of the DARPA-funded Speech Understanding Project. These systems addressed the challenges of integrating diverse knowledge sources to interpret noisy acoustic signals, marking the initial application of the blackboard metaphor for opportunistic, collaborative reasoning.[4][5] Key contributors to its development included Lee D. Erman, Victor R. Lesser, F. Hayes-Roth, and D. Raj Reddy, who drew inspiration from cognitive science observations of how human experts collaborate on ill-defined tasks. The architecture was further refined in subsequent projects like HASP (1973–1975) for sonar signal interpretation and CRYSALIS (starting 1976) for protein structure analysis. Formalization of the blackboard model as a general framework came with Barbara Hayes-Roth's influential 1985 paper, which proposed a domain-independent blackboard control architecture capable of self-adaptation, explanation, and learning, building directly on the Hearsay and HASP experiences. This work, published in Artificial Intelligence, established core principles for control in blackboard systems.[6][7] In the late 1980s and 1990s, the blackboard approach transitioned from specialized AI expert systems—often rule-based and focused on domains like signal processing—to a recognized software design pattern, influenced by the rise of object-oriented programming paradigms. This evolution was documented in seminal texts such as Blackboard Systems (edited by Robert Engelmore and Tony Morgan, 1988), which compiled applications and frameworks, and later in pattern literature like Pattern-Oriented Software Architecture (Buschmann et al., 1996), where it was formalized as an architectural pattern for integrating heterogeneous modules. By the mid-1990s, it was applied beyond AI to support non-deterministic control in multi-expert systems, as explored in conference proceedings like PLoP 1997.[8][1] The early motivations for the blackboard pattern stemmed from the need to tackle ill-structured problems, where complete algorithms are infeasible due to incomplete information, large search spaces, and uncertain data—scenarios common in real-world AI tasks like speech or image recognition. Inspired by cognitive science models of human planning and opportunistic reasoning (e.g., observations by Allen Newell and Herbert Simon), it enabled incremental solution building through loosely coupled knowledge sources, mimicking collaborative expertise without rigid hierarchies. This focus on flexibility for dynamic, evolving problem states distinguished it from more deterministic expert system approaches of the era.[3][8]Core Components
The Blackboard
The blackboard serves as the central, shared repository in the blackboard design pattern, functioning as a global database that stores evolving problem states, partial solutions, hypotheses, and relevant domain knowledge.[9] It is characterized by its dynamic nature, allowing entries to be created, modified, or deleted as the problem-solving process unfolds, and its hierarchical organization, which accommodates information at multiple levels of abstraction, such as situational data (raw inputs and observations), solution elements (intermediate results), and control information (meta-level strategies).[3] This structure enables the representation of complex, ill-structured problems where the solution path is not predefined, drawing from early implementations like the Hearsay-II system.[7] Data on the blackboard is typically organized into levels or panels that reflect varying degrees of abstraction and granularity, facilitating efficient access and manipulation by system components. For instance, lower levels might hold fine-grained, domain-specific details, while higher levels aggregate coarser summaries or hypotheses, with links connecting related elements across levels to maintain coherence.[9] This partitioning supports notifications or events triggered by changes to specific entries, alerting other parts of the system to relevant updates without requiring direct polling.[3] Such organization ensures that the blackboard acts as a flexible "community memory," accommodating diverse data types and representations without imposing rigid schemas.[9] In the blackboard pattern, the blackboard functions as the exclusive medium for information exchange among independent modules, promoting modularity by decoupling knowledge sources and preventing direct interdependencies.[3] All contributions—whether raw data, partial analyses, or refined solutions—are posted to the blackboard, where they become visible to other components, fostering opportunistic, collaborative problem-solving.[7] This indirect communication mechanism enhances system extensibility, as new modules can be added to read from or write to the blackboard without altering existing ones.[9] Key design considerations for the blackboard include mechanisms for persistence to retain historical contributions, avoiding redundant recomputation; versioning to track changes in entries over time, which supports hypothesis evaluation and backtracking; and a focus of attention mechanism that highlights a relevant subset of the data based on the current problem state, thereby managing complexity in large-scale repositories.[3] These features, as exemplified in architectures like BB1, ensure scalability and maintainability in domains requiring incremental refinement.[10]Knowledge Sources
Knowledge sources in the blackboard design pattern are autonomous, independent modules that encapsulate specialized domain knowledge to contribute incrementally to problem-solving. These components operate as expert subsystems, each focusing on a particular aspect of the problem domain, and are typically categorized by their functional roles, such as data gatherers that collect and preprocess input, analyzers that evaluate patterns or hypotheses, and synthesizers that integrate partial solutions into coherent wholes. Examples of knowledge source types include rule-based experts that apply conditional logic to derive inferences, procedural algorithms that execute step-by-step computations, and machine learning models that perform predictive or classificatory tasks based on trained parameters.[3] Each knowledge source continuously monitors the blackboard for specific preconditions, such as the presence of particular data patterns, hypotheses, or solution fragments, which serve as triggers for activation. Upon detecting a relevant condition, the source executes its specialized operations independently and posts the resulting updates—such as new data, refined hypotheses, or modifications to existing entries—directly back to the blackboard for other sources to access. This reactive mechanism ensures that contributions are opportunistic and context-driven, allowing knowledge sources to respond dynamically to evolving problem states without direct interaction among themselves.[11] The design emphasizes autonomy and modularity, enabling individual knowledge sources to be developed, tested, replaced, or extended in isolation without impacting the overall system architecture. Preconditions for triggering are formally defined through patterns, queries, or event subscriptions on blackboard data structures, promoting loose coupling and facilitating scalability in complex applications. In the seminal Hearsay-II speech recognition system, for instance, knowledge sources included modules for phoneme detection to identify basic sound units, word hypothesis generation to propose lexical matches from acoustic segments, and syntax parsing to build grammatical structures from word sequences, demonstrating how specialized experts collaboratively refine interpretations of continuous speech.[8][12]Control Shell
The control shell serves as the meta-level controller in the blackboard design pattern, responsible for orchestrating the system's problem-solving dynamics by observing changes on the blackboard, evaluating activation opportunities for knowledge sources, and determining the sequence of their invocations.[9] It operates as an opportunistic director, ensuring that the system progresses incrementally toward a solution without a predefined linear path, adapting to emergent data states on the shared blackboard.[7] Key functions of the control shell include trigger detection, where it monitors blackboard events such as data additions, modifications, or absences to identify potential activation points; opportunity assessment, often involving scoring mechanisms that evaluate knowledge source relevance based on preconditions, urgency, or contextual fit; and execution sequencing, which prioritizes and orders invocations to maintain efficient progress.[9] Additionally, it incorporates a scheduler for conflict resolution, selecting among competing knowledge source activations using criteria like fixed priorities, dynamic utility weights, or first-in-first-out queues to resolve ambiguities when multiple sources are viable.[10] Various strategies underpin the control shell's operations, including rule-based approaches that apply if-then rules to decision-making, agenda-driven methods that maintain dynamic lists of pending actions for flexible prioritization, and heuristic techniques that employ domain-specific or adaptive evaluations to focus computational effort amid complexity.[9] These strategies support focus of control mechanisms, such as variable-grain heuristics, to manage large-scale systems by concentrating resources on high-impact opportunities while deferring less critical ones.[10] In terms of integration, the control shell interfaces directly with the blackboard to access current state information and post control directives, while invoking knowledge sources through standardized activation protocols that allow independent operation without tight coupling.[9] This design promotes modularity, enabling the control shell—often implemented as a separate blackboard for control knowledge in advanced variants like BB1—to facilitate non-deterministic, collaborative problem-solving.[10]Operational Mechanism
Problem-Solving Process
The problem-solving process in the blackboard design pattern begins with the posting of the initial problem on the blackboard, a shared data repository that represents the current state of the solution space.[13] This initiation triggers an iterative cycle involving opportunity recognition by the control shell, activation of relevant knowledge sources, contribution of partial solutions to the blackboard, and evaluation of the updated state to determine progress toward convergence or impasse. The cycle continues until a complete solution emerges or no further advancements are possible, enabling collaborative resolution through modular, independent contributions.[12] Central to this process is its incremental nature, where solutions develop opportunistically via successive partial contributions rather than through a linear, predefined sequence.[13] Knowledge sources analyze the evolving blackboard state and post refinements or new hypotheses, handling uncertainty by iteratively building and testing assumptions across multiple cycles. This approach accommodates ill-structured problems by allowing the system to refine partial interpretations dynamically, accumulating evidence piecemeal to reduce ambiguity over time.[12] The process unfolds in distinct phases: initialization, where the problem is defined and initial data or hypotheses are placed on the blackboard to establish the starting state; elaboration, involving data gathering, hypothesis generation, and incremental analysis by activated knowledge sources to expand the solution; consolidation, which synthesizes and validates contributions to form a more coherent overall state; and termination, occurring upon achieving a viable solution or reaching a point of no further viable opportunities.[13] These phases are not strictly sequential but overlap within the iterative loop, with the control shell orchestrating transitions based on the blackboard's evolving content. Conceptually, the workflow forms a feedback loop: the control shell monitors the blackboard for changes that signal opportunities, such as new data or unresolved hypotheses, then activates appropriate knowledge sources whose preconditions match the current state.[12] These sources, in turn, post updates—ranging from simple modifications to complex derivations—directly to the blackboard, prompting re-evaluation by the control shell to prioritize the next iteration.[13] This closed-loop interaction fosters adaptive, data-driven progression, as demonstrated in early systems like Hearsay-II, where acoustic signals were incrementally interpreted into linguistic structures through such cycles.Activation and Scheduling
In blackboard systems, activation of knowledge sources is typically event-driven, occurring when changes to the blackboard data structure match the preconditions specified by a knowledge source.[3] These preconditions are often monitored through pattern matching or dedicated event monitors that detect relevant updates, such as the addition or modification of hypotheses, thereby triggering potential activations without requiring constant scanning of the entire blackboard.[14] For instance, in the BB1 architecture, knowledge sources generate activation records (KSARs) upon trigger events, placing them into a to-do set for subsequent evaluation.[15] Scheduling strategies within the control shell prioritize and select from these activated knowledge sources to ensure efficient problem-solving progression. Common approaches include priority queues that rank activations based on utility scores, where each knowledge source provides estimates of its expected contribution quality, execution cost, and dependencies on other sources.[3] Utility-based selection, as implemented in BB1, involves rating KSARs against dynamic control plans using weighted criteria, such as favoring high-impact actions or those aligning with current foci, often resolved through greedy algorithms that choose the highest-rated option.[16] Conflict resolution mechanisms, like least commitment strategies, defer decisions when multiple activations compete, preventing premature binding and allowing opportunistic refinement.[15] Heuristics play a crucial role in optimizing activation and scheduling by focusing attention on promising subsets of the search space. Focus of attention mechanisms limit the number of monitored preconditions or eligible activations, reducing computational overhead in complex domains, as seen in systems where only a subset of blackboard levels or events are actively tracked.[14] In multi-threaded implementations, heuristics enable parallelism by scheduling independent activations concurrently while synchronizing dependent ones, often using variable-grain strategies that adapt between global planning and local execution.[3] These heuristics, derived from knowledge source estimates, maintain modularity by avoiding deep domain-specific logic in the control shell.[16] Key challenges in activation and scheduling include avoiding infinite loops from cyclic activations, managing resource contention in parallel environments, and adapting to evolving problem states. Infinite loops are mitigated through expiration criteria on activations or foci, such as cycle limits in BB1, ensuring termination if no progress is made.[15] Resource contention is addressed via priority-based arbitration and user overrides, while dynamic adaptation relies on real-time updates to utility scores and control plans to respond to blackboard changes without restarting the process.[3] These mechanisms collectively enable the control shell to orchestrate robust, opportunistic execution.[14]Implementation Considerations
Architectural Design
The blackboard architecture is fundamentally modular, promoting loose coupling among components by confining all inter-module communication to a central data repository known as the blackboard, which minimizes direct dependencies and enhances system flexibility. This design principle allows knowledge sources—specialized modules that contribute problem-solving expertise—to operate independently, focusing solely on reading from and writing to the blackboard without needing awareness of other sources' internal workings. Layering provides abstraction by organizing the blackboard into hierarchical levels, each representing different granularities of the problem domain, such as high-level hypotheses at the top and low-level data at the base, enabling progressive refinement of solutions. Extensibility is achieved through pluggable knowledge sources, which can be added or updated dynamically to incorporate new domain knowledge without disrupting the overall system structure. Scalability in blackboard systems addresses complex, large-scale problems by employing hierarchical blackboards that decompose the domain into manageable subproblems, allowing parallel exploration at multiple abstraction levels.[17] Distributed variants extend this further, partitioning the blackboard across networked nodes to enable parallel processing and fault tolerance, particularly useful in resource-intensive applications where knowledge sources can execute concurrently on separate processors.[18] These approaches mitigate performance bottlenecks inherent in monolithic designs, supporting systems that handle expansive search spaces or real-time constraints. Integration with complementary patterns enhances the blackboard's effectiveness; for instance, the observer pattern facilitates notifications when blackboard states change, triggering relevant knowledge sources opportunistically.[19] Similarly, the mediator pattern can be realized through the control shell, which coordinates interactions without direct source-to-source coupling, while compatibility with event-driven architectures allows asynchronous propagation of updates across the system. Best practices include defining clear data schemas on the blackboard to ensure semantic consistency and interoperability among contributions from diverse sources. In concurrent implementations, thread-safety mechanisms, such as locks or atomic operations, are essential to manage simultaneous access and prevent data inconsistencies.[18] Testing protocols should emphasize emergent behaviors arising from source interactions, using simulation to validate unexpected solution paths without exhaustive enumeration. Modern adaptations integrate blackboard principles with microservices architectures, where the blackboard functions as a shared, distributed data layer coordinating loosely coupled services in cloud-native environments, facilitating scalable AI-driven automation.Example in Pseudocode
To illustrate the implementation of the blackboard design pattern, consider a simplified pseudocode example for an incremental pathfinding system solving a puzzle, such as finding a path from a start node to a goal node in a grid while avoiding obstacles. In this scenario, the blackboard maintains shared state like the current path and detected obstacles, knowledge sources handle specific tasks (e.g., expanding nodes, detecting obstacles, and checking for the goal), and the control shell orchestrates activation based on preconditions and priorities. This structure draws from the foundational mechanisms described in the original blackboard architecture, where changes to the blackboard trigger opportunistic contributions from knowledge sources.90012-X) The pseudocode below outlines the core classes and the main control loop in a generic, language-agnostic form. It emphasizes event notification via updates, precondition checks for knowledge source eligibility, and priority-based scheduling in the control shell to select and invoke sources iteratively until the goal is reached.// Blackboard: Central shared data structure with update and notification
class Blackboard {
data: dictionary // e.g., {"current_path": [], "obstacles": set(), "goal_reached": false}
observers: list of KnowledgeSource // Registered knowledge sources to notify
function initialize() {
data = {"current_path": [], "obstacles": set(), "goal_reached": false}
observers = []
}
function register_observer(ks: KnowledgeSource) {
observers.add(ks)
}
function update(key: string, value: any) {
data[key] = value
// Notify all observers of the change
for each observer in observers {
notify(observer, key, value)
}
}
function get(key: string): any {
return data[key]
}
}
// KnowledgeSource Interface: Defines precondition and execution for modular contributions
interface KnowledgeSource {
priority: integer // Static priority for scheduling (higher = more urgent)
function precondition(blackboard: Blackboard): boolean {
// Check if conditions on blackboard state are met for activation
// e.g., for NodeExpander: if current_path is not empty
}
function execute(blackboard: Blackboard) {
// Perform task and update blackboard if applicable
// e.g., append new nodes to current_path
}
}
// Example Knowledge Sources for pathfinding puzzle
class NodeExpander implements KnowledgeSource {
priority = 3 // High priority for exploration
function precondition(blackboard: Blackboard): boolean {
return blackboard.get("current_path").length > 0 and not blackboard.get("goal_reached")
}
function execute(blackboard: Blackboard) {
current_path = blackboard.get("current_path")
last_node = current_path.last()
neighbors = get_valid_neighbors(last_node) // Domain-specific: adjacent grid cells
current_path.append(neighbors) // Incremental expansion
blackboard.update("current_path", current_path)
}
}
class ObstacleDetector implements KnowledgeSource {
priority = 2 // Medium priority after expansion
function [precondition](/page/Precondition)([blackboard](/page/Blackboard): [Blackboard](/page/Blackboard)): [boolean](/page/Boolean) {
return [blackboard](/page/Blackboard).get("current_path").length > 0 and not [blackboard](/page/Blackboard).get("goal_reached")
}
function execute([blackboard](/page/Blackboard): [Blackboard](/page/Blackboard)) {
path = [blackboard](/page/Blackboard).get("current_path")
new_obstacles = detect_obstacles_in_path(path) // Domain-specific: check grid for walls
obstacles = [blackboard](/page/Blackboard).get("obstacles").union(new_obstacles)
if new_obstacles not empty {
[blackboard](/page/Blackboard).update("obstacles", obstacles)
// Optionally [prune](/page/Prune) invalid path segments
}
}
}
class GoalChecker implements KnowledgeSource {
priority = 1 // Low priority, checked last
function precondition(blackboard: Blackboard): boolean {
return blackboard.get("current_path").length > 0
}
function execute(blackboard: Blackboard) {
path = blackboard.get("current_path")
goal = get_goal() // Domain-specific: target node
if path.contains(goal) {
blackboard.update("goal_reached", true)
}
}
}
// Control Shell: Monitors, schedules, and invokes knowledge sources
class ControlShell {
blackboard: Blackboard
sources: list of KnowledgeSource
function initialize(blackboard: Blackboard, sources: list) {
self.blackboard = blackboard
self.sources = sources
for each source in sources {
blackboard.register_observer(source)
}
}
function run() {
blackboard.update("current_path", [start_node]) // Initialize with start
while not blackboard.get("goal_reached") {
eligible_sources = []
for each source in sources {
if source.precondition(blackboard) {
eligible_sources.add(source)
}
}
if eligible_sources empty {
// No progress; handle deadlock (e.g., backtrack or fail)
break
}
// Select source with highest priority (simple max; could use heuristics)
selected_source = eligible_sources.max_by_priority()
selected_source.execute(blackboard)
// Event loop: updates trigger notifications for next cycle
}
if blackboard.get("goal_reached") {
return blackboard.get("current_path") // Solution
} else {
return null // No solution
}
}
}
// Usage: Initialize and run
main() {
bb = new Blackboard()
bb.initialize()
sources = [new NodeExpander(), new ObstacleDetector(), new GoalChecker()]
control = new ControlShell(bb, sources)
solution = control.run()
}
// Blackboard: Central shared data structure with update and notification
class Blackboard {
data: dictionary // e.g., {"current_path": [], "obstacles": set(), "goal_reached": false}
observers: list of KnowledgeSource // Registered knowledge sources to notify
function initialize() {
data = {"current_path": [], "obstacles": set(), "goal_reached": false}
observers = []
}
function register_observer(ks: KnowledgeSource) {
observers.add(ks)
}
function update(key: string, value: any) {
data[key] = value
// Notify all observers of the change
for each observer in observers {
notify(observer, key, value)
}
}
function get(key: string): any {
return data[key]
}
}
// KnowledgeSource Interface: Defines precondition and execution for modular contributions
interface KnowledgeSource {
priority: integer // Static priority for scheduling (higher = more urgent)
function precondition(blackboard: Blackboard): boolean {
// Check if conditions on blackboard state are met for activation
// e.g., for NodeExpander: if current_path is not empty
}
function execute(blackboard: Blackboard) {
// Perform task and update blackboard if applicable
// e.g., append new nodes to current_path
}
}
// Example Knowledge Sources for pathfinding puzzle
class NodeExpander implements KnowledgeSource {
priority = 3 // High priority for exploration
function precondition(blackboard: Blackboard): boolean {
return blackboard.get("current_path").length > 0 and not blackboard.get("goal_reached")
}
function execute(blackboard: Blackboard) {
current_path = blackboard.get("current_path")
last_node = current_path.last()
neighbors = get_valid_neighbors(last_node) // Domain-specific: adjacent grid cells
current_path.append(neighbors) // Incremental expansion
blackboard.update("current_path", current_path)
}
}
class ObstacleDetector implements KnowledgeSource {
priority = 2 // Medium priority after expansion
function [precondition](/page/Precondition)([blackboard](/page/Blackboard): [Blackboard](/page/Blackboard)): [boolean](/page/Boolean) {
return [blackboard](/page/Blackboard).get("current_path").length > 0 and not [blackboard](/page/Blackboard).get("goal_reached")
}
function execute([blackboard](/page/Blackboard): [Blackboard](/page/Blackboard)) {
path = [blackboard](/page/Blackboard).get("current_path")
new_obstacles = detect_obstacles_in_path(path) // Domain-specific: check grid for walls
obstacles = [blackboard](/page/Blackboard).get("obstacles").union(new_obstacles)
if new_obstacles not empty {
[blackboard](/page/Blackboard).update("obstacles", obstacles)
// Optionally [prune](/page/Prune) invalid path segments
}
}
}
class GoalChecker implements KnowledgeSource {
priority = 1 // Low priority, checked last
function precondition(blackboard: Blackboard): boolean {
return blackboard.get("current_path").length > 0
}
function execute(blackboard: Blackboard) {
path = blackboard.get("current_path")
goal = get_goal() // Domain-specific: target node
if path.contains(goal) {
blackboard.update("goal_reached", true)
}
}
}
// Control Shell: Monitors, schedules, and invokes knowledge sources
class ControlShell {
blackboard: Blackboard
sources: list of KnowledgeSource
function initialize(blackboard: Blackboard, sources: list) {
self.blackboard = blackboard
self.sources = sources
for each source in sources {
blackboard.register_observer(source)
}
}
function run() {
blackboard.update("current_path", [start_node]) // Initialize with start
while not blackboard.get("goal_reached") {
eligible_sources = []
for each source in sources {
if source.precondition(blackboard) {
eligible_sources.add(source)
}
}
if eligible_sources empty {
// No progress; handle deadlock (e.g., backtrack or fail)
break
}
// Select source with highest priority (simple max; could use heuristics)
selected_source = eligible_sources.max_by_priority()
selected_source.execute(blackboard)
// Event loop: updates trigger notifications for next cycle
}
if blackboard.get("goal_reached") {
return blackboard.get("current_path") // Solution
} else {
return null // No solution
}
}
}
// Usage: Initialize and run
main() {
bb = new Blackboard()
bb.initialize()
sources = [new NodeExpander(), new ObstacleDetector(), new GoalChecker()]
control = new ControlShell(bb, sources)
solution = control.run()
}
