Metadata-Version: 2.2
Name: movablegames
Version: 0.2.7
Summary: AI-powered adaptive game engine for educational platforms
Keywords: education,games,AI,math,engine
Author-Email: MovableGames <bertin@gmovablegames.com>
License: TERMS OF SERVICE AND END USER LICENSE AGREEMENT (EULA)
         
         Last Updated: May 29, 2026
         
         Please read this Terms of Service and End User License Agreement ("Agreement") carefully before downloading, installing, or using the MovableGames desktop application ("Desktop App") or accessing our cloud-hosted platform and browser services ("Cloud Services") (collectively, the "Platform").
         
         By creating an account, downloading the Desktop App, or accessing the Cloud Services, you ("User" or "Licensee") agree to be bound by the terms of this Agreement. If you do not agree to these terms, do not install the Desktop App or access the Cloud Services.
         
         1. THE PARTIES AND THE PLATFORM
            This Agreement is between you and MovableGames Ltd ("Company", "we", "us", or "our"). Our Platform consists of a proprietary cloud-hosted backend engine, a web-browser interface, and a downloadable desktop application that connects to our servers to manage local user files and provide native desktop functionality.
         
         2. LICENSE GRANTS
            2.1 Desktop App License: Subject to your compliance with this Agreement, Company grants you a limited, non-exclusive, non-transferable, non-sublicensable, and revocable license to download, install, and run the Desktop App on compatible devices solely for your personal or authorized institutional use.
            2.2 Cloud Services Access: Company grants you a non-exclusive, non-transferable right to access and use the Cloud Services through a standard web browser or authorized Desktop App connection during your subscription term.
         
         3. LICENSE RESTRICTIONS
            You agree that you will not, and will not permit any third party to:
            a) Copy, modify, adapt, translate, or create derivative works of the Desktop App or Cloud Services.
            b) Reverse engineer, decompile, disassemble, or attempt to derive the source code, API protocols, or underlying adaptive AI and algorithms of any part of the Platform.
            c) Bypass, circumvent, or disable any security or digital rights management features of the Platform.
            d) Rent, lease, lend, sell, sublicense, distribute, or otherwise transfer the Desktop App or access to the Cloud Services to any third party.
            e) Use the Platform in any manner that interferes with, disrupts, or places an undue burden on our cloud servers or network infrastructure.
         
         4. INTELLECTUAL PROPERTY RIGHTS
            Except for the limited licenses explicitly granted in Section 2, the Company retains all right, title, and interest in and to the Platform, including the Desktop App, Cloud Services, proprietary source code, algorithms, game designs, cognitive tracking mechanics, graphics, and user interfaces. No ownership of any intellectual property is transferred to you under this Agreement.
         
         5. USER FILES AND CLOUD STORAGE
            5.1 Local File Interactions: You acknowledge that the Desktop App is designed to read, write, and manage designated local files on your computer to provide native desktop performance while synchronizing with our cloud servers.
            5.2 Data Ownership: You retain ownership of all original files, intellectual property, or code created by you using our Platform ("User Content").
            5.3 Server Synchronization: To ensure seamless operation between the Desktop App and web browsers, you grant the Company a limited, secure, royalty-free license to host, transmit, and back up your User Content on our cloud servers, solely as necessary to provide the services to you.
         
         6. SUBSCRIPTIONS, ACCOUNTS, AND FEES
            6.1 Account Registration: To use the Platform, you must register for an account and activate a valid license key. You are responsible for safeguarding your credentials and for all activities that occur under your account.
            6.2 Subscription Tiers: The Platform offers the following license tiers, each conferring access to a defined set of features and games:
         
         - Free: Core games and basic features at no cost.
         - Basic: Expanded game library and curriculum alignment tools.
         - Pro: Full game library, advanced AI tutoring, tournament participation, and career-prediction analytics.
         - Premium / Custom: All Pro features plus extended student seats, priority onboarding, and custom curriculum integration.
           The features and games available in any given session are determined by the active license key associated with the account. Subscription terms, fees, and billing cycles are outlined at the time of purchase at https://movablegames.com/pricing. Fees are non-refundable except as required by law.
           6.3 Termination for Non-Payment: We reserve the right to suspend or terminate your access to the Cloud Services and disable the Desktop App's server sync functionality in the event of non-payment or license expiry.
         
         7. PRIVACY AND SAFETY
            7.1 Data Protection: Our collection and use of personal data, including analytics, account information, and educational performance tracking, is governed by our Privacy Policy, located at https://movablegames.com/privacy.
            7.2 Educational Compliance: If you are an institutional User (e.g., a school or teacher), both parties agree to protect student privacy in accordance with applicable student data safety laws (such as COPPA and FERPA, where applicable).
            7.3 Telemetry and Usage Analytics: To improve the Platform's educational effectiveness, performance, and reliability, we collect anonymised behavioural telemetry from your use of the Platform. This includes, but is not limited to: session events (logins, session durations), game completion and accuracy data, AI service request statistics, feature usage patterns, and aggregate demographic information. All telemetry data is anonymised, processed internally, and handled in accordance with our Privacy Policy. You may request a summary or deletion of data associated with your account at any time by contacting us at legal@movablegames.com.
         
         8. TERM AND TERMINATION
            8.1 Term: This Agreement remains in effect until terminated by you or the Company.
            8.2 Termination by You: You may terminate this Agreement at any time by deleting your account, uninstalling the Desktop App, and ceasing all use of the Cloud Services.
            8.3 Termination by Company: We may terminate or suspend your access to the Platform immediately without prior notice if you breach any terms of this Agreement.
            8.4 Effect of Termination: Upon termination, all license rights granted under Section 2 will immediately cease. You must uninstall and destroy all copies of the Desktop App, and your access to synced cloud files will be deactivated.
         
         9. DISCLAIMER OF WARRANTIES
            THE PLATFORM (INCLUDING THE DESKTOP APP AND CLOUD SERVICES) IS PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE COMPANY DISCLAIMS ALL WARRANTIES, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. WE DO NOT WARRANT THAT THE PLATFORM WILL RUN COMPLETELY UNINTERRUPTED, ERROR-FREE, OR SECURE.
         
         10. LIMITATION OF LIABILITY
             TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL THE COMPANY, ITS AFFILIATES, OR ITS LICENSORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR ANY LOSS OF PROFITS, DATA, USE, OR GOODWILL, ARISING OUT OF OR IN CONNECTION WITH YOUR USE OF THE PLATFORM. THE COMPANY'S TOTAL AGGREGATE LIABILITY FOR ALL CLAIMS RELATING TO THE PLATFORM SHALL NOT EXCEED THE TOTAL FEES PAID BY YOU TO THE COMPANY IN THE TWELVE (12) MONTHS PRECEDING THE EVENT GIVING RISE TO LIABILITY.
         
         11. GOVERNING LAW AND SEVERABILITY
             This Agreement shall be governed by and construed in accordance with the laws of the State of Delaware, United States, without regard to its conflict of law principles. If any provision of this Agreement is held to be invalid or unenforceable, the remaining provisions will continue in full force and effect.
         
         12. CONTACT INFORMATION
             For questions or concerns regarding this Agreement, please contact us at:
         
         MovableGames Ltd
         [Mailing Address, fill in before publishing]
         Email: contact@movablegames.com
         Website: https://movablegames.com
         
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Education
Classifier: Topic :: Games/Entertainment
Project-URL: Homepage, https://movablegames.com
Requires-Python: >=3.12
Requires-Dist: numpy>=2.4.6
Description-Content-Type: text/markdown

