-
Notifications
You must be signed in to change notification settings - Fork 0
Proof of concept ‐ Using AI, Self‐Evolving Game
Credits: Thanks to George P. Afentakis for this inspired program.
The concept of a Self-Evolving Program using Artificial Intelligence focuses on systems where the AI component actively modifies the application's underlying source code or configuration rules. Unlike traditional AI that merely optimizes parameters or generates outputs, this approach grants the AI the meta-ability to act as its own programmer. . The AI, often based on techniques like Genetic Algorithms or advanced Large Language Models (LLMs), monitors the program's performance and identifies bottlenecks or opportunities for new functionality. It then generates or alters specific code segments, typically within a safe, modular, and controlled environment, and automatically integrates the change after rigorous testing. This capability transforms the program from a fixed piece of software into an autopoietic system—one that can iteratively refine its own structure to maximize efficiency and adapt to unforeseen challenges in real-time, ushering in a new era of truly autonomous software development.
That's a great idea! Focusing on the Game of Life grounds the abstract concept of "self-evolving" code in a tangible, recognizable simulation.
Here is the paragraph specifically focused on Conway's Game of Life:
Conway's Game of Life is an ideal platform for demonstrating self-evolving programs because it is a Turing-complete cellular automaton defined by only four simple, static rules (survival, death by loneliness, death by overcrowding, and birth). The self-evolving concept introduces an external AI layer that monitors the Game of Life's ongoing state, identifying persistent, stable patterns (like gliders or still life forms) or emergent, complex phenomena. Instead of merely observing, the AI system can use its analysis to modify the fundamental rule set of the Game of Life itself, or strategically inject new cell configurations into the grid. This meta-level control allows the program to guide the evolution of the simulation, perhaps to maximize population density, ensure pattern longevity, or intentionally crash the simulation, showcasing AI's capability to rewrite the governing logic of its own environment.
This diagram illustrates the workflow of the Proof of Concept program, detailing how the simulation uses Artificial Intelligence (AI) to dynamically generate its own rules. The process is broken down into three main phases: AI Rule Generation, Initialization, and the continuous Simulation Loop.
The program begins by gathering user input for the number of generations and a Rule Suggestion. This suggestion is passed to the AI component . The AI is prompted with the base sample rules and the user's idea, and in response, it generates new FBASIC Rule Code (RuleProgram). Crucially, the AI also provides an Explanation of Changes (RuleChange). Both the executable code and the human-readable explanation are saved for persistence.
Before the simulation starts, the program Initializes a Random
The core of the system is the Simulation Loop, which runs for the specified number of generations (
- The current Grid State is Displayed.
- The grid data is prepared and Stored in a Memory Stream.
- The program executes the AI-generated code using the command
eval RuleProgram. This is the self-evolving action, where the program runs the dynamic rules created by the AI to calculate the next state. - The Next Grid State is Retrieved and used to Update the Grid.
- The generation counter is incremented, and the loop repeats.
Once the generations are complete, the program exits, printing the AI's Final Rule Summary to show the user exactly how the rules were changed during the PoC run.
graph TD
id1[Start Program Execution] --> id2{Input: Generations and AI Rule Prompt};
subgraph AI_RULE_GENERATION
direction TB
id2 -- Rule Suggestion --> id3[AI Prompted with Sample Rules];
id3 --> id4[AI Generates New FBASIC Rule Code];
id4 --> id5[AI Writes Rule Change Explanation];
id4 --> id6[Save Generated Rule Code lifeGame.rule];
id5 --> id7[Save Rule Change Text lifeGame.txt];
end
id8[Initialize Random 16x16 Grid] --> id9(Initialize Generation Counter: gen=0);
subgraph SIMULATION_LOOP
direction TB
id9 --> id10{Current Generation < M?};
id10 -- No --> id11[Simulation Finished];
id10 -- Yes --> id12[Display Grid State];
id12 --> id13[Store Current Grid in Memory Stream];
id13 --> id14[Execute AI Code eval RuleProgram];
id14 --> id15[Retrieve Next Grid State];
id15 --> id16[Update GameScreen];
id16 --> id17[Increment Generation];
id17 --> id10;
end
id11 --> id18[Print AI's Final Rule Summary];
id18 --> id19[End Program];
The scope of this program is to implement a self-evolving version of Conway's Game of Life on a fixed
The program encompasses three main areas: initialization, simulation, and AI rule generation.
-
Grid Size: Fixed at
$N \times N$ , where$N=16$ (a$16 \times 16$ grid). -
Initialization: The grid is initialized with a random distribution of live cells (
@) and dead cells (.), with live cells having approximately a$27%$ probability of appearance. -
Execution: The program runs for a user-specified number of generations (
$M$ ), printing the grid state to the console for each generation. -
Mechanics: The simulation logic reads the current grid from a
MEMSTREAM(GridStream), applies the rules defined in theRuleProgram(which is code generated by the AI), and writes the new grid state back to the stream, thus completing one generation cycle.
- Self-Evolving Core: The primary function is to replace the standard Game of Life rules with rules generated by an AI model (Claude).
-
User Input: The user is prompted for a
suggestionRule(e.g., "Add 5 new rules," or "Be Very Creative") to influence the AI's code generation. -
Code Generation: An AI session (
RuleSession) is used to prompt the AI to rewrite asamplecodetemplate—which contains the classic Game of Life rules—into a new set of rules in the FBASIC low code language. The AI is specifically instructed to output only the executable code (RuleProgram). -
Documentation: The AI is also prompted to explain what changes it made (
RuleChange), providing documentation for the new rules.
-
Dynamic Execution: The AI-generated code (
RuleProgram) is executed using theevalcommand, allowing the program's core logic to be changed on the fly. -
Persistence: The generated rule code (
RuleProgram) and the AI's explanation of the change (RuleChange) are saved to local files (lifeGame.ruleandlifeGame.txt). -
Loading: The user has the option (
L) to skip AI generation and load the last saved rule set from these files, which is useful for testing or re-running a specific generated rule.
In essence, the program's scope is not just to run a simulation, but to demonstrate a Proof of Concept (PoC) for AI-driven self-modification by using the simple, rule-based Game of Life as a testbed.
The Conway's Game of Life.
How many Generations should I'll simulate: 10 Should the Game rule include anything special? (E.g. How many New rules should I add? Or just write "Be Very Creative")
Left empty line, to use the sample code or enterLand the last rule will be used: Be Realistic
Waiting AI to make a new rule code.
Generated program saved.
Generation 0
. . . @ @ . @ . . . . . . . . .
. . . . . @ . @ @ . . @ . . . .
@ . @ @ @ . @ @ . @ . . . . . @
. @ . . @ . . . @ . . @ @ . . .
. . @ . . @ . @ . . @ . . @ @ @
. . . @ @ . . . . . . . . . . .
. . . . . . . . . . @ @ . . @ @
. . . . . . . . . @ . . . . . @
@ . . . @ . . . . @ @ . @ @ . .
. @ @ . . . . . . @ . . . @ . .
@ @ @ . . . @ . . . . . . . @ .
. . . . . . . . . . @ . @ . . .
@ . @ . . . . . @ @ . . @ @ . .
. @ . @ . . . . . @ . @ . @ . .
@ @ . . @ . . . . . . . . . @ .
. @ . . @ . . . . . . @ . . . @
...
...
...
Generation 9
. @ . @ . @ . . . @ . @ @ . . .
. @ . @ @ . @ @ @ . . . @ . @ .
. @ . @ @ . @ @ @ . . @ @ . @ @
. @ . . . . . @ @ . . @ @ @ @ @
. @ . . . @ . @ @ . . . . . . .
@ . @ . . . . @ . @ . . . . @ @
. . . . . . @ @ @ . . @ @ @ . .
@ @ @ @ @ . @ . @ . . @ @ @ . .
@ @ . . . . @ . . . . . . @ . @
@ @ @ . . @ @ . . . . . . . @ .
. . @ @ @ . @ . . . . . . . @ @
. . @ @ @ . . . @ @ . . @ . . @
. . . . @ @ . . @ @ @ @ @ . @ @
@ @ . . . @ . @ . . . . . . . @
. @ . . . @ @ @ . @ @ @ . . @ .
. . . . @ @ @ . . @ @ @ @ @ . .
User Prompt: Be realistic
Change on the rules: I introduced three major changes:
- Toroidal wrapping: The grid now wraps around at the edges (like a torus), so cells at the boundary interact with cells on the opposite side instead of treating out-of-bounds as dead cells.
- Entropy-based randomness: I added a deterministic but varying "entropy" factor based on position and generation number that creates probabilistic behavior in certain neighbor count scenarios.
- Modified survival/birth rules: Living cells now survive with 1, 2, or 3 neighbors (instead of just 2 or 3), and can sometimes survive with 4 neighbors based on entropy. Dead cells can be born with 2 or 4 neighbors (with entropy conditions) in addition to the standard 3 neighbors, creating more chaotic and unpredictable patterns that resist stabilization.
The Conway's Game of Life. How many Generations should I'll simulate: 10 Should the Game rule include anything special? (E.g. How many New rules should I add? Or just write "Be Very Creative" ) Left empty line, to use the sample code or enter
Land the last rule will be used: Each cell can have only two other cells in side areas. If more will die. Choose a clear notation Waiting AI to make a new rule code. Generated program saved.
Generation 0
. . . . . . @ . . . @ . . . . .
. . . . . @ . @ . . @ . . . . .
. @ . . . . . . . . . . . @ . @
. @ . . . . . . . . . . @ . . .
. . . . . . . @ . . . . . . @ .
@ @ . @ @ . . @ @ @ . . @ . . .
@ . @ . . @ . . @ @ . . . . @ .
@ . @ . . . . . . @ . . . . . .
. @ . . . . @ . @ . . . . . . .
. . . . . . . @ . . @ . . . . @
@ . @ . @ . @ . . . . @ @ . . .
. . @ . @ . . . @ . . . . @ @ @
@ . . . . . . @ . . . . . @ . @
. @ @ . . . @ . . @ . @ @ . . .
. . . @ . @ . @ @ @ . @ . @ . .
@ @ . . . @ . . . . . . @ . . .
...
...
...
Generation 9
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
@ @ @ @ @ . . @ @ @ . . . . . .
. . . . . . . . @ @ . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . @ @ . . .
. . . . . . . . . . . . . @ @ @
. . . . . . . . . . . . . . . .
. @ @ . . . . . . . @ @ @ . . .
. . . . . @ @ @ @ @ @ @ . . . .
@ @ . . . . . . . . . . . . . .
User Prompt: Each cell can have only two other cells in side areas. If more will die. Choose a clear notation
Change on the rules: I changed the Game of Life to only count the two side neighbors (left and right) instead of all 8 surrounding cells. The new rules are: a live cell stays alive if it has exactly 1 or 2 live side neighbors, otherwise it dies (from isolation with 0 neighbors or overcrowding with more than 2). A dead cell becomes alive if it has exactly 2 live side neighbors. This creates a one-dimensional-like behavior where patterns propagate horizontally across rows, with each row evolving independently based only on left-right relationships. Cells can no longer be influenced by diagonal or vertical neighbors, fundamentally changing the dynamics from Conway's complex 2D patterns to simpler horizontal wave-like behaviors.
Generated Code
let N = 16
SREWIND GridStream
STOS GridStream TO GridText
let row = 0
let col = 0
let qRow = 0
let qCol = 0
let idx = 0
let cellChar = "."
let curCell = "."
let sideNeighbors = 0
let newChar = "."
let NextText = ""
For row = 1 To N
For col = 1 To N
qRow = row
qCol = col
GOSUB GetCell
curCell = cellChar
sideNeighbors = 0
qRow = row
qCol = col - 1
GOSUB GetCell
if cellChar = "@" Then
sideNeighbors = sideNeighbors + 1
EndIf
qRow = row
qCol = col + 1
GOSUB GetCell
if cellChar = "@" Then
sideNeighbors = sideNeighbors + 1
EndIf
newChar = "."
if curCell = "@" Then
if sideNeighbors = 1 Then
newChar = "@"
EndIf
if sideNeighbors = 2 Then
newChar = "@"
EndIf
Else
if sideNeighbors = 2 Then
newChar = "@"
EndIf
EndIf
NextText = NextText + newChar
Next col
Next row
SREWIND GridStream
STOS GridStream FROM NextText
RESULT 0
END
GetCell:
if qRow < 1 Then
cellChar = "."
RETURN
EndIf
if qRow > N Then
cellChar = "."
RETURN
EndIf
if qCol < 1 Then
cellChar = "."
RETURN
EndIf
if qCol > N Then
cellChar = "."
RETURN
EndIf
idx = (qRow - 1) * N + qCol
cellChar = mid(GridText, idx, 1)
RETURN
Find the latest revision of this program in Interactive Testing Console as
LifeAI.bas
rem ============================================
rem The Game of Life.
rem Uses AI to evolve the grid
rem (c) George P. Afentakis
rem ============================================
print "\n\n\nThe Conway's Game of Life."
print "How many Generations should I'll simulate: ";
input M
gosub MakeAIRules
let SEED=rnd()*34214*M 'SEED is a random 5 digit number or more
let i = 0
let N = 16
MEMSTREAM GridStream
REM Init random grid
For i = 1 To N * N
let gameChar = "."
SEED = mod(SEED * 16807, 2147483647)
let rng = mod(SEED * 11, 100)
if rng < 27 Then
gameChar = "@"
EndIf
SDATA GameScreen gameChar
Next i
let gen = 0
For gen = 0 To M - 1
print "Generation " + str(gen)
RESET GameScreen
let GameOutput = ""
let cnt = 0
FOREACH GameScreen
GameOutput = GameOutput + [GameScreen.Item] + " "
cnt = cnt + 1
if mod(cnt, N) = 0 Then
GameOutput = GameOutput + "\n"
EndIf
ENDFOREACH GameScreen
print GameOutput
print ""
if gen = M - 1 Then
GOTO DoneAll
EndIf
REM write grid to GridStream
RESET GameScreen
let GridText = ""
FOREACH GameScreen
GridText = GridText + [GameScreen.Item]
ENDFOREACH GameScreen
SREWIND GridStream
STOS GridStream FROM GridText
REM run the AI generated code
eval RuleProgram
REM read new grid back
SREWIND GridStream
STOS GridStream TO GridTextNext
let totalCells = len(GridTextNext)
let idx = 0
For idx = 1 To totalCells
let ch = mid(GridTextNext, idx, 1)
SSET GameScreen idx ch
Next idx
Next gen
DoneAll:
print "\nChange on the rules:\n"
print RuleChange
print "\n\n"
HALT
REM ============================================
REM GenerateRule
REM Ask AI to generate code based on a template
REM ============================================
REM --- Configure AI provider & session ---
MakeAIRules:
AIPROVIDER MyProvider, CLAUDE, *
AISESSION RuleSession, MyProvider, "Generate code in a tiny BASIC-like language called FBASIC. You must output ONLY FBASIC code, no explanations, no markdown, do no use ``` fences."
print "Should the Game rule include anything special?"
print "(E.g. How many New rules should I add? Or just write \"Be Very Creative\" )"
print "Left empty line, to use the sample code or enter `L` and the last rule will be used: ";
input suggestionRule
gosub loadSampleCode
if suggestionRule = "" then
let RuleProgram = samplecode
return
endif
if ucase(suggestionRule) = "L" Then
gosub LoadLastRule
return
endif
let RuleProgram = ""
let prompt = "Here is a complete novel programming language for a Game of Life rule:" + "\n" + samplecode
let prompt = "\nRewrite this so it follows different rules the rules can be as usual Or as diffrent New And creative as you want.
Output ONLY the final FBASIC program code without markdown code. No explanations. No code block in the begging Or the end.
The point here Is playing Conways Game of life. But utilize whatever New rules you want."+ suggestionRule
PRINT "Waiting AI to make a new rule code."
AIPROMPT RuleSession, RuleProgram, prompt
AIPROMPT RuleSession, RuleChange, "What exactly did you change? What New rules did you introduce Or what old ones did you delete? Explain in 1 to 10 sentences"
gosub SaveGeneratedRule
RETURN
rem
rem Save the Generated rule
rem
SaveGeneratedRule:
FILESTREAM RuleFile, out, "","Output", "lifeGame.rule"
STOS RuleFile FROM RuleProgram
FILESTREAM ChangeFile, out, "","Output", "lifeGame.txt"
let txt=suggestionRule+"\n\n"+RuleChange
STOS ChangeFile FROM txt
sclose ChangeFile
sclose RuleFile
PRINT "Generated program saved."
return
rem
rem Load last Generated rule
rem
LoadLastRule:
FILESTREAM oldRuleFile, in, "","Output", "lifeGame.rule"
STOS oldRuleFile TO RuleProgram
FILESTREAM oldRuleText, in, "","Output", "lifeGame.txt"
STOS oldRuleText TO RuleChange
sclose oldRuleText
sclose oldRuleFile
PRINT "Last generated program loaded."
return
rem
rem Sample Code
rem
loadSampleCode:
let samplecode = "let N = 16
SREWIND GridStream
STOS GridStream TO GridText
let row = 0
let col = 0
let qRow = 0
let qCol = 0
let idx = 0
let cellChar = \".\"
let curCell = \".\"
let liveNeighbors = 0
let newChar = \".\"
let NextText = \"\"
For row = 1 To N
For col = 1 To N
qRow = row
qCol = col
GOSUB GetCell
curCell = cellChar
liveNeighbors = 0
qRow = row - 1
qCol = col - 1
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row - 1
qCol = col
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row - 1
qCol = col + 1
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row
qCol = col - 1
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row
qCol = col + 1
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row + 1
qCol = col - 1
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row + 1
qCol = col
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
qRow = row + 1
qCol = col + 1
GOSUB GetCell
if cellChar = \"@\" Then
liveNeighbors = liveNeighbors + 1
EndIf
newChar = \".\"
if curCell = \"@\" Then
if liveNeighbors = 2 Then
newChar = \"@\"
EndIf
if liveNeighbors = 3 Then
newChar = \"@\"
EndIf
Else
if liveNeighbors = 3 Then
newChar = \"@\"
EndIf
EndIf
NextText = NextText + newChar
Next col
Next row
SREWIND GridStream
STOS GridStream FROM NextText
RESULT 0
END
GetCell:
if qRow < 1 Then
cellChar = \".\"
RETURN
EndIf
if qRow > N Then
cellChar = \".\"
RETURN
EndIf
if qCol < 1 Then
cellChar = \".\"
RETURN
EndIf
if qCol > N Then
cellChar = \".\"
RETURN
EndIf
idx = (qRow - 1) * N + qCol
cellChar = mid(GridText, idx, 1)
RETURN
"
return