July 20, 2026

How important is mathematics to understand Artificial intelligence?

 On the first look, computer science has its root in mathematics and physics, therefor the assumption is, that AI is based on mathematics too. The precondition, according to the claim, to understand modern robotics is located in analysis, algebra, statistics and boolean algebra.

A closer look will show that mathematics isn't needed in AI research at all or to be more precise, mathematics didn't enable advanced AI in the past. What researchers from 1960 until around 2000s tried was to describe artifciial intelligence in terms of mathematics and logic and they failed. The problem is that none of the mentioned disciplines like statistics, algebra and so on contain a method how to enable artificial intelligence. Even if mathematics is a great science disciplines its complete useless to control a robot. Some attempts were made to solve robotics problems with mathematical description of trajectories including model predictive control, but even these advanced math subjects are not powerful enough to enable autonomous robots.

Artificial intelligence as a science discipline is working different than classic sciences like physics, math and computer science. From a pessimistic perspective there is no such thing like Artificial intelligence. Most research around thinking machines and autonomous robots comes to the conclusion that the promising new technique isn't working. That means, a large scale robot project with hundreds of man year effort isn't working at all, the applied techniques are useless and the researchers have no idea about the cause.

Such a kind of pessimistic situation is not an exception in AI research but it was the default situation from 1960 to 2000s. So the best analogy is to compare AI with a complex puzzle which is impossible to solve and no matter how well the researchers are familiar with mathematics, philosophy or psychology they had no idea how to make a machine intelligent.

AI research in the past was mostly a trial by error meta disciplines which wasn't able to solve any of the goals. It was impossible to build intelligent robots, it was hard to program AI agents for computer games, and speech recognition with a computer was another unsolved topic.

The good news is, that its possible to list techniques who are not leading to AI. These techniques are:
- neural networks
- maschine learning
- reinforcement learning
- mathematical optimiziation
- heuristics
- number crunching
- genetic algorithms
- state space search
- case based reasoning
- expert system

In other words, the entire AIMA book (Russle/Norvig: AI a modern approach) is an anti pattern. It doesn't contain recipes to program robots but it describes the struggle of AI researchers for doing so.

After listing all these techniques who are not leading to AI there is a need to find the shared bias. THis bias is the computational paradigm which means, to use a computer to provide intelligence. This shared bias hasn't worked in the past because its an anti pattern in AI research.

On the first look it makes sense to assume, that AI has to do with computation because the computer or the robot should calculate something which leads to intelligent decision making. Therefor AI has to do with number crunching, programming and mathematics. The problem is that in the reality this paradigm isn't able to control robots but it blocks the progress in technology.

It seems, that AI aka intelligence isn't located inside a robot but outside of the machine. On the first look, such an assumption sounds like blasphemy because outside of a computer there is nothing which can calculate or make decisions. At least until the 2000s such a claim would be rejected by mainstream AI research for sure. With more recent understanding of AI there are some new results available which show that AI might located indeed outside of a robot.

Suppose the source of intelligence is not located in the CPU and not inside of a robot hardware, then intelligence has nothing to do with mathematics or physics. This doesn't mean that intelligence is equal to a magic force but it implies that AI has to do with communication. Communication is the science of how to connect things, communication puts a focus on the air gap between two systems.

The transition from former computational paradigm which locates AI Inside of a robot, towards modern communication paradigm which locates AI between two systems is the major paradigm shift in AI research which took place after the year 2000. The revised understanding of intelligence is strongly connected with communication, linguistics and man to machine interaction. In contrast, former focus on computation, mathematics, algorithms and programming have been discarded.

July 19, 2026

Robot control with head up displays

In contrast to a famous assumption, modern robotics isn't working with algorithms or neural networks but the basic building block is graphical user interface, namely a head up display (HuD). The HuD solves the symbol grounding problem. Typical elements are: bounding boxes around detected objects, text labels for describing the content of a bounding box, another text box for showing the inner voice of rhe robot.

These ingredients are enough to program an advanced artificial intelligence which can solve complex problems. The HuD including the mentioned bounding boxes acts as a communication layer. It ensures that the computer understands basic commands like "move to shelf and grasp the box". A certain high level command is converted into a visual pictures in the HuD, e.g. the word "shelf" is referencing to a bounding box with the label "shelf" which has a 2d position on the screen.

