Tuesday, September 15, 2026

GDScript++: Exploring the Next Generation of Scripting for Game Development

 

GDScript++: Exploring the Next Generation of Scripting for Game Development

https://technologiesinternetz.blogspot.com


Game development has become more accessible than ever. Modern engines allow developers to create 2D and 3D games without building every technology from scratch. One of the languages closely associated with this movement is GDScript, the scripting language created for the Godot game engine.

The term “GDScript++” can be used informally to describe the idea of extending or modernizing GDScript with more powerful programming capabilities. It is important to clarify that GDScript++ is not an official programming language or official replacement for GDScript. GDScript itself remains the scripting language designed specifically for Godot.

With that distinction in mind, let's explore what a hypothetical or community-oriented “GDScript++” concept could mean and why developers may be interested in it.

What Is GDScript?

GDScript is a high-level programming language designed specifically for the Godot Engine.

Its syntax is influenced by languages such as Python, making it relatively approachable for beginners. The language integrates closely with Godot's scene system, nodes, signals and other engine features.

A simple GDScript example looks like this:

extends Node

func _ready():
    print("Hello, Godot!")

The extends Node line tells Godot that the script is attached to a Node-based object, while _ready() is called when the node enters the scene tree.

So, What Could GDScript++ Mean?

The “++” name suggests an enhanced version of an existing language.

In a hypothetical GDScript++ environment, developers might expect features such as:

  • More advanced type checking
  • Better performance
  • Improved tooling
  • Stronger object-oriented programming support
  • Better code organization
  • Enhanced debugging
  • More sophisticated generics
  • Improved interoperability with native code

However, these should be viewed as possible design ideas rather than official GDScript++ features.

GDScript itself has already evolved considerably, including optional static typing and other language improvements.

Why Would Developers Want an Enhanced GDScript?

Game development can involve thousands of lines of code.

A small project might contain scripts for:

  • Player movement
  • Enemy AI
  • Weapons
  • Inventory systems
  • Menus
  • Audio
  • Saving and loading
  • Multiplayer
  • Physics
  • Quests

As a project becomes larger, developers need tools that make code easier to maintain.

An enhanced scripting approach could potentially provide stronger safeguards while retaining the simplicity that makes GDScript attractive.

Static Typing

One of the most useful features available in modern GDScript is static typing.

For example:

var player_health: int = 100
var player_name: String = "Hero"
var speed: float = 5.0

Types tell the engine and the developer what kind of data a variable is expected to contain.

A function can also specify parameter and return types:

func calculate_damage(power: int, bonus: int) -> int:
    return power + bonus

This can make larger projects easier to understand and can help catch certain mistakes earlier.

Object-Oriented Game Programming

Game engines naturally involve objects.

A player can be represented by one object, an enemy by another, and a weapon by another.

A simple class might look like:

class_name Player

var health: int = 100
var speed: float = 200.0

func take_damage(amount: int) -> void:
    health -= amount

Other scripts can then interact with the Player class.

This approach makes it easier to organize complicated game systems.

Performance Matters in Games

Games often need to perform many operations every frame.

For example, a game running at 60 frames per second has approximately:

1000 ÷ 60 ≈ 16.7 milliseconds

available for each frame.

That time may need to cover rendering, physics, animation, input processing, audio and game logic.

This is why performance becomes increasingly important as games become more sophisticated.

An enhanced scripting model could focus on reducing unnecessary overhead while retaining developer-friendly syntax.

GDScript and Native Languages

Godot supports more than one programming approach.

Developers can use GDScript for general game logic while using other technologies where lower-level performance or specialized functionality is required.

A hypothetical GDScript++ ecosystem could potentially make this interaction more seamless.

For example:

GDScript
   ↓
Game Logic
   ↓
GDScript++-style Advanced Systems
   ↓
Native / Engine-Level Code
   ↓
Godot Engine

The idea would be to allow developers to choose the appropriate level of abstraction for each part of a game.

Better Developer Tools

Modern programming is not only about the language itself. Development tools are equally important.

An advanced GDScript ecosystem could emphasize:

  • Intelligent code completion
  • Static analysis
  • Better error messages
  • Refactoring tools
  • Performance profiling
  • Debugging support
  • Documentation integration
  • Automatic code suggestions

These features can save developers considerable time during large projects.

GDScript for Beginners

One of GDScript's biggest advantages is its relatively simple syntax.

For example:

var score: int = 0

func add_score(points: int) -> void:
    score += points

Even someone learning programming for the first time can understand the basic structure.

This makes GDScript particularly useful for students and aspiring game developers.

Building a Simple Player Script

Here is a basic example:

extends CharacterBody2D

@export var speed: float = 250.0

func _physics_process(delta: float) -> void:
    var direction := Input.get_vector(
        "ui_left",
        "ui_right",
        "ui_up",
        "ui_down"
    )

    velocity = direction * speed
    move_and_slide()

