> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/ai-college-notes/practical-4-table-driven-vacuum-cleaner-agent.md).

# Practical 4 — Table-Driven Vacuum Cleaner Agent

**Language used:** Python 3 (plain Python, no libraries needed)

**Aim:** Build a simple AI **agent** that cleans a two-room "vacuum world," by looking up the correct action from a fixed table instead of "thinking" on the fly.

***

### 4.1 The scenario, in plain English

Picture a robot vacuum living in a world with just **two rooms**: Room **A** and Room **B**. Each room can be either **Dirty** or **Clean**. The robot can only do one of four things at any moment:

* **Suck** — clean the dirt in the room it's currently in
* **Right** — move from A to B
* **Left** — move from B to A
* **Stop** — nothing left to do, both rooms are clean

```mermaid
flowchart LR
    subgraph World
    A[Room A] <-- Right / Left --> B[Room B]
    end
```

The robot doesn't have a camera or sensors that see the whole world — it only **perceives** one thing at every step: *"which room am I in, and is it dirty or clean?"* That single observation is called a **percept**, written as a pair like `("A", "Dirty")`.

***

### 4.2 What is a "Table-Driven Agent"? (the core idea)

In AI, an **agent** is anything that perceives its environment and acts on it. There are several ways to design one:

| Agent type                                          | How it decides what to do                                                                                                                |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Simple reflex agent**                             | Looks only at the *current* percept, ignores everything before it                                                                        |
| **Table-driven agent** *(this practical)*           | Keeps a memory of **every percept it has ever seen**, and looks up the right action for that *entire history* in a giant pre-built table |
| **Model-based / goal-based / utility-based agents** | Use internal reasoning instead of a fixed table (more advanced, not this practical)                                                      |

A table-driven agent is the simplest possible "thinking" agent: someone (a human designer) has already worked out, in advance, *"if the robot has seen exactly this sequence of percepts, it should do exactly that action,"* and stored all those answers in a lookup table (a Python dictionary here). The agent's whole "intelligence" is just **remembering what it has seen so far and looking that up.**

**Why this matters / its big weakness:** the table needs one entry for *every possible sequence of percepts* the agent could ever encounter. Even in our tiny 2-room world, the table already needs multiple entries just to handle a few steps — in a real, large world this table would be **astronomically large**. This is the main lesson of the practical: table-driven agents are simple to understand, but don't scale.

***

### 4.3 The code

```python
class TableDrivenVacuumAgent:
    def __init__(self):
        self.percept_history = []
        self.step = 0

        self.lookup_table = {
            (("A", "Dirty"),): "Suck",
            (("A", "Clean"),): "Right",
            (("B", "Dirty"),): "Suck",
            (("B", "Clean"),): "Left",

            (("A", "Dirty"), ("A", "Clean")): "Right",
            (("A", "Clean"), ("B", "Dirty")): "Suck",
            (("A", "Clean"), ("B", "Clean")): "Stop",
            (("B", "Dirty"), ("B", "Clean")): "Left",
            (("B", "Clean"), ("A", "Dirty")): "Suck",
            (("B", "Clean"), ("A", "Clean")): "Stop",

            (("A", "Dirty"), ("A", "Clean"), ("B", "Dirty")): "Suck",
            (("A", "Dirty"), ("A", "Clean"), ("B", "Clean")): "Stop",
            (("B", "Dirty"), ("B", "Clean"), ("A", "Dirty")): "Suck",
            (("B", "Dirty"), ("B", "Clean"), ("A", "Clean")): "Stop",
        }

    def act(self, current_percept):
        self.step += 1
        self.percept_history.append(current_percept)
        history_key = tuple(self.percept_history)
        action = self.lookup_table.get(history_key, "Stop")
        return action
```

> **Note:** the last couple of lines of `act()` were cut off in the photographed slide. The version above (`self.lookup_table.get(history_key, "Stop")`) is the standard, correct way to finish this method — it looks up `history_key` in the table and safely falls back to `"Stop"` if that exact history was never given an entry. This has been written and tested to confirm it behaves correctly (see §4.6).

***

### 4.4 Line-by-line explanation

#### The class and its memory

```python
class TableDrivenVacuumAgent:
```

Defines a blueprint for our agent. Every vacuum robot we create from this class will have its own memory and table.

```python
def __init__(self):
    self.percept_history = []
    self.step = 0
```

`__init__` runs once, automatically, when the agent is first created.