Programming a Head up display for an existing video game is a demanding task but can be solved with standard programming techniques. Most videogames created since the 1980s have a built in debug mode which comes close to a head up display. In the debut mode, all the sprites on the screen are highlighted with frames and sometimes the name of the objects are shown as textual overlay. The combination of graphical display plus textual overlay is the main principle of a head up display and also the main principle of grounded language. So the HuD itself acts as technology for enabling artificial intelligence.

Let me give another example to demonstrate the advantages: Suppose the head up display for a warehouse robot videogame was activated. The user sees some bounding boxes on the screen for highlighting objects in the map like charging station, corridor, shelf A, shelf B, green box, red box. Also the inner voice of the robot is shown a text frame and contains:

"I'm standing at position (3,2). My battery level is 80%, my goal is to fetch the red box from shelf A, the planned trajectory is shown as arrows in the map".

So the initial situation for the robot is, that an annotated HuD is visible which labels objects and mentions the current goal. These information can be translated into actions for the robot. All what the AI of the robot has to do is to compile these information and decide what to do next. From an AI perspective its an instruction following task with an aciivated head up display.

A head up display provides a cognitive space. The shown bouding boxes and labels are creating a symbolic representation of the world. The world of the robot can be described in terms from the head up display. Its no longer a mathematical space and not a 3d space but the reality introduced by the HuD consists of words, locations of items and goals from the inner voice. Such a high level space can be processed by a computer because the amount of possible states is small. There are not millions of possible objects but the HuD shows only 6 different objects in a map. and the inner voice doesn't display millions of possible actions, but the inner voice describes clearly what the current situation is, and what the desired goal state is, similar to a text adventure.

July 18, 2026

Introduction into typst typeseetting

 The amount of tutorials for typst is very low, because the software is new and works different from LaTeX. The following tutorial should explain the basics.

At first, a new file is created in the working directory which gets compiled into a pdf document with: "typst compile main.typ". The software itself is available as a binary file for all operating systems and needs around 60 MB on the SSD storage.

----------------
mainsimple.typ
----------------
#align(center)[
  #text(24pt, weight:"bold", "title of paper")
  
  #text(16pt, "Manuel Rodriguez\n 1 July 2026")
]

= 1 Introduction

#lorem(100)

= 2 Literature

- #lorem(10)
- #lorem(10)



If the typst user is reducing its demands to a minimum, the academic paper is ready for submission. Most authors have a need for more advanced layout so the file can be modified a bit.

----------------
maincomplex.typ
----------------
#set par(
  justify: true,
  spacing: 0.65em,
  first-line-indent: 2em,
)
#set text(
  font: "Liberation Sans",
  size: 9pt,
  lang: "en",
)

#align(center)[
  #text(24pt, weight:"bold", "title of paper")
  
  #text(16pt, "Manuel Rodriguez\n 1 July 2026")
]

#outline()

= 1 Introduction

#lorem(100)

#lorem(100)

= 2 Topic

== 2.1 Subtopic

#table(
  columns: 2,
  table.header[date][event],
  [May 2, 2026], [hello],
  [Jun 3, 2026], [world],
)

== 2.2 Subtopic

#figure(
  image("drawing2.jpg", width: 4cm),
  caption: [Drawing with pencil],
)

= 3 Literature

- #lorem(10)
- #lorem(10)




July 13, 2026

AI as open system

 The last AI winter during the early 1990s was caused by the ignorance towards open systems namely Teleoperation for robot control. What the AI researchers have prefered instead were autonomous algorithm controlled AI systems. The goal was to program a large scale software similar to an operating system or a word processing software and make the software higly intelligent. Such bloat AI projects have failed, even a program written in 200k lines of code in C/C++ code isn't able to control a toy car in an obstacle course.

The reason why closed system failed is because existing programming languages like C/C++ can't grasp reality outside of a robot, existing algorithms like RRT pathplanning are too slow for realtime planning and the possible amount of trajectories for a robot in the reality is too large. This mixtures of challenges prevents that robot projects in the 1990s have become succesful. The written sourcecode was useless and the project doesn't make any sense.

The term AI winter is referencing to a situation in which the problems are known but no answer is available. This answer is maybe the transition from closed systems towards open systems. Open systems in robotics are equal to teleoperation which means that the human operator controls the robot. So its not longer an algorithm controlled robot but its an RC car. The main advantage is that such an open system can be realized easier with existing technology. The needed software is minimal and no true Artificial Intelligence is required.

What is used instead for remote controlled robots is a sender/receiver device which is an interface between human and machine. Such a device has multiple tasks:
1. it receives radio waves over the air
2. it parses natural language commands
3. it receives sensor signals
4. it transmits radio waves to the remove control
5. it transmits natural language status information to the human operator