# MovableGames Python API

The `movablegames` package is a thin Python facade over the pybind11-compiled `mag_engine` C++ wheel. It provides the building blocks for generating educational game environments, producing narrative frame sequences, and dispatching problems across all supported subjects.

---

## Installation

**From wheel (production):**

```bash
pip install movablegames
```

**Editable / source build** (requires CMake 3.25+, vcpkg, a C++17 compiler):

```bash
uv pip install -e .
# or
pip install -e .
```

The build compiles the C++ engine with `BUILD_PYTHON_BINDINGS=ON` and places the resulting `.pyd` / `.so` alongside the pure-Python modules. See [engine/README.md](../engine/README.md) for C++ build details.

---

## Package layout

```
python/movablegames/
├── __init__.py        re-exports everything from mag_engine (C++ bindings)
├── environment.py     EnvironmentFactory, HistoryEnvironment
├── level.py           MathLevelGenerator, ProblemGenerator
├── sequencer.py       NarrativeManager
└── topics.py          Topic enum, TopicManager
```

---

## Core types, from the C++ bindings (`mag_engine`)

These are re-exported by `__init__.py` via `from .mag_engine import *`.

### `ChargePolarity`

```python
from movablegames import ChargePolarity

ChargePolarity.POSITIVE   # numbers > 0
ChargePolarity.NEGATIVE   # numbers < 0
ChargePolarity.NEUTRAL    # variables / dormant entities
```

---

### `Charge`