The script reads player input, calculates a movement direction and moves the character.

Although this example is small, the same principles can be expanded into much larger game systems.

Where an Advanced GDScript Could Be Useful

An enhanced scripting concept could be particularly valuable for projects such as:

Indie Games

Small development teams need languages that allow rapid development without creating excessive complexity.

2D Games

Godot is particularly popular for 2D development, where scripting handles gameplay mechanics, characters and interactions.

3D Games

Larger 3D projects can benefit from strong code organization and performance-conscious scripting.

Educational Projects

A simple syntax can help students learn programming through game creation.

Prototypes

Developers can quickly test gameplay ideas before investing in complex systems.

GDScript++ and AI-Powered Game Development

Another interesting possibility is combining game scripting with AI-assisted development.

AI coding assistants can help developers:

  • Generate basic scripts
  • Explain errors
  • Create gameplay prototypes
  • Suggest optimizations
  • Generate boilerplate code
  • Explain unfamiliar APIs

For example, a developer could describe:

“Create an enemy that follows the player but stops when it reaches a certain distance.”

An AI assistant could generate a starting GDScript implementation.

The developer would still need to test, understand and modify the generated code.

A Possible Future Architecture

A future game-development workflow might look like this:

Game Design
     ↓
AI-Assisted Development
     ↓
GDScript
     ↓
Advanced Typed Systems
     ↓
Godot Engine
     ↓
2D / 3D Game

Such a workflow could make sophisticated game development accessible to a wider range of creators.

Is GDScript++ a Real Replacement for GDScript?

No official GDScript++ replacement should be assumed simply because the term appears in articles, repositories or online discussions.

If you encounter the term “GDScript++,” check the specific project's documentation to determine whether it refers to:

  • A community project
  • A proposed language extension
  • A personal programming experiment
  • A tool or framework
  • A misunderstanding of GDScript's existing features

For actual Godot development, learning GDScript is the appropriate starting point.

Conclusion

The idea of GDScript++ represents an interesting vision: combining the simplicity of GDScript with stronger typing, better tooling, improved performance and more advanced programming capabilities.

However, it should not be confused with an official successor to GDScript. Developers interested in Godot should focus on learning modern GDScript and the Godot architecture first.

As game engines continue to evolve, scripting languages will likely become more powerful while remaining accessible. Whether through future improvements to GDScript, community tools or AI-assisted development, the goal remains the same: help developers turn game ideas into playable experiences faster and with less unnecessary complexity.

Combining Traditional Machine Learning with Agentic Reasoning: A Practical AI Architecture

 

Combining Traditional Machine Learning with Agentic Reasoning: A Practical AI Architecture

Artificial intelligence is moving beyond systems that simply make predictions. Modern AI applications are increasingly expected to understand a problem, make decisions, use tools, evaluate results, and take multiple steps toward a goal.

This is where agentic AI becomes important.

However, that does not mean traditional machine learning has become obsolete. In many real-world applications, classical machine-learning models remain excellent at specific tasks such as fraud detection, demand forecasting, classification, anomaly detection, recommendation, and risk scoring.

A powerful approach is therefore to combine traditional machine learning with agentic reasoning.

Instead of asking an AI agent to perform everything itself, developers can give it access to specialized ML models and allow the agent to decide when and how those models should be used.

What Is Traditional Machine Learning?

Traditional machine learning focuses primarily on learning patterns from historical data and producing predictions or classifications.

Common algorithms include:

  • Linear and logistic regression
  • Decision trees
  • Random forests
  • Gradient boosting
  • Support vector machines
  • K-means clustering
  • XGBoost
  • Neural networks

For example, imagine an online store wants to predict whether an order is potentially fraudulent.

A machine-learning model can examine features such as:

  • Transaction value
  • Customer history
  • Location
  • Device information
  • Purchase frequency
  • Previous chargebacks

The model might return:

Fraud probability: 0.87

This is extremely useful, but the model generally does not decide what should happen next.

An agentic system can take that prediction and reason about the next action.

What Is Agentic Reasoning?

Agentic reasoning refers to an AI system that can work toward a goal through multiple steps.

Instead of producing only one prediction, an agent can:

  1. Understand the user's objective.
  2. Break the problem into smaller tasks.
  3. Select appropriate tools.
  4. Collect additional information.
  5. Run models or queries.
  6. Evaluate the results.
  7. Decide what to do next.
  8. Produce an outcome.

For example:

"Investigate why sales dropped last month and recommend actions."

An agent might:

  • Retrieve sales data.
  • Ask a forecasting model for expected sales.
  • Compare actual and predicted values.
  • Run an anomaly detector.
  • Check inventory information.
  • Analyze customer segments.
  • Identify possible causes.
  • Recommend corrective actions.