In one word, the transceiver connects the robot with the environment.



The picture on the left shows the older paradigm. A robot in enclosed by a box and forms a closed system. The robot's AI is a turing machine executed on the CPU and the goal is to invent a sophisticated algorithm which makes the robot intelligent.

The picture on the right shows the modern paradigm which assumes two different systems connected by a sender/receiver. THese two systems are the robot and the environment around the robot. Both systems need to communicate. Communication doesn't require an autonomous algorithm but a protocol.

The transition from older closed systems into modern open systems is equal to discard algorithm oriented AI in favor of a communication perspective.



July 12, 2026

Die KI Blase ist geplatzt ...

 Schauplatz: Ein Besprechungsraum am Rande der Endmontage in einem süddeutschen Automobilwerk.

Die Beteiligten:

    Dr. Matthias Vogt (48), Leiter der Innovations- und Automatisierungsabteilung.
    Elena Rostova (34), leitende Projektingenieurin für Robotik.
    Dr. Julian Arndt (41), Key Account Manager von „Apex Robotics“ (Hersteller des Roboters).

Auf dem Tisch stehen drei unberührte Kaffeetassen. Durch die Glasscheibe sieht man die Werkshalle, in der ein leerer Stellplatz markiert ist. Die Testwoche des humanoiden Prototyps „Apex-One“ ist vorbei.

Arndt: (bemüht optimistisch) Erst einmal vielen Dank, Herr Dr. Vogt, Frau Rostova, dass wir unseren Apex-One unter echten Linienbedingungen testen durften. Ein Vision-Language-Action-Model, kurz VLAM, direkt in der Aggregate-Montage einzusetzen, das ist Pionierarbeit. Ich habe mir die Logdaten angesehen – die semantische Erfassung der Werkzeuge war phänomenal, oder nicht?

Vogt: (seufzt, reibt sich die Schläfen) Herr Arndt, ich mache es kurz. Der Roboter ist bereits verpackt. Er steht auf einer Palette im Wareneingang und wartet auf Ihren Spediteur. Wir treten von der Kaufoption zurück und werden das Projekt plangemäß beenden.

Arndt: (konsterniert) Bitte? Nach nur einer Woche? Gab es Hardware-Ausfälle? Wir können das Modell sofort gegen die Revision 1.4 austauschen, die hat verstärkte Aktuatoren in den Handgelenken…

Rostova: Es liegt nicht an den Gelenken, Herr Arndt. Es liegt am Gehirn. Genauer gesagt: an der Latenz und der mangelnden Deterministik dieses KI-Ansatzes.

Arndt: Aber das VLAM ist die Zukunft! Sie steuern die Maschine mit natürlicher Sprache. Keine Zeile Code. Der Roboter sieht die Werkstücke, versteht den Befehl und handelt.

Rostova: Ja, in der Theorie. In der Praxis sah das so aus: Am Dienstag sollte der Roboter Getriebeölkühler aus der Kiste nehmen und am Chassis fixieren. Der Befehl lautete: „Nimm den Kühler, überprüfe die Dichtung und setze ihn an Position B.“ Wissen Sie, was passiert ist?

Arndt: Er hat die Position gesucht?

Rostova: Er hat elf Sekunden lang „nachgedacht“. Elf Sekunden Standzeit, in denen sein neuronales Netz die visuelle Szene mit dem Sprachbefehl abgeglichen hat. In der Taktzeit unserer Produktion sind elf Sekunden eine Ewigkeit. Und als die Spätschicht am Mittwoch den Befehl leicht abwandelte – „Kühler greifen, Dichtring checken, ran an B“ – hat das Modell halluziniert. Es hat den Kühler gegriffen und ihn mit achtzig Newtonmetern gegen die Windschutzscheibe gedrückt, weil es „ran an B“ als „Scheibe einschlagen“ interpretiert hat.

Arndt: Oh. Gab es einen Personenschaden?

Vogt: Gott sei Dank nein, die Lichtgitter haben ausgelöst. Aber die Windschutzscheibe war Schrott und das Band stand für zwanzig Minuten. Herr Arndt, wir bauen hier achthundert Fahrzeuge am Tag. Wir können uns keine Maschine leisten, die auf denselben Befehl dreimal unterschiedlich reagiert, nur weil sich das Umgebungslicht ändert oder der Werker einen Dialekt spricht.

