ΠΡ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΡΠ°ΠΌΠ° ΡΠ΅Π±Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΡΠ΅Ρ ΠΈ ΡΠ²ΠΎΠ»ΡΡΠΈΠΎΠ½ΠΈΡΡΠ΅Ρ, ΡΠΎΠ·Π΄Π°Π²Π°Ρ Π½ΠΎΠ²ΡΠ΅ Π²Π΅ΡΡΠΈΠΈ ΡΠ΅Π±Ρ!
ΠΠ΅Π½Π΅ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π²ΡΠΎΠΌΠ°Ρ:
cpp
#include <EEPROM.h>
#include <avr/wdt.h>
#define PROGRAM_SIZE 512
#define POPULATION_SIZE 4
// Π‘ΡΡΡΠΊΡΡΡΠ° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ (Π³Π΅Π½ΠΎΠΌ)
struct Program {
uint8_t code[PROGRAM_SIZE];
uint16_t fitness;
uint8_t generation;
uint8_t mutationCount;
};
Program population[POPULATION_SIZE];
uint8_t bestProgram[PROGRAM_SIZE];
uint16_t bestFitness = 0;
// ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ ΠΈΠ· EEPROM
void loadProgram(uint8_t index) {
uint16_t addr = index * PROGRAM_SIZE;
for (uint16_t i = 0; i < PROGRAM_SIZE; i++) {
population[index].code[i] = EEPROM.read(addr + i);
}
}
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ Π² EEPROM
void saveProgram(uint8_t index) {
uint16_t addr = index * PROGRAM_SIZE;
for (uint16_t i = 0; i < PROGRAM_SIZE; i++) {
EEPROM.write(addr + i, population[index].code[i]);
}
}
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ (ΠΈΠΌΠΈΡΠ°ΡΠΈΡ)
uint16_t executeProgram(uint8_t* code) {
uint16_t result = 0;
uint16_t pc = 0;
while (pc < PROGRAM_SIZE && code[pc] != 0xFF) { // 0xFF = HALT
uint8_t op = code[pc];
switch (op) {
case 0x01: { // ADD
result += code[pc + 1];
pc += 2;
break;
}
case 0x02: { // XOR
result ^= code[pc + 1];
pc += 2;
break;
}
case 0x03: { // SHIFT
result <<= (code[pc + 1] % 8);
pc += 2;
break;
}
case 0x04: { // BRANCH
if (result > 1000) {
pc = code[pc + 1];
} else {
pc += 2;
}
break;
}
default:
pc++;
}
}
return result;
}
// ΠΡΠ΅Π½ΠΊΠ° ΠΏΡΠΈΡΠΏΠΎΡΠΎΠ±Π»Π΅Π½Π½ΠΎΡΡΠΈ (ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ + ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΡΡΡ)
uint16_t calculateFitness(uint8_t* code) {
// ΠΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ Ρ ΡΠ°Π·Π½ΡΠΌΠΈ Π²Ρ
ΠΎΠ΄Π½ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ
uint16_t totalScore = 0;
uint16_t complexity = 0;
for (uint16_t test = 0; test < 10; test++) {
// ΠΠΎΠΏΠΈΡΡΠ΅ΠΌ ΠΊΠΎΠ΄ Π²ΠΎ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ ΠΎΠ±Π»Π°ΡΡΡ
uint8_t testCode[PROGRAM_SIZE];
memcpy(testCode, code, PROGRAM_SIZE);
// ΠΠΎΠ΄ΡΡΠ°Π²Π»ΡΠ΅ΠΌ Π²Ρ
ΠΎΠ΄Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅
testCode[1] = test;
testCode[3] = test * 2;
uint16_t result = executeProgram(testCode);
totalScore += result;
// Π‘Π»ΠΎΠΆΠ½ΠΎΡΡΡ (ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π½Π΅Π½ΡΠ»Π΅Π²ΡΡ
Π±Π°ΠΉΡ)
for (uint16_t i = 0; i < PROGRAM_SIZE; i++) {
if (code[i] != 0) complexity++;
}
}
// Π€ΠΈΠ·ΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΏΡΠΈΡΠΏΠΎΡΠΎΠ±Π»Π΅Π½Π½ΠΎΡΡΡ = ΡΠ΅Π·ΡΠ»ΡΡΠ°Ρ / ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ
uint16_t fitness = totalScore / (complexity / 16 + 1);
return fitness;
}
// ΠΡΠΎΡΡΠΈΠ½Π³ΠΎΠ²Π΅Ρ (ΠΎΠ±ΠΌΠ΅Π½ ΡΡΠ°ΡΡΠΊΠ°ΠΌΠΈ ΠΊΠΎΠ΄Π°)
void crossover(uint8_t* parent1, uint8_t* parent2, uint8_t* child1, uint8_t* child2) {
uint16_t point1 = random(PROGRAM_SIZE);
uint16_t point2 = random(PROGRAM_SIZE);
if (point1 > point2) {
uint16_t temp = point1;
point1 = point2;
point2 = temp;
}
for (uint16_t i = 0; i < PROGRAM_SIZE; i++) {
if (i < point1 || i > point2) {
child1[i] = parent1[i];
child2[i] = parent2[i];
} else {
child1[i] = parent2[i];
child2[i] = parent1[i];
}
}
}
// ΠΡΡΠ°ΡΠΈΡ
void mutate(uint8_t* code) {
uint8_t mutations = random(1, 10);
for (uint8_t i = 0; i < mutations; i++) {
uint16_t pos = random(PROGRAM_SIZE);
code[pos] ^= (1 << random(8));
}
}
// ΠΠ²ΠΎΠ»ΡΡΠΈΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ
void evolvePrograms() {
// Π‘Π΅Π»Π΅ΠΊΡΠΈΡ (ΡΡΡΠ½ΠΈΡΠ½Π°Ρ)
uint8_t parents[POPULATION_SIZE];
for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
uint8_t best = random(POPULATION_SIZE);
for (uint8_t j = 0; j < 3; j++) {
uint8_t contender = random(POPULATION_SIZE);
if (population[contender].fitness > population[best].fitness) {
best = contender;
}
}
parents[i] = best;
}
// Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΠΎΠΊΠΎΠ»Π΅Π½ΠΈΠ΅
Program newPop[POPULATION_SIZE];
for (uint8_t i = 0; i < POPULATION_SIZE; i += 2) {
crossover(population[parents[i]].code, population[parents[i+1]].code,
newPop[i].code, newPop[i+1].code);
mutate(newPop[i].code);
mutate(newPop[i+1].code);
newPop[i].generation = population[parents[i]].generation + 1;
newPop[i+1].generation = population[parents[i+1]].generation + 1;
newPop[i].mutationCount = population[parents[i]].mutationCount + 1;
newPop[i+1].mutationCount = population[parents[i+1]].mutationCount + 1;
}
// ΠΡΠ΅Π½ΠΈΠ²Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΠΎΠΊΠΎΠ»Π΅Π½ΠΈΠ΅
for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
newPop[i].fitness = calculateFitness(newPop[i].code);
}
// ΠΠ°ΠΌΠ΅Π½ΡΠ΅ΠΌ ΠΏΠΎΠΏΡΠ»ΡΡΠΈΡ
memcpy(population, newPop, sizeof(population));
// ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ Π»ΡΡΡΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ
for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
if (population[i].fitness > bestFitness) {
bestFitness = population[i].fitness;
memcpy(bestProgram, population[i].code, PROGRAM_SIZE);
}
}
}
// Π‘Π°ΠΌΠΎ-ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡ (ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ° ΠΌΠ΅Π½ΡΠ΅Ρ ΡΠ΅Π±Ρ)
void selfModify() {
// ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΡΡΠ°ΡΡΠΎΠΊ ΠΊΠΎΠ΄Π° Π΄Π»Ρ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ
uint16_t pos = random(PROGRAM_SIZE - 10);
uint8_t modification[10];
for (uint8_t i = 0; i < 10; i++) {
modification[i] = random(256);
}
// ΠΡΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅
for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
for (uint8_t j = 0; j < 10; j++) {
population[i].code[pos + j] ^= modification[j];
}
}
}
void setup() {
Serial.begin(115200);
randomSeed(analogRead(A0));
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎΠΏΡΠ»ΡΡΠΈΠΈ
for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
for (uint16_t j = 0; j < PROGRAM_SIZE; j++) {
population[i].code[j] = random(256);
}
population[i].code[PROGRAM_SIZE - 1] = 0xFF; // HALT
population[i].generation = 0;
population[i].mutationCount = 0;
population[i].fitness = calculateFitness(population[i].code);
}
Serial.println("𧬠БΠΠΠΠΠΠ‘ΠΠ ΠΠΠΠΠΠΠ―Π©ΠΠ―Π‘Π― ΠΠ ΠΠΠ ΠΠΠΠ ΠΠΠΠ£Π©ΠΠΠ");
}
void loop() {
// ΠΠ²ΠΎΠ»ΡΡΠΈΡ
evolvePrograms();
// Π‘Π°ΠΌΠΎ-ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡ
if (random(100) < 30) {
selfModify();
Serial.println("π ΠΡΠΎΠ³ΡΠ°ΠΌΠΌΠ° ΠΌΠΎΠ΄ΠΈΡΠΈΡΠΈΡΠΎΠ²Π°Π»Π° ΡΠ΅Π±Ρ");
}
// Π‘ΠΎΡ
ΡΠ°Π½ΡΠ΅ΠΌ Π»ΡΡΡΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ
static uint32_t lastSave = 0;
if (millis() - lastSave > 10000) {
saveProgram(0);
lastSave = millis();
Serial.print("𧬠ΠΠΎΠΊΠΎΠ»Π΅Π½ΠΈΠ΅: ");
Serial.print(population[0].generation);
Serial.print(" | ΠΡΡΡΠ°Ρ ΠΏΡΠΈΡΠΏΠΎΡΠΎΠ±Π»Π΅Π½Π½ΠΎΡΡΡ: ");
Serial.println(bestFitness);
}
// Π‘ΡΠΎΡΠΎΠΆΠ΅Π²ΠΎΠΉ ΡΠ°ΠΉΠΌΠ΅Ρ Π·Π°ΡΠΈΡΠ°Π΅Ρ ΠΎΡ Π·Π°Π²ΠΈΡΠ°Π½ΠΈΡ
wdt_reset();
delay(1000);
}