The traditional ML models provide specialized intelligence, while the agent provides coordination and decision-making.

Why Combine the Two?

Traditional ML and agentic AI solve different parts of a problem.

Traditional ML Agentic AI
Excellent at prediction Excellent at task orchestration
Works with structured data Can work across multiple tools
Produces scores or classifications Can plan multiple actions
Usually task-specific Can handle broader objectives
Fast inference Dynamic decision-making
Easier to benchmark More flexible

The combination can provide the best of both worlds.

A machine-learning model might be better at calculating a credit-risk score than an LLM. Meanwhile, an agent might be better at deciding what information should be collected before presenting a recommendation.

A Simple Architecture

A practical architecture could look like this:

                    User Goal
                       │
                       ▼
                ┌─────────────┐
                │ AI Agent    │
                │ Reasoning   │
                └──────┬──────┘
                       │
             ┌─────────┼─────────┐
             ▼         ▼         ▼
        ML Models    Databases   APIs
             │         │         │
             ▼         ▼         ▼
        Predictions   Data      External
                                  Tools
             │         │         │
             └─────────┼─────────┘
                       ▼
                 Agent Evaluation
                       │
                       ▼
                  Final Decision

The agent acts as the orchestration layer.

The ML models act as specialized tools.

Step 1: Identify Tasks That Need Machine Learning

The first step is deciding which parts of the workflow should use conventional ML.

For example, in a retail application:

Prediction tasks

  • Sales forecasting
  • Customer churn prediction
  • Product recommendation
  • Fraud detection
  • Inventory forecasting

These tasks can be handled by dedicated ML models.

There is usually little reason to replace a highly optimized forecasting model with an LLM simply because an agent is being introduced.

Step 2: Turn ML Models into Tools

The next step is to make your ML models accessible to the agent.

Suppose you have a Python model:

def predict_churn(customer_data):
    probability = model.predict_proba(customer_data)[0][1]
    return {
        "churn_probability": float(probability)
    }

Instead of manually calling this function every time, expose it as an agent tool.

Conceptually:

Tool: predict_customer_churn

Input:
customer_id

Output:
churn_probability
risk_level
important_features

Now the agent can decide when this model is useful.

Step 3: Give the Agent Context

An agent should not blindly call every available model.

It needs relevant context.

For example:

Customer:
- 4 years with company
- Purchased 3 times last year
- No purchases in 90 days
- Support complaints increased

Churn model:
Probability = 0.82

The agent can combine the structured prediction with other information.

It might reason:

The churn model indicates high risk. The customer also has declining activity and increased complaints. The next useful step is to examine recent support interactions before recommending an intervention.

This is where agentic reasoning adds value.

Step 4: Allow Multiple Models to Work Together

A sophisticated agent can use several specialized models.

Imagine a manufacturing system.

It could have:

Model A — Predictive maintenance

Machine failure probability: 74%

Model B — Anomaly detection

Vibration anomaly: Detected

Model C — Production forecasting

Expected production loss: 11%

The agent can combine these outputs.

Instead of treating each model independently, it can construct a workflow:

Detect anomaly
      ↓
Check failure probability
      ↓
Estimate production impact
      ↓
Check maintenance schedule
      ↓
Recommend action

The agent becomes the decision layer connecting specialized models.

Step 5: Use Agentic Reasoning for Model Selection

One of the most interesting possibilities is allowing an agent to select the appropriate model.

Suppose your system has:

fraud_model
churn_model
forecast_model
anomaly_model
recommendation_model

A user asks:

"Which customers should our team contact this week?"

The agent identifies that churn prediction is relevant.

It can then call:

customer_database
        ↓
churn_model
        ↓
customer segmentation
        ↓
agent analysis
        ↓
contact recommendations

This avoids running every model unnecessarily.

Step 6: Keep Predictions Separate from Reasoning

A crucial design principle is to distinguish between model outputs and agent conclusions.

For example:

{
  "model": "churn_model",
  "probability": 0.82,
  "confidence": 0.91
}

The agent should treat this as evidence.

It should not silently change:

0.82

into:

Customer will definitely leave.

A probability is not a certainty.

This separation improves transparency and makes the system easier to audit.

Step 7: Let the Agent Evaluate Model Results

An agent can also act as a verification layer.

Suppose a forecasting model predicts:

Next month's sales = $850,000

The agent could check:

  • Historical performance
  • Seasonal patterns
  • Recent marketing campaigns
  • Inventory levels
  • Current orders
  • External business information

If something looks unusual, it could request another analysis.

This creates a workflow such as:

Prediction
    ↓
Agent evaluation
    ↓
Does result make sense?
   / \
 Yes  No
  ↓    ↓
Use   Investigate
       ↓
    Recalculate

Step 8: Build a Feedback Loop