Arndt: Das sind Feinheiten im Prompt-Engineering! Wir können das Modell feintunen. Wir füttern es mit spezifischen Daten aus Ihrer Halle. Mit einem Ersatzmodell und zwei Wochen Datenkorrektur kriegen wir die Fehlerquote unter ein Prozent.

Vogt: Ein Prozent? Das ist im Automobilbau eine Katastrophe. Ein herkömmlicher Knickarmroboter von Kuka oder Fanuc arbeitet mit einer Wiederholgenauigkeit von weniger als einem Zehntel Millimeter, stundenlang, fehlerfrei, deterministisch. Er denkt nicht nach, er tut es einfach.

Arndt: Aber ein Knickarmroboter kann nicht flexibel auf unstrukturierte Kisten reagieren oder per Sprache umprogrammiert werden! Humanoiden sind die Zukunft für die flexible Montage.

Rostova: Flexibilität nützt uns nichts, wenn sie auf Kosten der Prozesssicherheit geht. Ihr Apex-One hat versucht, einen Schlagschrauber wie eine Kaffeetasse zu greifen, weil am Donnerstag jemand eine Mate-Flasche neben der Station vergessen hatte und das Vision-Modell die Geometrien verwechselt hat. Die Multimodalität ist für komplexe, dynamische Industrieanwendungen einfach noch nicht reif. Es fehlen die harten Sicherheitsgarantien. Ein neuronales Netz ist eine Blackbox. Wir können nicht zertifizieren, was wir nicht mathematisch beweisen können.

Arndt: (schaut auf seine Notizen) Ich verstehe Ihre Frustration. Aber bedenken Sie den Imagegewinn. Ein humanoider Roboter an der Linie…

Vogt: (unterbricht ihn kühl) …ist teures Theater für die Aktionärshauptversammlung, aber kein Werkzeug für die Werkshalle. Wir brauchen keine Roboter, die wie Menschen aussehen und versuchen, wie Menschen zu denken, nur um Aufgaben zu erledigen, die eine starre Automatisierungslösung in einem Zehntel der Zeit für ein Fünftel der Kosten erledigt.

Arndt: Also kein Ersatzmodell? Auch kein kostenloser Folgetest mit unserer neuesten Software-Generation im Herbst?

Vogt: Nein. Das Thema Humanoiden ist für uns vorerst gestorben. Wir investieren das Budget wieder in klassische Portalroboter und smarte Kamerasysteme. Die sprechen zwar nicht mit uns, aber sie halten den Takt.

Rostova: (steht auf) Ich begleite Sie zum Wareneingang, Herr Arndt. Die Papiere für die Rückgabe liegen beim Meister.

Arndt: (packt enttäuscht sein Tablet ein) Schade. Sie verpassen den Anschluss an die nächste industrielle Revolution.

Vogt: Mag sein. Aber dafür steht mein Band morgen früh um sechs nicht still. Auf Wiedersehen, Herr Arndt.

July 10, 2026

History of TeX from 1985-1995

 For newbies in document typesetting, the current LaTeX ecosystem seems to be obsolete and populated with lots of useless packages. Its unclear about the the TeX community is talking exactly if they are discussing certain parameters for a certain LaTeX fork like Xelatex. To understand the current mess we have to go back some years into the past.

The dacade from 1985 until 1995 can be described as the rise of TeX. The system was using state of the art technology and made professional typesetting on a computer available for the mass. In 1985 Donald Knuth released Tex version 3.0 which evolved later into      
3.141592653, also he invented the .dvi output format. In the year 1990 TeX become popular for a larger audience, due to the development of distributions which combined TeX, fonts, and additional programs, also the extension LaTeX was created in the early 1990s. Around the year 1995, LaTeX had become the standard in academic publishing. A .tex file was compiled into a postscript file including mathematical equations and postscript fonts which was revolutionary at this time.

Unfurtunately, the years after 1995 can be described as a decline in the TeX community. There are multiple problems available. First, Donald Knuth decided to freeze the development of the TeX engine, secondly lots of forks were created like latex3, omega, context, pdflatex, xetex and so on with the attempt to improve the original project. The CTAN archive was initially planned as a repository of useful packages, evolved into a messy museum of obosolete code. Instead of throwing away outdated code, font specification and templates, the TeX Community decided to preserve the past at any price.

10 years later around the year 2005, the LaTeX ecosystem showed the first sign of serious problems. The mainstream typesetting reality has switched to the pdf format and introduced HTML documents for the internet, while TeX users were devoted to the former dvi/postscript pipeline. It was very difficult to use foreign special characters and the amount of possible packages increased.