* `self.percept_history = []` — an empty list that will store **every percept the agent has ever received**, in order.
* `self.step = 0` — a counter tracking how many actions the agent has taken so far.

#### The lookup table

```python
self.lookup_table = { ... }
```

This is a Python **dictionary** where:

* **Key** = a *tuple of percepts* (the full history so far)
* **Value** = the correct action for that exact history

For example:

```python
(("A", "Dirty"),): "Suck"
```

means: *"if the entire percept history is just one percept — being in Room A and it's dirty — then Suck."*

```python
(("A", "Dirty"), ("A", "Clean")): "Right"
```

means: *"if the agent's history is (1) it started in A and it was dirty, then (2) after cleaning, A is now clean — then move Right to room B."*

Notice the table has to spell out every possible *sequence*, not just single percepts — that's the "remember everything" design mentioned in §4.2.

#### The decision-making method

```python
def act(self, current_percept):
    self.step += 1
    self.percept_history.append(current_percept)
```

Every time the environment gives the agent a new percept (e.g. `("B", "Dirty")`), this method:

1. Increases the step counter.
2. Adds this new percept onto the end of its memory (`percept_history`).

```python
    history_key = tuple(self.percept_history)
```

Converts the percept history (a `list`, which can't be a dictionary key) into a `tuple` (which *can* be a dictionary key — tuples are "frozen"/unchangeable, so Python allows them as keys, but lists aren't allowed).

```python
    action = self.lookup_table.get(history_key, "Stop")
    return action
```

Looks up the **entire history so far** in the table. `.get(key, default)` is a safe way to read a dictionary — if `history_key` exists in the table, return its action; otherwise, don't crash, just return `"Stop"` as a safe fallback. Finally, the chosen action is returned so the environment can carry it out.

***

### 4.5 Tracing it step by step (a worked example)

Let's say both rooms start Dirty, and the robot begins in Room A.

```mermaid
flowchart TD
    S1["Step 1: percept = (A, Dirty)\nhistory = [(A,Dirty)]"] -->|lookup table says| A1[Action: Suck]
    A1 --> S2["Step 2: percept = (A, Clean)\nhistory = [(A,Dirty),(A,Clean)]"]
    S2 -->|lookup table says| A2[Action: Right]
    A2 --> S3["Step 3: percept = (B, Dirty)\nhistory = [...,(B,Dirty)]"]
    S3 -->|lookup table says| A3[Action: Suck]
    A3 --> S4["Step 4: percept = (B, Clean)\nhistory = [...,(B,Clean)]"]
    S4 -->|lookup table says| A4[Action: Stop]
```

| Step | Location | Room status          | Percept         | Action chosen         |
| ---- | -------- | -------------------- | --------------- | --------------------- |
| 1    | A        | Dirty                | `("A","Dirty")` | **Suck**              |
| 2    | A        | Clean (just cleaned) | `("A","Clean")` | **Right** (move to B) |
| 3    | B        | Dirty                | `("B","Dirty")` | **Suck**              |
| 4    | B        | Clean (just cleaned) | `("B","Clean")` | **Stop**              |

***

### 4.6 Actual output (verified by running the reconstructed code with a small test simulation)

```
Step 1: Location=A, Status=Dirty -> Action=Suck
Step 2: Location=A, Status=Clean -> Action=Right
Step 3: Location=B, Status=Dirty -> Action=Suck
Step 4: Location=B, Status=Clean -> Action=Stop
Both rooms clean. Agent stops.
```

This matches the trace table above exactly — the agent successfully cleans both rooms in 4 steps and then correctly recognizes it's done and stops.

***

### 4.7 Quick recap for viva/oral exam

* The **vacuum world** is a classic simple environment used to teach agent design (2 rooms, dirty/clean states, 4 possible actions).
* A **percept** is one snapshot of what the agent currently observes — here, `(location, status)`.
* A **table-driven agent** decides its action by looking up the **entire percept history so far** in a pre-built lookup table — it doesn't compute or reason, it just remembers and matches.
* Its biggest weakness: the table must have an entry for every possible history, so it **grows exponentially** and becomes impossible to build for any realistically complex environment — this is exactly why AI moved toward smarter agent designs (reflex agents with rules, model-based agents, learning agents, etc.).
* `tuple()` is used here because Python dictionary keys must be **immutable** (unchangeable) — a `list` can't be a key, but a `tuple` can.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/ai-college-notes/practical-4-table-driven-vacuum-cleaner-agent.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
