ΠΡ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠΈΡΡΠ΅ΠΌΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΈΡΠΊΡΠΈΠ²Π»ΡΠ΅Ρ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ-Π²ΡΠ΅ΠΌΡ Π½Π° LED-ΠΌΠ°ΡΡΠΈΡΠ΅, ΡΠΈΠΌΡΠ»ΠΈΡΡΡ Π³ΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½ΡΠ΅ Π»ΠΈΠ½Π·Ρ ΠΈ ΠΈΡΠΊΡΠΈΠ²Π»Π΅Π½ΠΈΠ΅ ΡΠ²Π΅ΡΠ°!
ΠΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½Π°Ρ Π»ΠΈΠ½Π·Π° Π½Π° LED-ΠΌΠ°ΡΡΠΈΡΠ΅:
cpp
#include <avr/pgmspace.h>
#define GRID_SIZE 16
#define LIGHT_RAYS 32
// 2D ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ-Π²ΡΠ΅ΠΌΡ (ΠΈΡΠΊΡΠΈΠ²Π»Π΅Π½ΠΈΠ΅)
int8_t spacetime[GRID_SIZE][GRID_SIZE];
// ΠΠ°ΡΡΠ° (Π³ΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½ΡΠΉ ΠΈΡΡΠΎΡΠ½ΠΈΠΊ)
int8_t massX, massY;
uint8_t massStrength;
// ΠΡΡΠΈ ΡΠ²Π΅ΡΠ° (ΡΠΎΡΠΎΠ½Ρ)
struct LightRay {
int8_t x, y;
int8_t dx, dy;
uint8_t intensity;
};
LightRay rays[LIGHT_RAYS];
// ΠΡΠΊΡΠΈΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²Π°-Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ
void curveSpacetime() {
// ΠΠ΅ΡΡΠΈΠΊΠ° ΠΈΡΠΊΡΠΈΠ²Π»Π΅Π½ΠΈΡ: dsΒ² = -dtΒ² + (1 + 2Ξ¦)drΒ²
for (int8_t x = 0; x < GRID_SIZE; x++) {
for (int8_t y = 0; y < GRID_SIZE; y++) {
int8_t dx = x - massX;
int8_t dy = y - massY;
int16_t dist2 = dx * dx + dy * dy;
if (dist2 < 1) dist2 = 1;
// ΠΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½ΡΠΉ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π» Ξ¦ = -GM/r
int16_t phi = (-massStrength * 100) / dist2;
spacetime[x][y] = phi / 100;
}
}
}
// Π’ΡΠ°ΡΡΠΈΡΠΎΠ²ΠΊΠ° ΡΠ²Π΅ΡΠ° (Π³Π΅ΠΎΠ΄Π΅Π·ΠΈΡΠ΅ΡΠΊΠΈΠ΅)
void traceLightRays() {
for (uint8_t i = 0; i < LIGHT_RAYS; i++) {
LightRay* ray = &rays[i];
// Π‘ΠΈΠ»Π° ΠΈΡΠΊΡΠΈΠ²Π»Π΅Π½ΠΈΡ Π² ΡΠ΅ΠΊΡΡΠ΅ΠΉ ΡΠΎΡΠΊΠ΅
int8_t curvature = spacetime[ray->x][ray->y];
// ΠΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ (ΡΡΡΠ΅ΠΊΡ Π³ΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠΉ Π»ΠΈΠ½Π·Ρ)
int8_t fx = (massX - ray->x) * curvature / 8;
int8_t fy = (massY - ray->y) * curvature / 8;
ray->dx += fx;
ray->dy += fy;
// ΠΠΎΡΠΌΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΡΠΊΠΎΡΠΎΡΡΠΈ ΡΠ²Π΅ΡΠ°
int16_t speed2 = ray->dx * ray->dx + ray->dy * ray->dy;
if (speed2 > 0) {
int16_t speed = sqrt(speed2);
int16_t c = 10; // Π‘ΠΊΠΎΡΠΎΡΡΡ ΡΠ²Π΅ΡΠ°
ray->dx = (ray->dx * c) / speed;
ray->dy = (ray->dy * c) / speed;
}
// ΠΠ΅ΡΠ΅ΠΌΠ΅ΡΠ΅Π½ΠΈΠ΅
ray->x += ray->dx;
ray->y += ray->dy;
// ΠΠ½ΡΠ΅Π½ΡΠΈΠ²Π½ΠΎΡΡΡ (ΠΊΡΠ°ΡΠ½ΠΎΠ΅ ΡΠΌΠ΅ΡΠ΅Π½ΠΈΠ΅)
if (abs(ray->x - massX) < 2 && abs(ray->y - massY) < 2) {
ray->intensity = max(0, ray->intensity - 10); // ΠΠΎΠ³Π»ΠΎΡΠ΅Π½ΠΈΠ΅
}
}
}
// ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π³ΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠΉ Π»ΠΈΠ½Π·Ρ
void renderGravitationalLens() {
clearScreen();
// Π ΠΈΡΡΠ΅ΠΌ ΠΈΡΠΊΡΠΈΠ²Π»Π΅Π½Π½ΠΎΠ΅ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ-Π²ΡΠ΅ΠΌΡ
for (int8_t x = 0; x < GRID_SIZE; x++) {
for (int8_t y = 0; y < GRID_SIZE; y++) {
uint8_t brightness = 64 + spacetime[x][y] * 4;
if (brightness > 255) brightness = 255;
drawPixel(x, y, brightness > 128);
}
}
// Π ΠΈΡΡΠ΅ΠΌ Π»ΡΡΠΈ ΡΠ²Π΅ΡΠ°
for (uint8_t i = 0; i < LIGHT_RAYS; i++) {
LightRay* ray = &rays[i];
if (ray->x >= 0 && ray->x < GRID_SIZE &&
ray->y >= 0 && ray->y < GRID_SIZE) {
drawPixel(ray->x, ray->y, 1);
}
}
// Π ΠΈΡΡΠ΅ΠΌ ΠΌΠ°ΡΡΡ (ΡΠ΅ΡΠ½Π°Ρ Π΄ΡΡΠ°)
drawPixel(massX, massY, 0);
drawPixel(massX + 1, massY, 0);
drawPixel(massX - 1, massY, 0);
drawPixel(massX, massY + 1, 0);
drawPixel(massX, massY - 1, 0);
updateDisplay();
}
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ
void initGravitySimulation() {
// Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΈΡΠΊΡΠΈΠ²Π»Π΅Π½ΠΈΠ΅
massX = GRID_SIZE / 2;
massY = GRID_SIZE / 2;
massStrength = 100;
curveSpacetime();
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΠΌ Π»ΡΡΠΈ ΡΠ²Π΅ΡΠ°
for (uint8_t i = 0; i < LIGHT_RAYS; i++) {
rays[i].x = random(GRID_SIZE);
rays[i].y = 0;
rays[i].dx = random(-2, 3);
rays[i].dy = random(1, 3);
rays[i].intensity = 255;
}
}
void setup() {
initOLED();
initGravitySimulation();
Serial.println("π ΠΠ‘ΠΠ£Π‘Π‘Π’ΠΠΠΠΠΠ― ΠΠ ΠΠΠΠ’ΠΠ¦ΠΠ― ΠΠΠ’ΠΠΠΠ ΠΠΠΠΠ");
}
void loop() {
// ΠΠ±Π½ΠΎΠ²Π»ΡΠ΅ΠΌ Π³ΡΠ°Π²ΠΈΡΠ°ΡΠΈΡ (Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠ°ΡΡΡ)
massX = GRID_SIZE / 2 + sin(millis() / 1000.0) * 3;
massY = GRID_SIZE / 2 + cos(millis() / 1500.0) * 3;
curveSpacetime();
// Π’ΡΠ°ΡΡΠΈΡΡΠ΅ΠΌ Π»ΡΡΠΈ ΡΠ²Π΅ΡΠ°
for (uint8_t step = 0; step < 5; step++) {
traceLightRays();
}
// ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ
renderGravitationalLens();
delay(50);
}