Agentic systems become more useful when they can learn from outcomes.

Consider a recommendation system.

The agent recommends:

Contact Customer A with a retention offer.

Later, the system observes:

Customer responded: Yes
Customer purchased: Yes

That outcome can become feedback for improving future decisions.

A larger architecture might look like:

Historical Data
      ↓
ML Training
      ↓
Prediction Model
      ↓
Agent
      ↓
Action
      ↓
Real-World Result
      ↓
Feedback Data
      ↓
Model Improvement

This creates a continuous improvement cycle.

Python-Based Example

A simple architecture can be built using Python.

Imagine a traditional classification model:

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(
    n_estimators=100,
    random_state=42
)

model.fit(X_train, y_train)

Create a prediction function:

def predict_risk(features):
    probability = model.predict_proba([features])[0][1]

    return {
        "risk_probability": float(probability)
    }

Then an agent can conceptually use this function as one of its tools:

tools = [
    predict_risk,
    search_customer_history,
    get_recent_transactions,
    create_report
]

The agent decides which tools are appropriate for the user's objective.

The important idea is not the particular agent framework. The important idea is the architecture:

ML models provide specialized predictions; the agent coordinates them.

Where This Architecture Works Well

Fraud Detection

A fraud model can generate risk scores while an agent investigates supporting information.

For example:

Transaction
   ↓
Fraud model
   ↓
Risk score
   ↓
Agent
   ↓
Check account history
   ↓
Check recent transactions
   ↓
Decision

Healthcare Analytics

Specialized models can assist with:

  • Risk prediction
  • Medical-image classification
  • Patient deterioration prediction
  • Appointment forecasting

An agent could organize information and assist professionals with analysis.

However, high-stakes healthcare decisions require strong human oversight. The agent should not independently make clinical decisions.

Financial Services

Traditional ML can perform:

  • Credit-risk prediction
  • Fraud detection
  • Default prediction
  • Market-data analysis

An agent can combine those outputs with financial information and generate structured reports.

Again, important financial decisions should have appropriate human review and controls.

E-Commerce

An agent can combine:

  • Recommendation models
  • Demand forecasting
  • Customer segmentation
  • Churn prediction

For example:

Customer request
      ↓
Agent
      ↓
Recommendation model
      ↓
Inventory model
      ↓
Customer preference data
      ↓
Final recommendation

Important Challenges

Combining ML and agents also introduces new problems.

1. Incorrect Reasoning

An agent can misunderstand a model's output.

A probability of 70% does not mean something is guaranteed.

2. Poor Tool Selection

An agent may call the wrong model.

Tool descriptions therefore need to be clear.

Bad:

predict()

Better:

predict_customer_churn()

3. Data Quality

Agentic reasoning cannot compensate for fundamentally bad data.

If the ML model receives incorrect or biased information, its predictions may also be unreliable.

4. Cost and Latency

Calling multiple models, databases and APIs can make an agentic workflow slower and more expensive.

Developers should monitor:

  • Number of tool calls
  • Inference time
  • Token usage
  • API costs
  • Failure rates

5. Security

Agents can potentially access sensitive tools and databases.

Use:

  • Authentication
  • Authorization
  • Tool-level permissions
  • Input validation
  • Logging
  • Rate limits
  • Human approval for sensitive actions

The agent should have only the permissions it actually needs.

A Better Design: Deterministic + Agentic

Not every decision needs an LLM.

A strong architecture often combines deterministic workflows with agentic reasoning.

For example:

             User Request
                  ↓
            Agent Planner
                  ↓
        ┌─────────┴─────────┐
        ↓                   ↓
 Deterministic          ML Models
 Workflow                   ↓
        ↓              Predictions
        └─────────┬─────────┘
                  ↓
             Agent Review
                  ↓
             Final Output

Use conventional code where rules are predictable.

Use ML where statistical prediction is required.

Use agents where flexible planning and tool selection are valuable.

This hybrid approach is often more practical than making everything agentic.

The Future of Hybrid AI

The future of AI applications is unlikely to be purely traditional ML or purely generative AI.

Instead, many systems will combine several specialized components:

LLMs
 +
Traditional ML
 +
Databases
 +
Search
 +
APIs
 +
Business Rules
 +
Human Oversight

An agent can act as the orchestration layer connecting these components.

Traditional ML remains valuable because specialized models can be faster, cheaper and more predictable for well-defined tasks. Agentic systems add flexibility by deciding how those capabilities should be combined.

Final Thoughts

Combining traditional machine learning with agentic reasoning is not about replacing one technology with another. It is about giving each technology the job it performs best.

Traditional ML can provide reliable predictions, classifications and numerical estimates. Agentic AI can interpret goals, select tools, coordinate multiple steps and turn individual predictions into useful workflows.

The resulting system can be thought of as:

