ai9414 is a Python teaching toolkit for interactive artificial intelligence demos. It opens small browser-based visualisations for search, logic, uncertainty, constraint satisfaction, planning, and tokenisation, with simple installed commands that are easy to use in class.
It currently includes thirteen ready-to-run demos:
- labyrinth DFS search
- spatial graph DFS search
- spatial graph BFS search
- spatial graph greedy best-first search
- spatial graph A* search
- spatial graph uniform-cost search
- spatial graph branch-and-bound search
- propositional logic DPLL
- reasoning with uncertainty belief-state explorer
- foundation models tokenisation explorer
- CSP map colouring
- CSP delivery time-slot assignment
- STRIPS planning
labyrinth DFS searchStart withai9414 demo labyrinthspatial graph DFS searchStart withai9414 demo graph-dfsspatial graph BFS searchStart withai9414 demo graph-bfsspatial graph greedy best-first searchStart withai9414 demo graph-gbfsspatial graph A* searchStart withai9414 demo graph-astarspatial graph uniform-cost searchStart withai9414 demo graph-ucsspatial graph branch-and-bound searchStart withai9414 demo graph-bnbpropositional logic DPLLStart withai9414 demo logic-dpllreasoning with uncertainty belief-state explorerStart withai9414 demo uncertaintyfoundation models tokenisation explorerStart withai9414 demo foundation-modelsCSP map colouringStart withai9414 demo csp-mapCSP delivery time-slot assignmentStart withai9414 demo csp-deliverySTRIPS planningStart withai9414 demo strips
- one installed package with a small command-line interface:
ai9414 ... - browser-based visualisations with packaged frontend assets and no separate web build step
- curated examples for search, logic, uncertainty, CSP, planning, and tokenisation
- Python APIs for loading custom problems and launching demos directly from code
- replayable traces for classroom walkthroughs and static solution export
- automated tests plus contributor documentation
Install from PyPI:
python -m venv .venv
source .venv/bin/activate
pip install ai9414
ai9414 demo graph-bnbInstall directly from this repository:
python -m venv .venv
source .venv/bin/activate
pip install .
ai9414 list
ai9414 demo graph-bnbIf your environment does not put console scripts on PATH, the module entry point works too:
python -m ai9414 demo graph-bnbTo see the curated example names for a demo:
ai9414 list --examples graph-dfspython -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
pytest
python -m build
ai9414 demo graph-bnbThe scripts under examples/ are still useful when working directly in the repository, but they are no longer the main installed interface.
To start the labyrinth example directly from the repository:
python examples/labyrinth_demo.pyTo start the spatial graph DFS example directly from the repository:
python examples/graph_dfs_demo.pyTo start the spatial graph BFS example directly from the repository:
python examples/graph_bfs_demo.pyTo start the spatial graph greedy best-first example directly from the repository:
python examples/graph_gbfs_demo.pyTo start the spatial graph A* example directly from the repository:
python examples/graph_astar_demo.pyTo start the spatial graph uniform-cost example directly from the repository:
python examples/graph_ucs_demo.pyTo start the spatial graph branch-and-bound example directly from the repository:
python examples/graph_branch_and_bound_demo.pyTo start the DPLL logic example directly from the repository:
python examples/logic_dpll_demo.pyTo start the reasoning-with-uncertainty example directly from the repository:
python examples/uncertainty_demo.pyTo start the foundation models tokenisation example directly from the repository:
python examples/foundation_models_demo.pyTo start the CSP map-colouring example directly from the repository:
python examples/csp_demo.pyTo start the CSP delivery scheduling example directly from the repository:
python examples/delivery_csp_demo.pyTo start the STRIPS planning example directly from the repository:
python examples/strips_demo.pyThe same install is enough for the labyrinth live-Python stub as well. The
student download now uses the built-in ai9414.search.run_labyrinth_solver(...)
wrapper, so no separate Flask setup is required.
To export a backend-free replay bundle:
PYTHONPATH=src python - <<'PY'
from pathlib import Path
from ai9414.search import SearchDemo
app = SearchDemo()
output_dir = app.export_solution_bundle(Path("build/search-solution"))
print(output_dir)
PYLabyrinth example:
from ai9414.labyrinth import LabyrinthDemo
app = LabyrinthDemo()
app.load_example("small")
app.show()Spatial graph DFS example:
from ai9414.graph_dfs import GraphDfsDemo
app = GraphDfsDemo()
app.load_example("small")
app.show()Spatial graph BFS example:
from ai9414.graph_bfs import GraphBfsDemo
app = GraphBfsDemo()
app.load_example("small")
app.show()Spatial graph greedy best-first example:
from ai9414.graph_gbfs import GraphGbfsDemo
app = GraphGbfsDemo()
app.load_example("small")
app.show()Spatial graph A* example:
from ai9414.graph_astar import GraphAStarDemo
app = GraphAStarDemo()
app.load_example("small")
app.show()Spatial graph branch-and-bound example:
from ai9414.search import SearchDemo
app = SearchDemo()
app.load_example("small")
app.set_options(playback_speed=1.0)
app.show()Spatial graph uniform-cost example:
from ai9414.graph_ucs import GraphUcsDemo
app = GraphUcsDemo()
app.load_example("small")
app.show()Visual DPLL example:
from ai9414.logic import DpllDemo
app = DpllDemo()
app.load_example("unit_chain")
app.show()Reasoning with uncertainty example:
from ai9414.uncertainty import BeliefStateExplorer
app = BeliefStateExplorer()
app.load_example("office_localisation_basic")
app.show()Set a custom initial belief:
from ai9414.uncertainty import BeliefStateExplorer
app = BeliefStateExplorer()
app.load_example("office_localisation_basic")
app.set_belief({
"mail_room": 0.1,
"office_a": 0.4,
"corridor": 0.2,
"office_b": 0.2,
"lab": 0.1,
})
app.show()Foundation models tokenisation example:
from ai9414.foundation_models import TokenisationExplorer
app = TokenisationExplorer()
app.load_example("simple_sentence")
app.show()Custom tokenisation text:
from ai9414.foundation_models import TokenisationExplorer
app = TokenisationExplorer()
app.load_corpus("office_messages")
app.learn_merges(12)
app.set_text("Deliver parcel to Office A before 10:30.")
app.show()Visual CSP example:
from ai9414.csp import CSPDemo
app = CSPDemo(example="australia")
app.set_algorithm("backtracking_forward_checking")
app.show()Custom CSP map:
from ai9414.csp import CSPDemo
app = CSPDemo()
app.load_map_problem(
regions=["a", "b", "c", "d"],
adjacency={
"a": ["b", "c"],
"b": ["a", "c", "d"],
"c": ["a", "b", "d"],
"d": ["b", "c"],
},
colours=["red", "green", "blue"],
)
app.set_variable_ordering("mrv")
app.show()Delivery scheduling CSP example:
from ai9414.delivery_csp import DeliveryCSPDemo
app = DeliveryCSPDemo(example="weekday_schedule")
app.set_algorithm("backtracking_forward_checking")
app.show()Custom delivery scheduling CSP:
from ai9414.delivery_csp import DeliveryCSPDemo
app = DeliveryCSPDemo()
app.load_delivery_problem(
deliveries=[
{"id": "a", "label": "Delivery A", "short_label": "A", "colour": "#c75b4a"},
{"id": "b", "label": "Delivery B", "short_label": "B", "colour": "#4d79ab"},
],
slots=[
{"id": "slot_1", "label": "09:00", "order": 0},
{"id": "slot_2", "label": "11:00", "order": 1},
],
rooms=[
{"id": "dock", "label": "Dock"},
],
values=[
{"id": "slot_1_dock", "slot": "slot_1", "room": "dock", "label": "09:00 @ Dock"},
{"id": "slot_2_dock", "slot": "slot_2", "room": "dock", "label": "11:00 @ Dock"},
],
domains={
"a": ["slot_1_dock", "slot_2_dock"],
"b": ["slot_2_dock"],
},
constraints=[
{
"kind": "precedence",
"left": "a",
"right": "b",
"label": "A before B",
"description": "Delivery A must happen before delivery B.",
}
],
)
app.set_variable_ordering("mrv")
app.show()Visual STRIPS planning example:
from ai9414.strips import StripsDemo
app = StripsDemo()
app.load_example("canonical_delivery")
app.show()Custom STRIPS problem:
from ai9414.strips import StripsDemo, StripsProblem
problem = StripsProblem(
rooms=["corridor", "mail_room", "office_a", "office_b", "lab"],
robot_start="corridor",
parcel_start="mail_room",
keycard_start="office_a",
locked_edge=("corridor", "lab"),
door_locked=True,
goal=[("at", "parcel", "lab")],
)
app = StripsDemo(problem=problem)
app.solve()
app.show()Suggested STRIPS exercises:
- Move the keycard from office A to office B and predict how the plan changes.
- Start the robot in the mail room and explain why collecting the parcel too early is a bad idea.
- Unlock the lab door at the start and identify which action disappears from the plan.
- Move the locked door to the office B connection and compare the new plan structure.
Custom CNF with DPLL:
from ai9414.logic import DpllDemo
app = DpllDemo()
app.load_cnf([
["A", "B"],
["~A", "C"],
["~B", "C"],
])
app.show()Entailment with DPLL:
from ai9414.logic import DpllDemo
app = DpllDemo(mode="entailment")
app.load_kb(
formulas=["A -> B", "B -> C", "A"],
query="C",
)
app.show()Live labyrinth solver wrapper:
from typing import Any
from ai9414.search import run_labyrinth_solver
def solve_dfs(labyrinth: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_labyrinth_solver(solve_dfs)Live graph solver wrapper:
from typing import Any
from ai9414.search import run_graph_solver
def solve_dfs(graph: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_graph_solver(solve_dfs)Live graph BFS solver wrapper:
from typing import Any
from ai9414.search import run_graph_bfs_solver
def solve_bfs(graph: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_graph_bfs_solver(solve_bfs)Live graph A* solver wrapper:
from typing import Any
from ai9414.search import run_graph_astar_solver
def solve_astar(graph: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_graph_astar_solver(solve_astar)Live graph UCS solver wrapper:
from typing import Any
from ai9414.search import run_graph_ucs_solver
def solve_ucs(graph: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_graph_ucs_solver(solve_ucs)Live graph greedy best-first solver wrapper:
from typing import Any
from ai9414.search import run_graph_gbfs_solver
def solve_gbfs(graph: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_graph_gbfs_solver(solve_gbfs)Live spatial graph branch-and-bound solver wrapper:
from typing import Any
from ai9414.search import run_weighted_graph_solver
def solve_dfbb(graph: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_weighted_graph_solver(solve_dfbb)Live DPLL solver wrapper:
from typing import Any
from ai9414.logic import run_dpll_solver
def solve_dpll(problem: dict[str, Any], options: dict[str, Any]) -> dict[str, Any]:
...
if __name__ == "__main__":
run_dpll_solver(solve_dpll)src/ai9414/
core/
demo/
graph_bfs/
graph_dfs/
graph_astar/
graph_gbfs/
graph_ucs/
labyrinth/
logic/
search/
frontend/
examples/
tests/
docs/