Represents a number as a physical entity.

```python
from movablegames import Charge, ChargePolarity

c = Charge(magnitude=3.0, polarity=ChargePolarity.POSITIVE, visual_id="c_01")
c.magnitude    # float
c.polarity     # ChargePolarity
c.visual_id    # str, unique identifier for the frontend renderer
c.to_json()    # str, JSON representation
```

---

### `Environment`

A container for charges and mathematical operators (agents). Supports nested sub-environments (parentheses).

```python
from movablegames import Environment

env = Environment("zone_main")

# Add a charge directly
env.add_charge(magnitude=5.0, polarity=ChargePolarity.POSITIVE, visual_id="c_01")

# Add operator agents
env.add_plus_magician("m_plus_01")
env.add_minus_magician("m_minus_01")
env.add_multiply_magician("m_mul_01")
env.add_divide_magician("m_div_01")
env.add_power_sorcerer("m_pow_01")
env.add_root_magician("m_root_01")
env.add_abs_magician("m_abs_01")
env.add_factorial_magician("m_fac_01")
env.add_modulo_magician("m_mod_01")
env.add_log_magician("m_log_01")
env.add_chronomancer("m_chrono_01")       # parenthesis handler

# Add validation gates
env.add_equals_gate("gate_01", target=42.0)
env.add_inequality_gate("gate_02", target=10.0, comparison_type=">")

# Nest a sub-environment (parenthesis bubble)
sub = Environment("zone_sub")
env.add_sub_environment(sub)

# Inspect state
env.id                    # str
env.charges               # list[Charge]
env.agents                # list[MagicianAgent]
env.sub_environments      # list[Environment]
env.is_time_frozen        # bool

env.to_json()             # str, full JSON snapshot of the environment
```

---

### `NarrativeSequencer`

Drives the game loop one step at a time, applying operator priority rules (BIDMAS/BODMAS) and producing a JSON event for each step.

```python
from movablegames import NarrativeSequencer

seq = NarrativeSequencer(env)

while not seq.is_finished:
    frame_json = seq.next_frame()   # str, JSON with status and event data
    print(frame_json)

seq.current_frame    # int, index of the last processed frame
seq.is_finished      # bool
```

**Frame event types** (values of the `"status"` key in frame JSON):

| Constant         | Meaning                                |
| ---------------- | -------------------------------------- |
| `CAST_SPELL`     | An operator agent acted on charges     |
| `COLLAPSE_ZONE`  | A parenthesis bubble resolved          |
| `LEVEL_COMPLETE` | All operators finished; gate validates |
| `ERROR`          | An unrecoverable error occurred        |
| `FINISHED`       | Simulation is done (no more frames)    |
| `RUNNING`        | Step completed; simulation continues   |

---

## Python wrappers

### `EnvironmentFactory`, `movablegames.environment`

Factory that builds typed `Environment` objects from level data dictionaries.

```python
from movablegames.environment import EnvironmentFactory

env = EnvironmentFactory.create_math_environment(level_data)
env = EnvironmentFactory.create_science_environment(level_data)
env = EnvironmentFactory.create_history_environment(level_data)   # returns HistoryEnvironment
env = EnvironmentFactory.create_english_environment(level_data)
env = EnvironmentFactory.create_technology_environment(level_data)
```

`level_data` is the dict returned by `MathLevelGenerator.generate_math_problem` or any `ProblemGenerator.*` method. See the **Level data schema** section below.

**Operator role → `add_*` method mapping** (`EnvironmentFactory.MAG_MAGICIAN_METHODS`):

| Role string   | Method                   |
| ------------- | ------------------------ |
| `"plus"`      | `add_plus_magician`      |
| `"minus"`     | `add_minus_magician`     |
| `"multiply"`  | `add_multiply_magician`  |
| `"divide"`    | `add_divide_magician`    |
| `"power"`     | `add_power_sorcerer`     |
| `"root"`      | `add_root_magician`      |
| `"abs"`       | `add_abs_magician`       |
| `"factorial"` | `add_factorial_magician` |
| `"modulo"`    | `add_modulo_magician`    |
| `"log"`       | `add_log_magician`       |

---

### `MathLevelGenerator`, `movablegames.level`

Generates a random, self-consistent math problem and its level data.

```python
from movablegames.level import MathLevelGenerator

expr_str, level_data = MathLevelGenerator.generate_math_problem(
    operators=["+", "-", "*", "/"],   # subset of MAG_OPERATORS keys; None = all
    difficulty="easy",                # "easy" | "medium" | "hard"
)
```