July 09, 2026

The slow emergence of Artificial Intelligence

 AI and robotics was researched since decades. In contrast to other disciplines like computer science or mathematics there was no success available. Even if AI researchers have analyzed the subject from a scientific perspective and discussed the situation at conferences there were not able to identify major problems or offer possible answers. What was happen instead was a long disappointing journey.

Even if AI in the past suffered, lots of subjects were analyzed. Notable examples are: autonomous robotics, model predictive control, genetic algorithms, reinforcement learning, Turing maschines. All these subjects were seen as promising candidates towards the pathway to intelligent machinery. They can be called advanced subjects in computer science and many papers were written. The general idea was to describe intelligence as an optimization problem which can be measured with a score. For example, trajectory optimization tries to reduce the costs, while genetic algorithms are maximing the fitness of candidates. In both cases the computer is a device for solving a mathematical problem.

On the first look, it makes sense to describe robotics movement with model predictve control algorithms. It helps to translate a problem from the reality towards an abstract mathematical equation. The idea is, that artificial intelligence can be realized as a combination of computer science, mathematics and game theory. Most researchers in the past would agree, that such kind of interdisplinary approach is a sign of excellence and allows to discover future robotics algorithms. What the researchers in the 1990s and 2000s didn't know was that the describe workflow is a dead end. None of mentioned techniques lead to artificial intelligence.

Model predictive control is a good example for a dead end in robotics resarch. The subject was researched by multiple researchers independend from each other with a great effort. There is no obvious mistake in the equation nor in a certain paper about the subject. At the same time, the entire model predictive control research has to be called a dead end because it fails to control simple robots.

In the history of artificial intelligence such kind of dead end is not an exception but its default situation. All the other attempts to realize robotics like expert system, neural networks and 5th generation programming languages like Prolog have failed too. It seems that there was a need to explore all the non working principles to get a better understanding what sort of approach won't result into a working robot.

Ai research in the past was realized as an intersection of physics models, mathematical theories and computer science. The hope was that the combination of these powerful disciplines allows to create intelligent machinery. For example trajectory optimiziation has a background in theoretical physics, and can be implemented as an algorithm on a computer. This would allow to plan the movement of a robot.

What was unknown in the past or perhaps it was ignored was, that the state space in robotics is too large to use mathematical optimization problems. Predicting future states of a system is only possible if the system consists of a few variables e.g. in a predator-prey scenario modelled with Lotka–Volterra equations. Such a system can be calculated on a computer and future states can be processed in advanced. The concept fails on robotics domains like dexterous grasping or biped walking. The equations are not known or they are too complicated the calculate. Even if there are realistic physics simulators available like Box2D, its not possible to determine future states of these engines into the future.

Despite this pessimistic situation it makes sense to explore model predtctive control and other mathematical optimization techniques because it allows a better understanding of np hard problems. If its known, that the state space in robotics is too large, its possible to rethink about the situation and explore strategies how to reduce the state space. A state space reduction is the pathway to advanced robotics.

July 08, 2026

Microtype simulator in python

 

import pygame
import sys
import math

# Initialize Pygame
pygame.init()
pygame.font.init()

# Constants
WIDTH, HEIGHT = 1100, 780
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Professional Microtype Engine & Layout Simulator")
CLOCK = pygame.time.Clock()

# Palettes
COLOR_BG = (249, 248, 245)       # Premium archival paper
COLOR_TEXT = (35, 35, 35)        # Soft black
COLOR_MARGIN = (230, 90, 90)     # Margin guideline
COLOR_UI_BG = (225, 227, 230)
COLOR_UI_TEXT = (50, 55, 60)
COLOR_SLIDER = (70, 130, 180)
COLOR_ACTIVE = (46, 139, 87)     # SeaGreen for scores/active selections

# Load fonts
try:
    FONT_SIZE = 18
    FONT = pygame.font.SysFont("georgia", FONT_SIZE)
    FONT_BOLD = pygame.font.SysFont("georgia", FONT_SIZE, bold=True)
except:
    FONT = pygame.font.Font(None, FONT_SIZE)
    FONT_BOLD = pygame.font.Font(None, FONT_SIZE)

SAMPLE_TEXT = (
    "Typography is the art and technique of arranging type to make written language "
    "legible, readable, and appealing when displayed. The Knuth-Plass dynamic programming "
    "algorithm revolutionizes this by looking ahead at the entire paragraph. Instead of "
    "making hasty choices on a line-by-line basis, it distributes layout 'badness' evenly, "
    "preventing unexpected blocks of loose text. Combined with microtype tracking expansions, "
    "subtle margin protrusions yield pristine geometric columns resembling classic elite print."
)