ML for specialized intelligence + agents for orchestration + software for reliable execution.

For developers building practical AI applications, this hybrid architecture offers a compelling path toward systems that are not only intelligent, but also modular, measurable and useful in real-world environments.

How to Monitor Websites Automatically with Python

 

How to Monitor Websites Automatically with Python

Websites change constantly. Prices are updated, product pages are modified, news headlines appear, job listings are added, and important announcements can be published without warning. Checking these changes manually can be time-consuming.

Python makes it possible to build a simple website monitoring system that regularly checks a webpage and alerts you when something changes. With a few libraries, even beginners can create a useful monitoring script.

What Is Website Monitoring?

Website monitoring means automatically checking a website or webpage at regular intervals and detecting changes.

For example, you could monitor:

  • A product price
  • A job listing
  • A news page
  • A blog post
  • A website's availability
  • A particular piece of text
  • A public announcement
  • Changes to HTML content

Instead of opening the website repeatedly, Python can perform these checks for you.

How Python Can Monitor a Website

A basic monitoring program follows this process:

Website → Download page → Extract information → Compare with previous result → Detect change → Send notification

Python provides several libraries that make this process relatively straightforward.

For a simple monitor, you can use:

  • requests — downloads webpage content
  • BeautifulSoup — extracts information from HTML
  • hashlib — creates a fingerprint of content
  • time — waits between checks
  • smtplib or a notification service — sends alerts

Installing the Required Libraries

First, install the two commonly used packages:

pip install requests beautifulsoup4

Then create a Python file such as:

website_monitor.py

A Simple Website Change Monitor

Here is a basic example that checks whether the content of a webpage has changed:

import requests
import hashlib
import time

URL = "https://example.com"

def get_page_hash():
    response = requests.get(
        URL,
        timeout=10,
        headers={"User-Agent": "Mozilla/5.0"}
    )

    response.raise_for_status()

    content = response.text
    return hashlib.sha256(content.encode("utf-8")).hexdigest()


old_hash = get_page_hash()

print("Monitoring started...")

while True:
    time.sleep(300)  # Check every 5 minutes

    try:
        new_hash = get_page_hash()

        if new_hash != old_hash:
            print("Website has changed!")
            old_hash = new_hash
        else:
            print("No changes detected.")

    except requests.RequestException as error:
        print("Unable to check website:", error)

The program downloads the webpage and creates a SHA-256 hash from its HTML. If the hash changes during the next check, the program reports that the page has changed.

Why Use a Hash?

Comparing an entire webpage every time can be inconvenient. A hash provides a compact representation of the content.

For example:

Webpage content
       ↓
SHA-256
       ↓
a8f4...9c21

If even a small part of the input changes, the resulting hash will normally be different.

This makes hashes useful for detecting whether a downloaded document or webpage has changed.

Monitoring Only a Specific Part of a Website

Sometimes you don't care about the entire webpage.

Imagine you want to monitor only a product price:

<div class="price">₹49,999</div>

Using BeautifulSoup, you can extract that particular element.

import requests
from bs4 import BeautifulSoup

URL = "https://example.com/product"

response = requests.get(
    URL,
    timeout=10,
    headers={"User-Agent": "Mozilla/5.0"}
)

response.raise_for_status()

soup = BeautifulSoup(response.text, "html.parser")

price = soup.select_one(".price")

if price:
    print("Current price:", price.get_text(strip=True))

Now the monitoring system can compare the price rather than the complete webpage.

Building a Price Change Detector

The next step is to remember the previous value.

import requests
from bs4 import BeautifulSoup
import time

URL = "https://example.com/product"

def get_price():
    response = requests.get(
        URL,
        timeout=10,
        headers={"User-Agent": "Mozilla/5.0"}
    )

    response.raise_for_status()

    soup = BeautifulSoup(response.text, "html.parser")
    element = soup.select_one(".price")

    return element.get_text(strip=True) if element else None


old_price = get_price()

print("Initial price:", old_price)

while True:
    time.sleep(300)

    try:
        new_price = get_price()

        if new_price != old_price:
            print("Price changed!")
            print("Old:", old_price)
            print("New:", new_price)

            old_price = new_price
        else:
            print("Price has not changed.")

    except requests.RequestException as error:
        print("Error:", error)

This example can form the foundation of a much larger monitoring application.

Sending an Alert

Printing a message in the terminal is useful for testing, but a monitoring system becomes much more useful when it sends a notification.

For example, you could connect your Python program to:

  • Email
  • Telegram
  • Discord
  • Slack
  • A custom notification API

The basic workflow becomes:

Website changes
      ↓
Python detects change
      ↓
Notification function
      ↓
Your phone/email

A notification function might look like this:

def send_alert(message):
    print("ALERT:", message)

You can later replace this function with an email or messaging API.

Monitoring Multiple Websites

