Именно. Экономия времени профи, обучение начинающих. Такие два вектора в интернет-публикациях. Инструмент, а не палочка-выручалочка.
Это шутка?
Да бред это собачий.
Не знаю, по стилю письма на наших не похоже ![]()
Ты ж учитель. Какой толк от того, что ученик спишет ответ? Какое вхрена обучение?!
Блин, вы как с Марса
Они давно уже всё списывают отовсюду…и так для многих было давно.
… А в скетчах с комментариями можно логику рассмотреть, ошибки опять же видны.
Вот это бугагашечка!!! ![]()
Ну вы дети
Почитайте методические труды учителей за 10,20,30,40 лет назад, там всё шаблон и копирка. У нас массовая школа и задачи такие же.
…одна отдушина - ИИ . Говорю жене надо в школах начинать учить пользоваться, ставить это на методический уровень. А она - зачем? Говорю, тут же просто, либо мы его, либо он нас ![]()
во…пишет товарищ
если кто-то это не понимает, уйдёт на свалку истории, других вариантов нет, почти нет
как не остановить бегущего бизона…
Хочу стравить двух аи - чтобы общались друг сдружкой. Никто такого не делал? ![]()
Да, господь с Вами! Одно время ютуб забит был милыми беседами Сири с Алисой “о своём, о девичьем”
Местами было забавно.
Думаю, что автор ошибся, когда оценивал соотношение входа и доводки, как «проблему 70%». По моим наблюениям там действует фундаментальное соотношение, открытая Парето – «20 на 80» (ну, Вы знаете, что «20% людей выпивают 80% пива». Так что, скорее, там «проблема 80%», а не 70.
Хотя, у меня другое отношение в использованию ИИ в программировании, просто я принципиально исхожу из другой концепции и идеи автора мне кажутся наивно-романтическими.
По моему субъективному ощущению “цифры” в этой проблеме постепенно плывут (по мере усложнения объекта рассмотрения), превращая ее в проблему “10 на 90”. А через некоторое время мы уже будем иметь “проблему 1 на 99”.
вот файлы User_Setup.h
#ifndef USER_SETUP_H
#define USER_SETUP_H
// === Настройка дисплея ST7735 ===
#define ST7735_DRIVER
#define TFT_WIDTH 128
#define TFT_HEIGHT 160
#define ST7735_REDTAB160x128 // Для дисплеев с красной платой (128x160)
// Вариант 1: BGR (чаще для ST7735)
//#define TFT_RGB_ORDER TFT_BGR
//#define TFT_INVERSION_ON // Включить инверсию
// Вариант 2: RGB
#define TFT_RGB_ORDER TFT_BGR//RGB
#define TFT_INVERSION_OFF
// === Пины SPI (HSPI) ===
#define TFT_MOSI 13 // GPIO13 (D7)
#define TFT_SCLK 14 // GPIO14 (D5)
#define TFT_CS 15 // GPIO15 (D8) - Chip Select
#define TFT_DC 2 // GPIO2 (D4) - Data/Command
#define TFT_RST 4 // GPIO4 (D2) - Reset (можно подключить к +3.3V, если есть кнопка Reset)
#define TFT_BL 12 // GPIO12 (D6) - Подсветка (PWM)
// === Настройки SPI ===
#define SPI_FREQUENCY 4000000 // Максимум для ST7735
//#define SPI_READ_FREQUENCY 40000000
// === Подсветка ===
#define TFT_BL 12 // Управление подсветкой через PWM
// === Настройки SD-карты (VSPI) ===
#define SD_CS 5 // GPIO5
#define SD_SCLK 18 // GPIO18
#define SD_MOSI 23 // GPIO23
#define SD_MISO 19 // GPIO19
// === Поддержка шрифтов ===
#define LOAD_GLCD // Стандартный шрифт 5x7
#define LOAD_FONT2 // Шрифт 8x16
#define LOAD_FONT4 // Шрифт 16x26
#define LOAD_GFXFF // Гибкие шрифты
#define SMOOTH_FONT // Сглаженные шрифты
// === Поддержка JPEG с SD ===
#define LOAD_JPG
#endif
вот такой дисплей https://aliexpress.ru/item/1005008632929260.html sd карту еще не подключал
вот код шахмат с ии, который не смогу долго тестировать, кстати для шашек мало кода в сети ? на тот случай что бы убедиться что ии сам пишет
#include <TFT_eSPI.h>
#include <EEPROM.h>
TFT_eSPI tft = TFT_eSPI();
#define TFT_BL_PIN 12
#define BOARD_SIZE 8
#define CELL_SIZE 16
#define BOARD_OFFSET_X 0
#define BOARD_OFFSET_Y 0
#define DARK_SQUARE tft.color565(0, 100, 0)
#define LIGHT_SQUARE TFT_LIGHTGREY
#define CURSOR_COLOR TFT_YELLOW
#define PLAYER1_COLOR TFT_RED
#define PLAYER2_COLOR TFT_WHITE
#define PLAYER1_KING TFT_ORANGE
#define PLAYER2_KING TFT_CYAN
#define MODE_PVP 1
#define MODE_PVAI1 2
#define MODE_PVAI2 3
#define MODE_AIVAI 4
#define MODE_TOURNAMENT 5
#define AI_MOVE_DELAY 1000
#define GENOME_SIZE 8
#define POPULATION_SIZE 10
#define EEPROM_SIZE 512
#define MUTATION_RATE 0.15
struct Genome {
float weights[GENOME_SIZE];
int fitness;
int games_played;
int wins;
};
struct EEPROMData {
uint32_t signature;
Genome ai1;
Genome ai2;
uint32_t total_games;
uint32_t ai1_wins;
uint32_t ai2_wins;
uint32_t draws;
uint32_t generation;
};
int board[BOARD_SIZE][BOARD_SIZE] = {0};
int cursorX = 0, cursorY = 0;
int selectedX = -1, selectedY = -1;
bool player1Turn = true;
bool gameRunning = true;
bool pieceLifted = false;
bool mustCapture = false;
int lastCaptureX = -1, lastCaptureY = -1;
int gameMode = MODE_PVP;
bool aiThinking = false;
unsigned long aiMoveStartTime = 0;
EEPROMData eepromData;
Genome population[POPULATION_SIZE];
int currentGeneration = 0;
#define W_MATERIAL 0
#define W_KING_VALUE 1
#define W_MOBILITY 2
#define W_CENTER 3
#define W_BACK_RANK 4
#define W_AGGRESSION 5
#define W_DEFENSE 6
#define W_POSITION 7
// Прототипы функций
void restartGame();
void initializeBoard();
void drawBoard();
void drawCursor();
void handleCommand(char command);
void handleSelection();
bool isValidMove(int fromX, int fromY, int toX, int toY, int &captureCount);
bool isEnemy(int checker1, int checker2);
bool hasForcedCapture(int x, int y);
bool hasAnyForcedCaptures();
void checkForcedCaptures();
bool canContinueCapture(int x, int y);
bool isValidPosition(int x, int y);
void makeMove(int fromX, int fromY, int toX, int toY);
int max(int a, int b);
bool isKing(int checker);
void checkGameOver();
bool canCheckerMove(int x, int y);
void showGameOver(const char* message);
void makeAIMove(int player);
void executeBestAIMove();
void makeRealMove(int fromX, int fromY, int toX, int toY);
float evaluatePosition(Genome* ai);
int countMobility(int player);
float evaluateCenterControl(int player1, int player2);
void evolveAI();
void eliteCrossover(Genome* winner, Genome* loser);
void knowledgeTransfer(Genome* winner, Genome* loser);
void replaceLoser(Genome* winner, Genome* loser);
void loadEEPROMData();
void initializeEEPROMData();
void initializeGenome(Genome* genome);
void saveEEPROMData();
void initializeAI();
void drawCell(int x, int y);
void drawChecker(int x, int y, int type);
void drawCursorRect(int x, int y, uint16_t color);
void drawAIStats();
void setup() {
Serial.begin(115200);
delay(2000);
EEPROM.begin(EEPROM_SIZE);
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_BLACK);
pinMode(TFT_BL_PIN, OUTPUT);
digitalWrite(TFT_BL_PIN, HIGH);
loadEEPROMData();
initializeAI();
Serial.println("READY");
}
void loop() {
if (Serial.available() > 0) {
char command = Serial.read();
while(Serial.available() > 0) Serial.read();
if (command >= '1' && command <= '5') {
gameMode = command - '0';
Serial.print("MODE:");
Serial.println(gameMode);
restartGame();
} else {
handleCommand(command);
}
}
if ((gameMode == MODE_AIVAI || gameMode == MODE_TOURNAMENT) && !gameRunning) {
delay(1000);
evolveAI();
restartGame();
return;
}
if ((gameMode == MODE_AIVAI || gameMode == MODE_TOURNAMENT) && gameRunning && !aiThinking) {
if (player1Turn) {
makeAIMove(1);
} else {
makeAIMove(2);
}
}
if (gameRunning && !player1Turn && !aiThinking) {
if ((gameMode == MODE_PVAI1 && !player1Turn) ||
(gameMode == MODE_PVAI2 && !player1Turn)) {
makeAIMove(2);
}
}
if (gameRunning && player1Turn && !aiThinking) {
if ((gameMode == MODE_PVAI1 && player1Turn) ||
(gameMode == MODE_PVAI2 && player1Turn)) {
makeAIMove(1);
}
}
if (aiThinking && millis() - aiMoveStartTime > AI_MOVE_DELAY) {
executeBestAIMove();
}
delay(10);
}
void restartGame() {
cursorX = 0;
cursorY = 0;
selectedX = -1;
selectedY = -1;
player1Turn = true;
gameRunning = true;
pieceLifted = false;
mustCapture = false;
lastCaptureX = -1;
lastCaptureY = -1;
initializeBoard();
checkForcedCaptures();
drawBoard();
drawCursor();
}
void evolveAI() {
eepromData.generation++;
float ai1_win_rate = (eepromData.ai1.games_played > 0) ?
(float)eepromData.ai1.wins / eepromData.ai1.games_played : 0;
float ai2_win_rate = (eepromData.ai2.games_played > 0) ?
(float)eepromData.ai2.wins / eepromData.ai2.games_played : 0;
eepromData.ai1.fitness = ai1_win_rate * 100 + eepromData.draws;
eepromData.ai2.fitness = ai2_win_rate * 100 + eepromData.draws;
Genome* winner = (eepromData.ai1.fitness >= eepromData.ai2.fitness) ? &eepromData.ai1 : &eepromData.ai2;
Genome* loser = (eepromData.ai1.fitness < eepromData.ai2.fitness) ? &eepromData.ai1 : &eepromData.ai2;
Serial.print("Generation: ");
Serial.println(eepromData.generation);
Serial.print("AI1 wins: ");
Serial.print(eepromData.ai1.wins);
Serial.print("/");
Serial.print(eepromData.ai1.games_played);
Serial.print(" (");
Serial.print(ai1_win_rate * 100);
Serial.print("%)");
Serial.print(" AI2 wins: ");
Serial.print(eepromData.ai2.wins);
Serial.print("/");
Serial.print(eepromData.ai2.games_played);
Serial.print(" (");
Serial.print(ai2_win_rate * 100);
Serial.println("%)");
float fitness_diff = abs(eepromData.ai1.fitness - eepromData.ai2.fitness);
if (fitness_diff < 10) {
Serial.println("Strategy: Elite crossover");
eliteCrossover(winner, loser);
} else if (fitness_diff < 30) {
Serial.println("Strategy: Knowledge transfer");
knowledgeTransfer(winner, loser);
} else {
Serial.println("Strategy: Winner clones");
replaceLoser(winner, loser);
}
eepromData.ai1.wins = 0;
eepromData.ai2.wins = 0;
eepromData.ai1.games_played = 0;
eepromData.ai2.games_played = 0;
eepromData.ai1.fitness = 0;
eepromData.ai2.fitness = 0;
saveEEPROMData();
Serial.println("AI evolved successfully!");
}
void eliteCrossover(Genome* winner, Genome* loser) {
for (int i = 0; i < GENOME_SIZE; i++) {
if (random(100) < 70) {
loser->weights[i] = winner->weights[i];
} else {
loser->weights[i] = (winner->weights[i] + loser->weights[i]) / 2.0;
}
if (random(100) < MUTATION_RATE * 100) {
float mutation = (random(200) - 100) / 200.0;
loser->weights[i] += mutation;
loser->weights[i] = constrain(loser->weights[i], 0.1, 2.0);
}
}
}
void knowledgeTransfer(Genome* winner, Genome* loser) {
for (int i = 0; i < GENOME_SIZE; i++) {
float transfer_rate = 0.3 + (random(70) / 100.0);
loser->weights[i] = winner->weights[i] * transfer_rate + loser->weights[i] * (1 - transfer_rate);
if (random(100) < MUTATION_RATE * 100) {
float mutation = (random(150) - 75) / 150.0;
loser->weights[i] += mutation;
loser->weights[i] = constrain(loser->weights[i], 0.1, 2.0);
}
}
}
void replaceLoser(Genome* winner, Genome* loser) {
for (int i = 0; i < GENOME_SIZE; i++) {
loser->weights[i] = winner->weights[i];
if (random(100) < MUTATION_RATE * 100 * 2) {
float mutation = (random(200) - 100) / 100.0;
loser->weights[i] += mutation;
loser->weights[i] = constrain(loser->weights[i], 0.1, 2.0);
}
}
}
void loadEEPROMData() {
EEPROM.get(0, eepromData);
if (eepromData.signature != 0xDEADBEEF) {
initializeEEPROMData();
}
Serial.println("EEPROM loaded:");
Serial.print("Total games: "); Serial.println(eepromData.total_games);
Serial.print("AI1 wins: "); Serial.println(eepromData.ai1_wins);
Serial.print("AI2 wins: "); Serial.println(eepromData.ai2_wins);
Serial.print("Draws: "); Serial.println(eepromData.draws);
Serial.print("Generation: "); Serial.println(eepromData.generation);
}
void initializeEEPROMData() {
eepromData.signature = 0xDEADBEEF;
eepromData.total_games = 0;
eepromData.ai1_wins = 0;
eepromData.ai2_wins = 0;
eepromData.draws = 0;
eepromData.generation = 0;
randomSeed(analogRead(0));
initializeGenome(&eepromData.ai1);
initializeGenome(&eepromData.ai2);
saveEEPROMData();
}
void initializeGenome(Genome* genome) {
for (int i = 0; i < GENOME_SIZE; i++) {
genome->weights[i] = random(100) / 100.0 + 0.5;
}
genome->fitness = 0;
genome->games_played = 0;
genome->wins = 0;
}
void saveEEPROMData() {
EEPROM.put(0, eepromData);
EEPROM.commit();
}
void initializeAI() {
for (int i = 0; i < POPULATION_SIZE; i++) {
if (i == 0) {
population[i] = eepromData.ai1;
} else if (i == 1) {
population[i] = eepromData.ai2;
} else {
initializeGenome(&population[i]);
}
}
}
void makeAIMove(int player) {
aiThinking = true;
aiMoveStartTime = millis();
if (gameMode == MODE_TOURNAMENT) {
executeBestAIMove();
}
}
void executeBestAIMove() {
if (!aiThinking) return;
int currentPlayer = player1Turn ? 1 : 2;
Genome* currentAI = player1Turn ? &eepromData.ai1 : &eepromData.ai2;
bool hasForced = hasAnyForcedCaptures();
int bestFromX = -1, bestFromY = -1, bestToX = -1, bestToY = -1;
float bestScore = -10000;
int bestMovesCount = 0;
int bestMoves[50][4];
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
int checker = board[y][x];
if (checker != 0 && ((currentPlayer == 1 && (checker == 1 || checker == 3)) ||
(currentPlayer == 2 && (checker == 2 || checker == 4)))) {
if (hasForced && !hasForcedCapture(x, y)) {
continue;
}
for (int toY = 0; toY < BOARD_SIZE; toY++) {
for (int toX = 0; toX < BOARD_SIZE; toX++) {
int captureCount = 0;
if (isValidMove(x, y, toX, toY, captureCount)) {
int tempBoard[BOARD_SIZE][BOARD_SIZE];
memcpy(tempBoard, board, sizeof(board));
makeRealMove(x, y, toX, toY);
float score = evaluatePosition(currentAI);
score += (random(100) - 50) / 200.0;
score += captureCount * currentAI->weights[W_AGGRESSION] * 5;
if (!isKing(checker) && ((checker == 1 && toY == 0) || (checker == 2 && toY == BOARD_SIZE - 1))) {
score += currentAI->weights[W_KING_VALUE] * 3;
}
memcpy(board, tempBoard, sizeof(board));
if (score >= bestScore - 0.5) {
if (score > bestScore + 0.5) {
bestScore = score;
bestMovesCount = 0;
}
if (bestMovesCount < 50) {
bestMoves[bestMovesCount][0] = x;
bestMoves[bestMovesCount][1] = y;
bestMoves[bestMovesCount][2] = toX;
bestMoves[bestMovesCount][3] = toY;
bestMovesCount++;
}
}
}
}
}
}
}
}
if (bestMovesCount > 0) {
int chosenMove = random(bestMovesCount);
bestFromX = bestMoves[chosenMove][0];
bestFromY = bestMoves[chosenMove][1];
bestToX = bestMoves[chosenMove][2];
bestToY = bestMoves[chosenMove][3];
}
if (bestFromX != -1) {
int captureCount = 0;
if (isValidMove(bestFromX, bestFromY, bestToX, bestToY, captureCount)) {
makeMove(bestFromX, bestFromY, bestToX, bestToY);
if (captureCount > 0 && canContinueCapture(bestToX, bestToY)) {
mustCapture = true;
lastCaptureX = bestToX;
lastCaptureY = bestToY;
selectedX = bestToX;
selectedY = bestToY;
pieceLifted = true;
} else {
pieceLifted = false;
selectedX = -1;
selectedY = -1;
mustCapture = false;
lastCaptureX = -1;
lastCaptureY = -1;
player1Turn = !player1Turn;
checkGameOver();
}
}
} else {
player1Turn = !player1Turn;
checkGameOver();
}
aiThinking = false;
drawBoard();
drawCursor();
}
void makeRealMove(int fromX, int fromY, int toX, int toY) {
int checker = board[fromY][fromX];
board[fromY][fromX] = 0;
board[toY][toX] = checker;
if (!isKing(checker)) {
if ((checker == 1 && toY == 0) || (checker == 2 && toY == BOARD_SIZE - 1)) {
board[toY][toX] = checker + 2;
}
}
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (abs(deltaX) > 1 || abs(deltaY) > 1) {
if (abs(deltaX) == 2 && abs(deltaY) == 2) {
board[fromY + deltaY/2][fromX + deltaX/2] = 0;
} else {
int stepX = (deltaX > 0) ? 1 : -1;
int stepY = (deltaY > 0) ? 1 : -1;
int steps = max(abs(deltaX), abs(deltaY));
for (int i = 1; i < steps; i++) {
int checkX = fromX + i * stepX;
int checkY = fromY + i * stepY;
if (isValidPosition(checkX, checkY) && board[checkY][checkX] != 0) {
if (isEnemy(checker, board[checkY][checkX])) {
board[checkY][checkX] = 0;
}
}
}
}
}
}
float evaluatePosition(Genome* ai) {
float score = 0;
int material1 = 0, material2 = 0;
int kings1 = 0, kings2 = 0;
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
int checker = board[y][x];
if (checker == 1) { material1 += 1; }
else if (checker == 2) { material2 += 1; }
else if (checker == 3) { material1 += 2; kings1++; }
else if (checker == 4) { material2 += 2; kings2++; }
}
}
score += (material1 - material2) * ai->weights[W_MATERIAL];
score += (kings1 - kings2) * ai->weights[W_KING_VALUE];
int mobility1 = countMobility(1);
int mobility2 = countMobility(2);
score += (mobility1 - mobility2) * ai->weights[W_MOBILITY];
score += evaluateCenterControl(1, 2) * ai->weights[W_CENTER];
return score;
}
int countMobility(int player) {
int mobility = 0;
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
int checker = board[y][x];
if ((player == 1 && (checker == 1 || checker == 3)) ||
(player == 2 && (checker == 2 || checker == 4))) {
mobility += 2;
}
}
}
return mobility;
}
float evaluateCenterControl(int player1, int player2) {
int control1 = 0, control2 = 0;
for (int y = 2; y <= 5; y++) {
for (int x = 2; x <= 5; x++) {
int checker = board[y][x];
if (checker == 1 || checker == 3) control1++;
else if (checker == 2 || checker == 4) control2++;
}
}
return control1 - control2;
}
void initializeBoard() {
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
board[y][x] = 0;
}
}
for (int y = 0; y < 3; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
if ((x + y) % 2 == 1) {
board[y][x] = 2;
}
}
}
for (int y = 5; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
if ((x + y) % 2 == 1) {
board[y][x] = 1;
}
}
}
}
void drawBoard() {
tft.fillScreen(TFT_BLACK);
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
drawCell(x, y);
}
}
if (gameMode == MODE_AIVAI || gameMode == MODE_TOURNAMENT) {
drawAIStats();
}
}
void drawCell(int x, int y) {
int color = ((x + y) % 2 == 0) ? LIGHT_SQUARE : DARK_SQUARE;
tft.fillRect(BOARD_OFFSET_X + x * CELL_SIZE,
BOARD_OFFSET_Y + y * CELL_SIZE,
CELL_SIZE, CELL_SIZE, color);
if (board[y][x] != 0) {
drawChecker(x, y, board[y][x]);
}
}
void drawChecker(int x, int y, int type) {
int screenX = BOARD_OFFSET_X + x * CELL_SIZE;
int screenY = BOARD_OFFSET_Y + y * CELL_SIZE;
int radius = CELL_SIZE / 2 - 2;
int centerX = screenX + CELL_SIZE / 2;
int centerY = screenY + CELL_SIZE / 2;
int color;
bool isKing = false;
switch(type) {
case 1: color = PLAYER1_COLOR; break;
case 2: color = PLAYER2_COLOR; break;
case 3: color = PLAYER1_KING; isKing = true; break;
case 4: color = PLAYER2_KING; isKing = true; break;
default: return;
}
tft.fillCircle(centerX, centerY, radius, color);
tft.drawCircle(centerX, centerY, radius, TFT_BLACK);
if (isKing) {
tft.fillCircle(centerX, centerY, radius/2, TFT_YELLOW);
tft.drawCircle(centerX, centerY, radius/2, TFT_BLACK);
}
}
void drawCursor() {
if (selectedX != -1 && selectedY != -1) {
drawCell(selectedX, selectedY);
}
static int lastCursorX = -1, lastCursorY = -1;
if (lastCursorX != -1 && lastCursorY != -1) {
if (!(lastCursorX == selectedX && lastCursorY == selectedY)) {
drawCell(lastCursorX, lastCursorY);
}
}
drawCursorRect(cursorX, cursorY, pieceLifted ? TFT_MAGENTA : CURSOR_COLOR);
if (selectedX != -1 && selectedY != -1) {
drawCursorRect(selectedX, selectedY, TFT_BLUE);
}
lastCursorX = cursorX;
lastCursorY = cursorY;
}
void drawCursorRect(int x, int y, uint16_t color) {
int screenX = BOARD_OFFSET_X + x * CELL_SIZE;
int screenY = BOARD_OFFSET_Y + y * CELL_SIZE;
tft.drawRect(screenX, screenY, CELL_SIZE, CELL_SIZE, color);
tft.drawRect(screenX+1, screenY+1, CELL_SIZE-2, CELL_SIZE-2, color);
}
void drawAIStats() {
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextSize(1);
String stats = "G:" + String(eepromData.total_games) +
" W1:" + String(eepromData.ai1_wins) +
" W2:" + String(eepromData.ai2_wins) +
" Gen:" + String(eepromData.generation);
tft.setCursor(0, 130);
tft.print(stats);
if (aiThinking) {
int progress = (millis() - aiMoveStartTime) * 100 / AI_MOVE_DELAY;
tft.setCursor(0, 140);
tft.print("AI thinking: ");
tft.print(progress);
tft.print("%");
}
}
void handleCommand(char command) {
int oldX = cursorX, oldY = cursorY;
switch(command) {
case 'w': if (cursorY > 0) cursorY--; break;
case 's': if (cursorY < BOARD_SIZE - 1) cursorY++; break;
case 'a': if (cursorX > 0) cursorX--; break;
case 'd': if (cursorX < BOARD_SIZE - 1) cursorX++; break;
case 'q': handleSelection(); break;
case 'r':
restartGame();
Serial.println("RESTART");
return;
default: return;
}
if (oldX != cursorX || oldY != cursorY) {
drawCursor();
Serial.print("POS:");
Serial.print(cursorX);
Serial.print(",");
Serial.println(cursorY);
}
}
void handleSelection() {
if (!gameRunning) {
Serial.println("GAME_OVER");
return;
}
if (mustCapture && pieceLifted && (selectedX != lastCaptureX || selectedY != lastCaptureY)) {
Serial.println("MUST_CONTINUE_CAPTURE");
return;
}
if (pieceLifted) {
if (cursorX == selectedX && cursorY == selectedY) {
pieceLifted = false;
selectedX = -1;
selectedY = -1;
drawCursor();
Serial.println("CANCEL");
} else {
int captureCount = 0;
if (isValidMove(selectedX, selectedY, cursorX, cursorY, captureCount)) {
makeMove(selectedX, selectedY, cursorX, cursorY);
if (captureCount > 0 && canContinueCapture(cursorX, cursorY)) {
mustCapture = true;
lastCaptureX = cursorX;
lastCaptureY = cursorY;
selectedX = cursorX;
selectedY = cursorY;
pieceLifted = true;
Serial.println("CONTINUE_CAPTURE");
} else {
pieceLifted = false;
selectedX = -1;
selectedY = -1;
mustCapture = false;
lastCaptureX = -1;
lastCaptureY = -1;
player1Turn = !player1Turn;
checkForcedCaptures();
checkGameOver();
Serial.println("MOVE_OK");
}
} else {
Serial.println("INVALID_MOVE");
}
}
} else {
if (mustCapture) {
Serial.println("MUST_CAPTURE");
return;
}
int checker = board[cursorY][cursorX];
if (checker != 0) {
bool isPlayer1 = (checker == 1 || checker == 3);
if ((player1Turn && isPlayer1) || (!player1Turn && !isPlayer1)) {
if (hasForcedCapture(cursorX, cursorY)) {
selectedX = cursorX;
selectedY = cursorY;
pieceLifted = true;
drawCursor();
Serial.println("PIECE_UP_CAPTURE");
} else if (!hasAnyForcedCaptures()) {
selectedX = cursorX;
selectedY = cursorY;
pieceLifted = true;
drawCursor();
Serial.println("PIECE_UP");
} else {
Serial.println("MUST_CAPTURE_OTHER");
}
} else {
Serial.println("WRONG_PLAYER");
}
} else {
Serial.println("NO_PIECE");
}
}
}
bool isValidMove(int fromX, int fromY, int toX, int toY, int &captureCount) {
if (board[toY][toX] != 0) return false;
if ((toX + toY) % 2 == 0) return false;
int checker = board[fromY][fromX];
bool isKing = (checker == 3 || checker == 4);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
captureCount = 0;
if (mustCapture && (fromX != lastCaptureX || fromY != lastCaptureY)) {
return false;
}
if (hasAnyForcedCaptures() && !hasForcedCapture(fromX, fromY)) {
return false;
}
if (!isKing) {
if (abs(deltaX) == 1 && abs(deltaY) == 1) {
if (!hasAnyForcedCaptures()) {
if ((checker == 1 && deltaY == -1) || (checker == 2 && deltaY == 1)) {
return true;
}
}
return false;
}
if (abs(deltaX) == 2 && abs(deltaY) == 2) {
int midX = fromX + deltaX / 2;
int midY = fromY + deltaY / 2;
int midChecker = board[midY][midX];
if (midChecker != 0 && isEnemy(checker, midChecker)) {
captureCount = 1;
return true;
}
}
} else {
if (abs(deltaX) == abs(deltaY)) {
int stepX = (deltaX > 0) ? 1 : -1;
int stepY = (deltaY > 0) ? 1 : -1;
int captured = 0;
for (int i = 1; i < abs(deltaX); i++) {
int checkX = fromX + i * stepX;
int checkY = fromY + i * stepY;
int cell = board[checkY][checkX];
if (cell != 0) {
if (isEnemy(checker, cell)) {
if (captured > 0) return false;
captured++;
} else {
return false;
}
}
}
captureCount = captured;
if (captured == 0 && !hasAnyForcedCaptures()) {
return true;
}
return captured > 0;
}
}
return false;
}
bool isEnemy(int checker1, int checker2) {
if (checker1 == 0 || checker2 == 0) return false;
bool isChecker1Player1 = (checker1 == 1 || checker1 == 3);
bool isChecker2Player1 = (checker2 == 1 || checker2 == 3);
return isChecker1Player1 != isChecker2Player1;
}
bool hasForcedCapture(int x, int y) {
int checker = board[y][x];
if (checker == 0) return false;
bool isKing = (checker == 3 || checker == 4);
int directions[4][2] = {{1,1}, {1,-1}, {-1,1}, {-1,-1}};
for (int i = 0; i < 4; i++) {
int dx = directions[i][0];
int dy = directions[i][1];
if (!isKing) {
int captureX = x + dx;
int captureY = y + dy;
int landingX = x + 2*dx;
int landingY = y + 2*dy;
if (isValidPosition(captureX, captureY) && isValidPosition(landingX, landingY)) {
if (isEnemy(checker, board[captureY][captureX]) && board[landingY][landingX] == 0) {
return true;
}
}
} else {
for (int dist = 1; dist < BOARD_SIZE; dist++) {
int checkX = x + dist * dx;
int checkY = y + dist * dy;
if (!isValidPosition(checkX, checkY)) break;
if (board[checkY][checkX] != 0) {
if (isEnemy(checker, board[checkY][checkX])) {
int behindX = checkX + dx;
int behindY = checkY + dy;
if (isValidPosition(behindX, behindY) && board[behindY][behindX] == 0) {
bool clearPath = true;
for (int j = 1; j < dist; j++) {
int betweenX = x + j * dx;
int betweenY = y + j * dy;
if (board[betweenY][betweenX] != 0) {
clearPath = false;
break;
}
}
if (clearPath) return true;
}
}
break;
}
}
}
}
return false;
}
bool hasAnyForcedCaptures() {
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
int checker = board[y][x];
if (checker != 0) {
bool isPlayer1 = (checker == 1 || checker == 3);
if ((player1Turn && isPlayer1) || (!player1Turn && !isPlayer1)) {
if (hasForcedCapture(x, y)) {
return true;
}
}
}
}
}
return false;
}
void checkForcedCaptures() {
if (hasAnyForcedCaptures()) {
Serial.println("FORCED_CAPTURE_AVAILABLE");
}
}
bool canContinueCapture(int x, int y) {
return hasForcedCapture(x, y);
}
bool isValidPosition(int x, int y) {
return x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE;
}
void makeMove(int fromX, int fromY, int toX, int toY) {
int checker = board[fromY][fromX];
board[fromY][fromX] = 0;
board[toY][toX] = checker;
if (!isKing(checker)) {
if ((checker == 1 && toY == 0) || (checker == 2 && toY == BOARD_SIZE - 1)) {
board[toY][toX] = checker + 2;
if (mustCapture) {
mustCapture = canContinueCapture(toX, toY);
}
}
}
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (abs(deltaX) > 1 || abs(deltaY) > 1) {
if (abs(deltaX) == 2 && abs(deltaY) == 2) {
board[fromY + deltaY/2][fromX + deltaX/2] = 0;
} else {
int stepX = (deltaX > 0) ? 1 : -1;
int stepY = (deltaY > 0) ? 1 : -1;
for (int i = 1; i < abs(deltaX); i++) {
int checkX = fromX + i * stepX;
int checkY = fromY + i * stepY;
if (isValidPosition(checkX, checkY) && board[checkY][checkX] != 0) {
board[checkY][checkX] = 0;
break;
}
}
}
}
drawCell(fromX, fromY);
drawCell(toX, toY);
delay(50);
}
int max(int a, int b) {
return (a > b) ? a : b;
}
bool isKing(int checker) {
return (checker == 3 || checker == 4);
}
void checkGameOver() {
int player1Count = 0, player2Count = 0;
bool player1CanMove = false;
bool player2CanMove = false;
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
int checker = board[y][x];
if (checker == 1 || checker == 3) {
player1Count++;
if (!player1CanMove) {
player1CanMove = canCheckerMove(x, y);
}
} else if (checker == 2 || checker == 4) {
player2Count++;
if (!player2CanMove) {
player2CanMove = canCheckerMove(x, y);
}
}
}
}
if (player1Count == 0 || (player1Turn && !player1CanMove)) {
gameRunning = false;
showGameOver("PLAYER 2 WINS");
Serial.println("PLAYER2_WINS");
} else if (player2Count == 0 || (!player1Turn && !player2CanMove)) {
gameRunning = false;
showGameOver("PLAYER 1 WINS");
Serial.println("PLAYER1_WINS");
} else if (!player1CanMove && !player2CanMove) {
gameRunning = false;
showGameOver("DRAW - NO MOVES");
Serial.println("DRAW");
}
if (!gameRunning && (gameMode == MODE_AIVAI || gameMode == MODE_TOURNAMENT)) {
eepromData.total_games++;
int p1Count = 0, p2Count = 0;
for (int y = 0; y < BOARD_SIZE; y++) {
for (int x = 0; x < BOARD_SIZE; x++) {
if (board[y][x] == 1 || board[y][x] == 3) p1Count++;
if (board[y][x] == 2 || board[y][x] == 4) p2Count++;
}
}
if (p1Count == 0) {
eepromData.ai2_wins++;
eepromData.ai2.wins++;
} else if (p2Count == 0) {
eepromData.ai1_wins++;
eepromData.ai1.wins++;
} else {
eepromData.draws++;
}
eepromData.ai1.games_played++;
eepromData.ai2.games_played++;
saveEEPROMData();
}
}
bool canCheckerMove(int x, int y) {
int checker = board[y][x];
if (checker == 0) return false;
bool isKing = (checker == 3 || checker == 4);
int directions[4][2] = {{1,1}, {1,-1}, {-1,1}, {-1,-1}};
for (int i = 0; i < 4; i++) {
int dx = directions[i][0];
int dy = directions[i][1];
int newX = x + dx;
int newY = y + dy;
if (isValidPosition(newX, newY) && board[newY][newX] == 0) {
if (!isKing) {
if ((checker == 1 && dy == -1) || (checker == 2 && dy == 1)) {
return true;
}
} else {
return true;
}
}
if (!isKing) {
newX = x + 2*dx;
newY = y + 2*dy;
if (isValidPosition(newX, newY) && board[newY][newX] == 0) {
int midX = x + dx;
int midY = y + dy;
if (isValidPosition(midX, midY) && isEnemy(checker, board[midY][midX])) {
return true;
}
}
} else {
for (int dist = 1; dist < BOARD_SIZE; dist++) {
int checkX = x + dist * dx;
int checkY = y + dist * dy;
if (!isValidPosition(checkX, checkY)) break;
if (board[checkY][checkX] != 0) {
if (isEnemy(checker, board[checkY][checkX])) {
int behindX = checkX + dx;
int behindY = checkY + dy;
if (isValidPosition(behindX, behindY) && board[behindY][behindX] == 0) {
bool clearPath = true;
for (int j = 1; j < dist; j++) {
int betweenX = x + j * dx;
int betweenY = y + j * dy;
if (board[betweenY][betweenX] != 0) {
clearPath = false;
break;
}
}
if (clearPath) return true;
}
}
break;
}
}
}
}
return false;
}
void showGameOver(const char* message) {
for (int i = 0; i < 5; i++) {
tft.fillRect(10, 70, 108, 20, TFT_BLACK);
delay(100);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextSize(1);
tft.setCursor(15, 72);
tft.print(message);
delay(100);
}
}
вот программа управления, для игры и выбора режима, протестировал 2 режима, ии ии, игрок игрок https://ru.files.me/u/kvpkr98h4x
писал универсальный ии дип сик))), к которому имеет смысл обращаться если есть какие то знания,(сначало обучение, а потом написание через ии!) а не просто так)) прошел ли он тест или нет не знаю, а то кажется у меня через 3 дня времени не будет, кто захочет сможет взять за основу, или просто потестировать… при нахождении багов, и сообщением ему что не так, еще за 20-30 запросов думаю сможет сделать
почему шутка ? он много весит… не помещается в уно, если я код не перепутал…
выглядит все так https://ru.files.me/u/apaha7smjt через месяц можно наверное тестировать обучился он или нет)))
но кажется после нескольких прогонов алгоритм пока что один и тот же, ходы повторяются, может позже это изменится…
И где тут “горькая правда”? В том, что ИИ это не волшебная кнопка, которая “р-р-раз!” и выдаст вам готовый проект? А что, кто-то ожидал? :)))
Я сейчас постоянно пишу код на пару с ИИ. Моя схема использования - ИИ как продвинутый вариант Гугля. Я спрашиваю у него примеры использования той или иной конструкции, которую знаю, но не помню синтаксис. А потом заполняю шаблон своим кодом. Это ускоряет работу.
Чего у меня не получается пока - это заставить ИИ рефакторить мой код. Или хотя бы давать какие-то разумные советы. Я думаю, что тут главная проблема - мой код слабо структурирован, или скорее, мало инкапсулирован… не уверен что применяю слово правильно. Короче, у меня проблема что в большом коде отдельные блоки слабо разделены друг от друга… поэтому их невозможно рефакторить по отдельности.
Как итог - когда я прошу ИИ отрефакторитькакой-то блок, каждый раз оказывается, что его меры ломают взаимодействие с соседними участками кода и весь выхлоп ИИ оказывается бесполезен
А ты в какой среде все это делаешь? Я пользуюсь VS Code с обычным ГитХаб ко-пилот. Он у меня угадывает даже мой стиль нейминга переменных.
Иногда пишет не то, что я задумал, но чаще всего мы “на одной волне”! Я думаю - вот напишу как я тут проверку, перед основной работой. пишу: “if(“ и этот гад мне не дает даже продолжить - за меня дописывает именно то, о чем я думал.
мне кажется, что они мысли читают!
А про рефакторинг, смотри как можно: написал свич с перечислением меток, как “в голове”, типа “case 3,14,15,92,6:” …и так далее, выделил, нажал контрол-i и в промпте пишешь - поправь, как надо…. именно так, без ложной вежливости! - и он аккуратно все исправит.
Или работаешь в функции с параметрами- указателями на объекты. Выделил кусок, контрол-i в промпте написал: “добавть проверки на null где надо, оставь мне место написать обработку исключений”…
ВОт как-то так надо… сорри - можно.
стравил код от AI с дипсиком, последний обосрал код на 180 строк и, с пяти пинков написал компилирующийся код на 460 строк, даже кнопка со второго пинка ему заработала, а всего пять пинков пришлось дать. чтобы скомпилировался, осциллограмма правильная однако