# --- UI Widgets ---
class Slider:
    def __init__(self, x, y, w, h, min_val, max_val, start_val, label):
        self.rect = pygame.Rect(x, y, w, h)
        self.min_val = min_val
        self.max_val = max_val
        self.val = start_val
        self.label = label
        self.grabbed = False
        self.update_handle()

    def update_handle(self):
        ratio = (self.val - self.min_val) / (self.max_val - self.min_val)
        hx = self.rect.x + int(ratio * self.rect.w)
        self.handle_rect = pygame.Rect(hx - 5, self.rect.y - 4, 10, self.rect.h + 8)

    def draw(self, screen):
        lbl = FONT.render(f"{self.label}: {self.val:.2f}", True, COLOR_UI_TEXT)
        screen.blit(lbl, (self.rect.x, self.rect.y - 22))
        pygame.draw.rect(screen, (190, 195, 200), self.rect, border_radius=3)
        pygame.draw.rect(screen, COLOR_SLIDER, self.handle_rect, border_radius=3)

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.handle_rect.collidepoint(event.pos) or self.rect.collidepoint(event.pos):
                self.grabbed = True
        elif event.type == pygame.MOUSEBUTTONUP:
            self.grabbed = False
        elif event.type == pygame.MOUSEMOTION and self.grabbed:
            mx = max(self.rect.x, min(event.pos[0], self.rect.x + self.rect.w))
            rel = (mx - self.rect.x) / self.rect.w
            self.val = self.min_val + rel * (self.max_val - self.min_val)
            self.update_handle()

class RadioSelector:
    def __init__(self, x, y, options):
        self.x = x
        self.y = y
        self.options = options
        self.selected_index = 1 # Default to Knuth-Plass
        self.buttons = []
        
        for idx, opt in enumerate(options):
            bx = x + (idx * 280)
            self.buttons.append(pygame.Rect(bx, y, 20, 20))

    def draw(self, screen):
        lbl_title = FONT_BOLD.render("Line Breaking Algorithm:", True, COLOR_UI_TEXT)
        screen.blit(lbl_title, (self.x, self.y - 25))
        
        for idx, opt in enumerate(self.options):
            rect = self.buttons[idx]
            # Draw outer circle
            pygame.draw.circle(screen, COLOR_UI_TEXT, rect.center, 10, 2)
            # Draw internal selection
            if idx == self.selected_index:
                pygame.draw.circle(screen, COLOR_ACTIVE, rect.center, 6)
            
            lbl = FONT.render(opt, True, COLOR_UI_TEXT)
            screen.blit(lbl, (rect.x + 25, rect.y + 1))

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            for idx, rect in enumerate(self.buttons):
                # Expanded click zone for user convenience
                click_zone = rect.inflate(150, 10)
                if click_zone.collidepoint(event.pos):
                    self.selected_index = idx
                    return True
        return False

# --- Helper Text Calculation Tools ---
def compute_word_widths(words, font, tracking):
    return [sum(font.size(char)[0] + tracking for char in word) for word in words]

def calc_line_badness(width, test_width, num_gaps, base_space_width, min_space, max_space, ideal_space, is_last=False):
    if num_gaps == 0:
        remaining = width - test_width
        return (remaining ** 2) if remaining >= 0 else 500000
    
    actual_space = (width - test_width) / num_gaps
    
    if actual_space < min_space:
        # Heavily penalize over-compressed lines
        return 100000 + (min_space - actual_space) * 50000
    elif actual_space > max_space:
        # Loose lines
        return int(((actual_space - max_space) ** 2) * 500)
    else:
        # Standard deviation penalty
        badness = int(((actual_space - ideal_space) ** 2) * 100)
        if is_last and actual_space > ideal_space:
            return 0 # Last line of a paragraph shouldn't stretch to fill the margin
        return badness

def apply_protrusion(word, font, protrusion):
    protruding_chars = [".", ",", "-", "!", "?"]
    if protrusion > 0 and word[-1:] in protruding_chars:
        return font.size(word[-1:])[0] * protrusion * 0.5
    return 0

# --- Line-Breaking Core Algorithms ---