Python can also monitor several pages.

websites = {
    "News": "https://example.com/news",
    "Blog": "https://example.com/blog",
    "Jobs": "https://example.com/jobs"
}

for name, url in websites.items():
    print("Checking:", name)

    response = requests.get(
        url,
        timeout=10,
        headers={"User-Agent": "Mozilla/5.0"}
    )

    print(response.status_code)

For a larger application, you could store the websites in a JSON file or database.

For example:

[
    {
        "name": "News",
        "url": "https://example.com/news"
    },
    {
        "name": "Jobs",
        "url": "https://example.com/jobs"
    }
]

This makes adding new websites easier without changing the Python program.

Using SQLite for Persistent Monitoring

A more advanced monitor should remember previous results even after the program closes.

Python includes SQLite support through the built-in sqlite3 module.

You could store:

  • Website URL
  • Last checked time
  • Previous content hash
  • Last detected change
  • Monitoring status

A simplified database structure might look like:

websites
-------------------------
id
name
url
content_hash
last_checked

This turns a small script into the foundation of a real monitoring service.

Handling Websites That Use JavaScript

One important limitation is that requests downloads the server's response but does not behave like a normal browser.

Some websites generate their content using JavaScript.

In such cases, BeautifulSoup may not find the information you're looking for because the desired content isn't present in the initial HTML.

For websites that require browser rendering, tools such as Playwright or Selenium can be used.

A browser-based workflow looks like:

Python
  ↓
Automated browser
  ↓
Load JavaScript
  ↓
Rendered webpage
  ↓
Extract information
  ↓
Compare with previous result

However, browser automation requires more resources than a simple requests-based monitor.

Important Monitoring Practices

Website monitoring should be performed responsibly.

Before monitoring a website, check its terms of service and robots.txt where applicable. Avoid sending excessive requests because frequent automated requests can put unnecessary load on a server.

A good monitoring application should:

  • Use reasonable intervals
  • Set request timeouts
  • Handle errors
  • Identify itself appropriately where appropriate
  • Avoid bypassing authentication or access controls
  • Respect website terms and applicable laws
  • Cache information when possible

For many tasks, checking every few minutes or even every hour is sufficient.

Turning the Script Into a Background Service

Once your monitor works, you don't necessarily need to keep a terminal window open manually.

On Linux, you can use:

cron

On Windows, you can use:

Task Scheduler

You can also deploy the monitoring program to a server or cloud environment.

Another approach is to use Python's scheduling libraries to execute monitoring jobs at predefined intervals.

Taking the Project Further

A basic website monitor can evolve into a complete application.

You could build a dashboard using Flask, FastAPI, or Django.

The dashboard could display:

Website Monitor
--------------------------------
Website       Status     Last Check

News          Changed    10:30 PM
Jobs          Stable     10:29 PM
Product       Changed    10:28 PM
Blog          Stable     10:27 PM

You could also add:

  • User accounts
  • Website categories
  • Custom CSS selectors
  • Change history
  • Email notifications
  • Telegram notifications
  • Scheduling
  • Database storage
  • Dashboard charts
  • Automatic screenshots
  • Failure alerts
  • Multiple monitoring frequencies

Conclusion

Python provides a practical way to automate website monitoring without building a complicated system from scratch. A simple combination of requests, BeautifulSoup and hashing can detect basic webpage changes, while tools such as Playwright can handle more dynamic websites.

The most important idea is to monitor only the information you actually need. Instead of repeatedly comparing an entire webpage, extracting a specific price, headline, status, or section usually produces cleaner and more useful results.

With persistent storage and notifications, a small Python script can eventually become a powerful website monitoring platform that works continuously in the background.

Mastering Complex Roots of Unity with Python


Mastering Complex Roots of Unity with Python

Complex numbers can look intimidating at first, especially when equations involve imaginary values. However, Python makes it much easier to experiment with complex mathematics and understand what is happening behind the equations.

One particularly interesting topic is roots of unity. They connect complex numbers with geometry, trigonometry, algebra, and computer science.

In this tutorial, we will learn what roots of unity are, understand the formulas in simple copyable form, and create Python programs to calculate, verify, and visualize them.

What Are Roots of Unity?

A root of unity is a complex number that satisfies an equation of the form:

z^n = 1

Here, n is a positive integer.

For example, consider:

z^2 = 1

The two solutions are:

z = 1
z = -1

Therefore, 1 and -1 are the second roots of unity.

If we consider:

z^3 = 1

there are three solutions. One is the familiar number 1, while the other two are complex numbers.

In general, the equation:

z^n = 1

has exactly n different complex roots.

The Formula for Roots of Unity

The roots can be calculated using the following formula:

z_k = e^(2*pi*i*k/n)

where:

k = 0, 1, 2, ..., n-1