**Supported operator symbols** (`MathLevelGenerator.MAG_OPERATORS`):

| Symbol          | Role      |
| --------------- | --------- |
| `"+"`           | plus      |
| `"-"`           | minus     |
| `"*"`           | multiply  |
| `"/"`           | divide    |
| `"**"` or `"^"` | power     |
| `"root"`        | root      |
| `"abs"`         | abs       |
| `"!"`           | factorial |
| `"%"`           | modulo    |
| `"log"`         | log       |

**Difficulty parameters:**

| Difficulty | Operators | Max value | Max complexity               |
| ---------- | --------- | --------- | ---------------------------- |
| `"easy"`   | 1–2       | 10        | 2 (+ − × ÷ abs)              |
| `"medium"` | 2–4       | 20        | 3 (adds power, root, modulo) |
| `"hard"`   | 4–6       | 50        | 5 (all operators)            |

---

### `ProblemGenerator`, `movablegames.level`

Placeholder generators for non-math subjects. Return a `(problem_string, level_data)` tuple suitable for the corresponding `EnvironmentFactory.create_*` method.

```python
from movablegames.level import ProblemGenerator

problem, data = ProblemGenerator.generate_science_problem(difficulty="easy")
problem, data = ProblemGenerator.generate_history_problem(difficulty="medium")
problem, data = ProblemGenerator.generate_english_problem(difficulty="hard")
problem, data = ProblemGenerator.generate_technology_problem(difficulty="easy")
```

---

### `NarrativeManager`, `movablegames.sequencer`

Runs the full narrative loop and collects all frames into a list.

```python
from movablegames.sequencer import NarrativeManager

frames = NarrativeManager.get_frames(environment=env, env_type="math")
# Returns list[dict], first entry is the initial state, subsequent entries are
# NarrativeSequencer frames; each dict has a "current_frame" index added.
```

Raises `ValueError` for unsupported `env_type` values.

---

### `Topic` / `TopicManager`, `movablegames.topics`

```python
from movablegames.topics import Topic, TopicManager

Topic.MATH         # "MATH"
Topic.SCIENCE      # "SCIENCE"
Topic.HISTORY      # "HISTORY"
Topic.ENGLISH      # "ENGLISH"
Topic.TECHNOLOGY   # "TECHNOLOGY"

TopicManager.get_all_topics()
# → ["math", "science", "history", "english", "technology"]
```

---

## Level data schema

`MathLevelGenerator.generate_math_problem` returns a dict with this shape:

```jsonc
{
  "level_id": "gen_easy_3f2a1b4c",
  "environment": {
    "zones": [
      {
        // The primary zone holding all top-level charges and operators
        "id": "zone_main",
        "type": "main_environment",
        "contents": [
          {
            "type": "charge",
            "value": 5.0,
            "polarity": "positive",
            "id": "c_a1b2",
          },
          { "type": "magician", "role": "plus", "id": "m_plus_c3d4" },
        ],
      },
      {
        // Optional: a parenthesis bubble (sub-environment)
        "id": "zone_e5f6",
        "type": "parenthesis_bubble",
        "contents": [
          {
            "type": "charge",
            "value": 3.0,
            "polarity": "positive",
            "id": "c_g7h8",
          },
          {
            "type": "charge",
            "value": 2.0,
            "polarity": "negative",
            "id": "c_i9j0",
          },
          { "type": "magician", "role": "minus", "id": "m_minus_k1l2" },
        ],
      },
      {
        // The goal gate, the equation target
        "id": "gate_main",
        "type": "equals_gate", // or "inequality_gate"
        "target_value": 6.0,
        // For inequality_gate only:
        // "comparison": ">" | "<" | ">=" | "<="
      },
    ],
  },
}
```

---

## End-to-end example

```python
from movablegames.level import MathLevelGenerator
from movablegames.environment import EnvironmentFactory
from movablegames.sequencer import NarrativeManager

# 1. Generate a medium-difficulty problem using addition and multiplication
expr_str, level_data = MathLevelGenerator.generate_math_problem(
    operators=["+", "*"],
    difficulty="medium",
)
print(f"Problem: {expr_str}")

# 2. Build the environment from the level data
env = EnvironmentFactory.create_math_environment(level_data)

# 3. Collect all narrative frames
frames = NarrativeManager.get_frames(env, env_type="math")
print(f"Total frames: {len(frames)}")

# 4. Inspect the first and last frames
import json
print("Initial state:", json.dumps(frames[0], indent=2))
print("Final state:  ", json.dumps(frames[-1], indent=2))
```