def layout_greedy(words, word_widths, font, width, min_space, max_space, ideal_space, protrusion):
    """ a) Traditional First-Fit Greedy Algorithm """
    lines = []
    current_line, current_widths = [], []
    current_width = 0
    
    for idx, word in enumerate(words):
        w_width = word_widths[idx]
        p_adjust = apply_protrusion(word, font, protrusion)
        
        # Test if it fits with standard spaces
        test_w = current_width + w_width + (ideal_space if current_line else 0) - p_adjust
        if test_w <= width or not current_line:
            current_line.append(word)
            current_widths.append(w_width)
            current_width += w_width + (ideal_space if len(current_line) > 1 else 0)
        else:
            # Seal line
            num_gaps = len(current_line) - 1
            last_word_pad = apply_protrusion(current_line[-1], font, protrusion)
            pure_width = sum(current_widths)
            
            space_used = (width - (pure_width - last_word_pad)) / num_gaps if num_gaps > 0 else ideal_space
            badness = calc_line_badness(width, pure_width - last_word_pad, num_gaps, ideal_space, min_space, max_space, ideal_space)
            
            lines.append((current_line, current_widths, space_used, False, badness))
            current_line, current_widths = [word], [w_width]
            current_width = w_width
            
    if current_line:
        num_gaps = len(current_line) - 1
        last_word_pad = apply_protrusion(current_line[-1], font, protrusion)
        pure_width = sum(current_widths)
        space_used = ideal_space
        badness = calc_line_badness(width, pure_width - last_word_pad, num_gaps, ideal_space, min_space, max_space, ideal_space, is_last=True)
        lines.append((current_line, current_widths, space_used, True, badness))
        
    return lines

def layout_knuth_plass(words, word_widths, font, width, min_space, max_space, ideal_space, protrusion):
    """ b) Look-Ahead Optimization (Global Minimum Variance) """
    n = len(words)
    dp = [(float('inf'), -1, ideal_space, 0)] * (n + 1)
    dp[0] = (0, -1, ideal_space, 0)
    
    for i in range(n):
        if dp[i][0] == float('inf'): continue
        current_width = 0
        for j in range(i, n):
            current_width += word_widths[j]
            num_gaps = j - i
            is_last = (j == n - 1)
            
            p_adjust = apply_protrusion(words[j], font, protrusion)
            line_txt_w = current_width - p_adjust
            
            badness = calc_line_badness(width, line_txt_w, num_gaps, ideal_space, min_space, max_space, ideal_space, is_last)
            
            actual_space = ideal_space
            if num_gaps > 0 and not is_last:
                actual_space = (width - line_txt_w) / num_gaps

            p_cost = dp[i][0] + badness
            if p_cost < dp[j + 1][0]:
                dp[j + 1] = (p_cost, i, actual_space, badness)

    lines, curr = [], n
    while curr > 0:
        parent = dp[curr][1]
        if parent == -1: break
        is_last = (curr == n)
        lines.append((words[parent:curr], word_widths[parent:curr], dp[curr][2], is_last, dp[curr][3]))
        curr = parent
    lines.reverse()
    return lines

def layout_first_fit_tight(words, word_widths, font, width, min_space, max_space, ideal_space, protrusion):
    """ c) Alternating Minimum Space Greedy Algorithm """
    # This variant forces as many words onto the line as physically allowed by compressing down to min_space limits.
    lines = []
    current_line, current_widths = [], []
    
    for idx, word in enumerate(words):
        w_width = word_widths[idx]
        current_line.append(word)
        current_widths.append(w_width)
        
        p_adjust = apply_protrusion(word, font, protrusion)
        num_gaps = len(current_line) - 1
        min_needed = sum(current_widths) + (num_gaps * min_space) - p_adjust
        
        if min_needed > width and num_gaps > 0:
            # Overfilled line, dump the last token to the next row
            popped_word = current_line.pop()
            popped_width = current_widths.pop()
            
            num_gaps = len(current_line) - 1
            last_word_pad = apply_protrusion(current_line[-1], font, protrusion)
            pure_width = sum(current_widths)
            
            space_used = (width - (pure_width - last_word_pad)) / num_gaps if num_gaps > 0 else ideal_space
            badness = calc_line_badness(width, pure_width - last_word_pad, num_gaps, ideal_space, min_space, max_space, ideal_space)
            
            lines.append((current_line, current_widths, space_used, False, badness))
            current_line, current_widths = [popped_word], [popped_width]
            
    if current_line:
        num_gaps = len(current_line) - 1
        last_word_pad = apply_protrusion(current_line[-1], font, protrusion)
        pure_width = sum(current_widths)
        badness = calc_line_badness(width, pure_width - last_word_pad, num_gaps, ideal_space, min_space, max_space, ideal_space, is_last=True)
        lines.append((current_line, current_widths, ideal_space, True, badness))
        
    return lines