Using Euler's formula, the same expression can be written as:

z_k = cos(2*pi*k/n) + i*sin(2*pi*k/n)

This second form is particularly useful when we want to understand the real and imaginary parts of each root.

Here:

i = sqrt(-1)

Python uses j instead of i for the imaginary unit.

Understanding the Unit Circle

Roots of unity have an interesting geometric property.

Every root lies on a circle with radius 1, called the unit circle.

The general form is:

z = cos(theta) + i*sin(theta)

The distance of this point from the origin is always 1.

The roots are evenly distributed around the circle. This means that if there are 4 roots, they form a square. If there are 5 roots, they form a pentagon. If there are 8 roots, they form an octagon.

This gives us a beautiful connection between algebra and geometry.

Complex Numbers in Python

Python supports complex numbers directly.

For example:

z = 3 + 4j

print(z)

Output:

(3+4j)

Python uses j instead of the mathematical i.

You can also access the real and imaginary parts:

z = 3 + 4j

print("Real part:", z.real)
print("Imaginary part:", z.imag)

Output:

Real part: 3.0
Imaginary part: 4.0

This built-in support makes Python convenient for experimenting with roots of unity.

Calculating Roots of Unity with Python

Python's cmath module provides mathematical functions for complex numbers.

Here is a simple program:

import cmath
import math

n = 5

for k in range(n):
    angle = 2 * math.pi * k / n
    root = cmath.exp(1j * angle)

    print(root)

This program calculates the five roots satisfying:

z^5 = 1

The values may be displayed as decimal approximations because computers work with floating-point numbers.

Calculating Roots Using Sine and Cosine

We can also implement the mathematical formula directly.

import math

def roots_of_unity(n):
    roots = []

    for k in range(n):
        angle = 2 * math.pi * k / n

        real = math.cos(angle)
        imaginary = math.sin(angle)

        root = complex(real, imaginary)

        roots.append(root)

    return roots


roots = roots_of_unity(6)

for root in roots:
    print(root)

This approach is useful because it clearly shows the relationship between the mathematical formula and the Python program.

The important part is:

angle = 2*pi*k/n

Then:

real = cos(angle)
imaginary = sin(angle)

Finally, Python combines the two components into a complex number.

Example: Cube Roots of Unity

Let's solve:

z^3 = 1

There are three roots.

The formula is:

z_k = e^(2*pi*i*k/3)

For the three values of k:

k = 0, 1, 2

the roots are:

z0 = 1
z1 = -1/2 + (sqrt(3)/2)i
z2 = -1/2 - (sqrt(3)/2)i

Python can calculate them:

import cmath
import math

n = 3

for k in range(n):
    angle = 2 * math.pi * k / n
    root = cmath.exp(1j * angle)

    print(root)

The output will be decimal approximations of the three roots.

Verifying the Roots

We can ask Python to check whether each calculated root actually satisfies:

z^n = 1

For example:

import cmath
import math

n = 5

for k in range(n):
    angle = 2 * math.pi * k / n
    root = cmath.exp(1j * angle)

    result = root ** n

    print("Root:", root)
    print("Root raised to n:", result)
    print()

The second result should be extremely close to:

1 + 0j

This confirms that the calculated values are roots of the equation.

Why Does Python Sometimes Show Tiny Errors?

You might see something like:

(1-2.4492935982947064e-16j)

instead of:

1+0j

This is caused by floating-point precision.

Mathematically:

2.4492935982947064e-16

is extremely close to zero.

Therefore, we should not normally compare floating-point complex numbers using an exact equality test.

Instead, we can use a small tolerance:

if abs(root ** n - 1) < 1e-10:
    print("Valid root")

This allows for tiny numerical errors.

Finding a Specific Root

Sometimes we don't need all the roots. We may want a particular root.

We can create a function:

import cmath
import math

def find_root(n, k):
    angle = 2 * math.pi * k / n
    return cmath.exp(1j * angle)


root = find_root(10, 3)

print(root)

Here:

n = 10

means we are calculating tenth roots of unity.

The value:

k = 3

selects the fourth root in the sequence because Python starts counting from zero.

Building an Interactive Root Calculator

We can turn the idea into a small Python project.

import cmath
import math

def calculate_roots(n):
    if n <= 0:
        raise ValueError("n must be positive")

    roots = []

    for k in range(n):
        angle = 2 * math.pi * k / n
        root = cmath.exp(1j * angle)
        roots.append(root)

    return roots


n = int(input("Enter the value of n: "))

roots = calculate_roots(n)

print(f"\nRoots of z^{n} = 1\n")

for index, root in enumerate(roots):
    print(f"Root {index}: {root}")

If the user enters:

Enter the value of n: 4

the program calculates the four roots of:

z^4 = 1

These are:

1
i
-1
-i

Understanding the Fourth Roots