# --- Rendering ---
def render_paragraph(lines, font, x_start, y_start, tracking, protrusion, leading_ratio):
    y = y_start
    line_height = int(font.get_linesize() * leading_ratio)
    
    for line_words, line_widths, space_width, is_last, _ in lines:
        x = x_start
        num_words = len(line_words)
        
        for w_idx, word in enumerate(line_words):
            for c_idx, char in enumerate(word):
                char_surf = font.render(char, True, COLOR_TEXT)
                render_x = x
                if w_idx == num_words - 1 and c_idx == len(word) - 1:
                    render_x += apply_protrusion(word, font, protrusion)

                SCREEN.blit(char_surf, (render_x, y))
                x += char_surf.get_width() + tracking
            
            if w_idx < num_words - 1:
                x += space_width
        y += line_height

# --- UI Layout ---
sliders = [
    Slider(50, 540, 260, 10, -1.5, 3.0, 0.0, "Font Expansion (Tracking)"),
    Slider(380, 540, 260, 10, 0.4, 1.0, 0.65, "Min Word Space Elasticity"),
    Slider(710, 540, 260, 10, 1.0, 3.0, 1.70, "Max Word Space Elasticity"),
    Slider(50, 620, 260, 10, 0.0, 1.2, 0.5, "Character Protrusion"),
    Slider(380, 620, 260, 10, 0.8, 2.5, 1.3, "Line Height (Leading)")
]

algo_radio = RadioSelector(50, 710, ["a) Greedy Algorithm", "b) Knuth-Plass Ahead", "c) Space-Tight Fit"])

MARGIN_LEFT = 200
BOX_WIDTH = 700

# Main loop
while True:
    SCREEN.fill(COLOR_BG)
    
    # Event Engine Loop
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        for slider in sliders:
            slider.handle_event(event)
        algo_radio.handle_event(event)

    # Drawing background infrastructure boundaries
    pygame.draw.rect(SCREEN, COLOR_UI_BG, (0, 480, WIDTH, HEIGHT - 480))
    pygame.draw.line(SCREEN, (190, 195, 200), (0, 480), (WIDTH, 480), 2)
    
    pygame.draw.line(SCREEN, COLOR_MARGIN, (MARGIN_LEFT, 75), (MARGIN_LEFT, 450), 1)
    pygame.draw.line(SCREEN, COLOR_MARGIN, (MARGIN_LEFT + BOX_WIDTH, 75), (MARGIN_LEFT + BOX_WIDTH, 450), 1)

    # Gather metrics
    base_space_width = FONT.size(" ")[0]
    tracking_val = sliders[0].val
    min_space = base_space_width * sliders[1].val
    max_space = base_space_width * sliders[2].val
    protrusion_val = sliders[3].val
    leading_val = sliders[4].val

    # Re-tokenize and check widths inside runtime
    words = SAMPLE_TEXT.split(" ")
    word_widths = compute_word_widths(words, FONT, tracking_val)

    # Route processing via radio flag selections
    if algo_radio.selected_index == 0:
        computed_lines = layout_greedy(words, word_widths, FONT, BOX_WIDTH, min_space, max_space, base_space_width, protrusion_val)
    elif algo_radio.selected_index == 1:
        computed_lines = layout_knuth_plass(words, word_widths, FONT, BOX_WIDTH, min_space, max_space, base_space_width, protrusion_val)
    else:
        computed_lines = layout_first_fit_tight(words, word_widths, FONT, BOX_WIDTH, min_space, max_space, base_space_width, protrusion_val)

    # Cumulative Badness Score Calculation
    total_paragraph_badness = sum(line[4] for line in computed_lines)

    # Render Paragraph Blocks
    render_paragraph(computed_lines, FONT, MARGIN_LEFT, 95, tracking_val, protrusion_val, leading_val)

    # Render Widgets
    for slider in sliders:
        slider.draw(SCREEN)
    algo_radio.draw(SCREEN)

    # Display Badness score at the top panel
    score_lbl = FONT_BOLD.render(f"Overall Paragraph Badness Score: {total_paragraph_badness}", True, COLOR_ACTIVE)
    SCREEN.blit(score_lbl, (MARGIN_LEFT, 35))

    pygame.display.flip()
    CLOCK.tick(30)