The fourth roots of unity are particularly easy to visualize.

The equation is:

z^4 = 1

The four solutions are:

z0 = 1
z1 = i
z2 = -1
z3 = -i

They are positioned at 90-degree intervals around the unit circle.

The angles are:

0 degrees
90 degrees
180 degrees
270 degrees

This creates a square.

Visualizing Roots with Python

A graph can make the concept much easier to understand.

We can use Matplotlib to plot the roots.

First install it if necessary:

pip install matplotlib

Then use:

import cmath
import math
import matplotlib.pyplot as plt

n = 8

roots = [
    cmath.exp(2j * math.pi * k / n)
    for k in range(n)
]

x = [root.real for root in roots]
y = [root.imag for root in roots]

plt.scatter(x, y)

plt.axhline(0)
plt.axvline(0)

plt.xlabel("Real")
plt.ylabel("Imaginary")
plt.title(f"{n}th Roots of Unity")

plt.axis("equal")
plt.grid(True)

plt.show()

For:

n = 8

the eight points form a regular octagon.

Try changing the value:

n = 3

You will get a triangle.

Try:

n = 6

and you will get a hexagon.

A Useful Property of Roots of Unity

There is another elegant way to represent the roots.

Let:

omega = e^(2*pi*i/n)

Then all the roots can be represented as:

1
omega
omega^2
omega^3
...
omega^(n-1)

The most important property is:

omega^n = 1

This means that after raising omega to the nth power, we return to 1.

Python can demonstrate this:

import cmath
import math

n = 5

omega = cmath.exp(2j * math.pi / n)

for k in range(n + 1):
    print(k, omega ** k)

The final value will be approximately 1.

Calculating the Magnitude

Every root of unity has magnitude 1.

Python allows us to calculate the magnitude using abs().

import cmath
import math

n = 6

for k in range(n):
    angle = 2 * math.pi * k / n
    root = cmath.exp(1j * angle)

    print("Root:", root)
    print("Magnitude:", abs(root))

The magnitude should be approximately:

1.0

for every root.

This confirms the geometric fact that all the roots lie on the unit circle.

Calculating the Angle

Python's cmath.phase() function can be used to find the angle of a complex number.

import cmath

z = 1 + 1j

angle = cmath.phase(z)

print("Angle in radians:", angle)

The result is expressed in radians.

For roots of unity, these angles are evenly distributed around the circle.

Applications of Roots of Unity

Roots of unity have applications far beyond classroom mathematics.

Fourier Analysis

Roots of unity are fundamental to the Discrete Fourier Transform, which is used to break signals into their frequency components.

The Fast Fourier Transform, commonly known as FFT, makes these calculations much faster and is widely used in computing.

Digital Signal Processing

Audio, images, communication systems, and other digital signals can be analyzed using Fourier-based methods.

Computer Graphics

Complex numbers can represent rotations in two-dimensional mathematics. This makes them useful in certain graphics and geometric calculations.

Polynomial Equations

Roots of unity provide useful examples for understanding complex polynomial equations and their solutions.

Number Theory

Roots of unity also appear in advanced topics involving algebra, modular arithmetic, and number theory.

Complete Python Project

Here is a complete version that calculates and verifies the roots:

import cmath
import math

def roots_of_unity(n):
    roots = []

    for k in range(n):
        angle = 2 * math.pi * k / n
        root = cmath.exp(1j * angle)

        roots.append(root)

    return roots


n = int(input("Enter a positive integer: "))

if n <= 0:
    print("Please enter a positive integer.")
else:
    roots = roots_of_unity(n)

    print(f"\nRoots of z^{n} = 1\n")

    for k, root in enumerate(roots):
        result = root ** n

        print(f"Root {k}: {root}")
        print(f"Verification: {result}")
        print()

This small project combines several important Python concepts:

  • Functions
  • Lists
  • Loops
  • User input
  • Complex numbers
  • Mathematical calculations
  • Error checking
  • Numerical verification

Final Thoughts

Complex roots of unity are a great example of how programming can make advanced mathematics easier to explore.

The central equation is:

z^n = 1

and the general solution is:

z_k = e^(2*pi*i*k/n)

or, using sine and cosine:

z_k = cos(2*pi*k/n) + i*sin(2*pi*k/n)

Python allows us to calculate these values, verify that they satisfy the original equation, and plot them on the unit circle.

The most interesting part is the connection between algebra and geometry. Although the roots come from solving an equation, they form a perfectly regular polygon when plotted.

Once you are comfortable with roots of unity, you can go further into complex-number programming, Fourier transforms, FFT algorithms, signal processing, and other areas where mathematics and Python come together.

GDScript++: Exploring the Next Generation of Scripting for Game Development

  GDScript++: Exploring the Next Generation of Scripting for Game Development Game development has become more accessible than ever. Modern...