It's challenging for QwQ to generate long codes...

#38
by DXBTR74 - opened

Build a Sudoku game with Arduino, I have an Arduino Uno (2 KB of SRAM, 1 KB of EEPROM, and 32 KB of flash) board, an OLED module with a resolution of 12864, a joystick, a bunch of wires and buttons, a buzzer, and a bread board. The game is a random generation of Sudoku problems using a backtracking algorithm, and ENSURE every puzzle is correct. The each cell of sudoku should be a square of 77 pixels (line included). Please give me the complete code.

Tested models: GPT-4o, DeepSeek-R1, DeepSeek-R1-distill-Llama-70B, DeepSeek-R1-distill-Qwen-32B, GPT-o3-mini, QwQ-32B
Parameters: Temperature=0.6, TopP=0.95,

Response (thinking process not incl.):
DeepSeek-R1:

Here's the complete Arduino code for the Sudoku game based on your specifications. This code includes Sudoku generation, display, input handling, and sound feedback:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Joystick pins
#define JOYSTICK_X_PIN A0
#define JOYSTICK_Y_PIN A1
#define JOYSTICK_BTN_PIN 2

// Buzzer pin
#define BUZZER_PIN 3

byte solutionGrid[9][9];
byte puzzleGrid[9][9];
bool fixedCells[9][9];

int currentRow = 0;
int currentCol = 0;
unsigned long lastInputTime = 0;

struct Cell { int row; int col; };

void setup() {
  Serial.begin(9600);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);

  pinMode(JOYSTICK_BTN_PIN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
  randomSeed(analogRead(A4));

  generateSudoku();
  createPuzzle(45);
  drawGrid();
}

void loop() {
  handleInput();
}

void generateSudoku() {
  memset(solutionGrid, 0, sizeof(solutionGrid));
  Cell stack[81];
  int stackPtr = 0;
  stack[stackPtr++] = {0, 0};

  while (stackPtr > 0) {
    Cell current = stack[stackPtr-1];
    if (current.row >= 9) break;

    int nums[] = {1,2,3,4,5,6,7,8,9};
    shuffle(nums, 9);
    bool found = false;

    for (int i = 0; i < 9; i++) {
      if (isValid(current.row, current.col, nums[i])) {
        solutionGrid[current.row][current.col] = nums[i];
        Cell next;
        if (current.col == 8) {
          next.row = current.row + 1;
          next.col = 0;
        } else {
          next.row = current.row;
          next.col = current.col + 1;
        }
        if (stackPtr < 81) stack[stackPtr++] = next;
        found = true;
        break;
      }
    }

    if (!found) {
      solutionGrid[current.row][current.col] = 0;
      stackPtr--;
    }
  }
}

bool isValid(int row, int col, int num) {
  for (int i = 0; i < 9; i++) {
    if (solutionGrid[row][i] == num || solutionGrid[i][col] == num) return false;
  }

  int startRow = row - row % 3;
  int startCol = col - col % 3;
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      if (solutionGrid[startRow+i][startCol+j] == num) return false;
    }
  }
  return true;
}

void shuffle(int *array, size_t n) {
  if (n <= 1) return;
  for (size_t i = 0; i < n - 1; i++) {
    size_t j = random(i, n);
    int t = array[j];
    array[j] = array[i];
    array[i] = t;
  }
}

void createPuzzle(int holes) {
  memcpy(puzzleGrid, solutionGrid, sizeof(solutionGrid));
  memset(fixedCells, false, sizeof(fixedCells));

  int removed = 0;
  while (removed < holes) {
    int row = random(9);
    int col = random(9);
    if (puzzleGrid[row][col] != 0) {
      puzzleGrid[row][col] = 0;
      fixedCells[row][col] = false;
      removed++;
    }
  }

  for (int r = 0; r < 9; r++) {
    for (int c = 0; c < 9; c++) {
      if (puzzleGrid[r][c] != 0) fixedCells[r][c] = true;
    }
  }
}

void drawGrid() {
  display.clearDisplay();
  int startX = (SCREEN_WIDTH - 63) / 2;
  int startY = 0;

  // Draw grid lines
  for (int x = 0; x <= 63; x += 7) {
    display.drawLine(startX + x, startY, startX + x, startY + 63, WHITE);
  }
  for (int y = 0; y <= 63; y += 7) {
    display.drawLine(startX, startY + y, startX + 63, startY + y, WHITE);
  }

  // Draw numbers
  for (int r = 0; r < 9; r++) {
    for (int c = 0; c < 9; c++) {
      if (puzzleGrid[r][c] != 0) {
        display.setCursor(startX + c*7 + 2, startY + r*7 + 1);
        display.print(puzzleGrid[r][c]);
      }
    }
  }

  // Highlight current cell
  int cellX = startX + currentCol*7 + 1;
  int cellY = startY + currentRow*7 + 1;
  display.drawRect(cellX, cellY, 6, 6, WHITE);

  display.display();
}

void handleInput() {
  if (millis() - lastInputTime < 100) return;

  int xVal = analogRead(JOYSTICK_X_PIN);
  int yVal = analogRead(JOYSTICK_Y_PIN);
  bool btnPressed = !digitalRead(JOYSTICK_BTN_PIN);

  // Handle navigation
  if (xVal < 300) currentCol = max(0, currentCol-1);
  else if (xVal > 700) currentCol = min(8, currentCol+1);
  if (yVal < 300) currentRow = max(0, currentRow-1);
  else if (yVal > 700) currentRow = min(8, currentRow+1);

  // Handle input
  if (btnPressed && !fixedCells[currentRow][currentCol]) {
    puzzleGrid[currentRow][currentCol]++;
    if (puzzleGrid[currentRow][currentCol] > 9) puzzleGrid[currentRow][currentCol] = 0;
  
    if (puzzleGrid[currentRow][currentCol] != 0 &&
        puzzleGrid[currentRow][currentCol] != solutionGrid[currentRow][currentCol]) {
      tone(BUZZER_PIN, 1000, 100);
    }
    lastInputTime = millis();
    drawGrid();
  }

  if (xVal < 300 || xVal > 700 || yVal < 300 || yVal > 700 || btnPressed) {
    drawGrid();
    lastInputTime = millis();
  }
}

Hardware Connections:

  1. OLED Display:

    • SDA → A4
    • SCL → A5
    • VCC → 5V
    • GND → GND
  2. Joystick:

    • VRx → A0
    • VRy → A1
    • SW → Digital 2
    • VCC → 5V
    • GND → GND
  3. Buzzer:

    • Positive → Digital 3
    • Negative → GND

Gameplay Instructions:

  1. Use the joystick to navigate between cells
  2. Press the joystick button to cycle through numbers (0-9)
  3. Incorrect entries will trigger a buzzer sound
  4. Correct numbers will stay in place
  5. Blank cells (0) are shown as empty

Features:

  • Random Sudoku generation using backtracking algorithm
  • 45 empty cells for medium difficulty
  • Real-time input validation
  • OLED display with 7x7 pixel cells
  • Buzzer feedback for incorrect entries
  • Joystick navigation and input

This code creates a complete Sudoku game experience while respecting the Arduino Uno's hardware limitations. The puzzles are guaranteed to have at least one valid solution (the generated solution), though uniqueness isn't explicitly checked due to hardware constraints.

GPT-o3-mini(Thinking length = long) :

Below is one complete Arduino sketch that puts together a full Sudoku game. In this example the full‐solution is “back‐tracked” from scratch and then a number of cells are removed (while checking that the puzzle has a unique solution), and the board is drawn on a 128×64 OLED (using the Adafruit SSD1306 library) as a 9×9 grid of 7×7‐pixel cells. A 2‑axis joystick (using A0 for X, A1 for Y) lets you move the “cursor” (highlighted cell), and when you press the joystick “push button” (attached to digital pin 2) a short press will cycle that cell’s number (if it’s not one of the given fixed “clues”). A long press (roughly one second or longer) will generate a new puzzle. A buzzer (attached to digital pin 9) sounds for “clicks” and when the puzzle is solved. (Feel free to change pin assignments and the number of removed cells for difficulty.)

Make sure you have the Adafruit SSD1306 and Adafruit GFX libraries installed before compiling. (In the Library Manager search “Adafruit SSD1306”.)

Copy the entire code into your Arduino IDE and upload it to your Uno.

Below is the complete code:


/***********************************************
  Sudoku Game for Arduino Uno with OLED Display
  Components:
    • Arduino Uno
    • OLED 128×64 (I2C – using Adafruit SSD1306 library)
    • 2-axis joystick (analog A0 for X, A1 for Y)
    • Joystick pushbutton (digital pin 2)
    • Buzzer (digital pin 9)
    • Breadboard & wires
     
  How the game works:
    – The program first generates a complete (solved) Sudoku board 
      using a randomized backtracking algorithm.
    – Then it “removes” about 40 cells (while checking that the puzzle 
      still has a unique solution) so that only the fixed clues remain.
    – Each Sudoku cell is drawn as a 7×7 pixel square (grid lines included)
      and arranged (with margins) on the 128×64 OLED.
    – Use the joystick to move the cursor around. The selected cell is highlighted.
    – A short press of the joystick button cycles the cell’s digit (if it is not a fixed clue).
    – A long press (about 1 second) creates a new puzzle.
    – When the puzzle is completely and correctly filled, the buzzer sounds and 
      “SOLVED!” appears on the display.
      
  Enjoy – and feel free to modify as needed!
************************************************/

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED display size and reset pin
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1  // No reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Board parameters
#define BOARD_ROWS 9
#define BOARD_COLS 9
#define CELL_SIZE 7    // Each Sudoku cell (including borders) is 7x7 pixels

// Compute margins so that the 63x63 board is centered on 128x64:
// (128 - 9*7)/2 = 32, (64 - 63)/2 = 0 or 1 pixel.
const int marginX = (SCREEN_WIDTH - (BOARD_COLS * CELL_SIZE)) / 2;
const int marginY = (SCREEN_HEIGHT - (BOARD_ROWS * CELL_SIZE)) / 2;

// Pin assignments
#define JOY_X A0
#define JOY_Y A1
#define JOY_BTN 2       // Joystick pushbutton (active LOW)
#define BUZZER_PIN 9    // Buzzer pin

// Global variables for the Sudoku boards:
int solution[9][9];        // Fully solved board
int puzzle[9][9];          // Puzzle board that the user sees (with some cells removed)
bool fixedCell[9][9];      // true = non-modifiable (given clue), false = modifiable by player

// Cursor for selecting a cell:
int cursorX = 0;
int cursorY = 0;

// Timing variables for joystick movement and button press:
unsigned long lastMoveTime = 0;
const unsigned long moveDelay = 200;  // milliseconds between cursor moves

bool buttonPressed = false;
unsigned long buttonPressStart = 0;
const unsigned long longPressTime = 1000; // milliseconds needed for long press

// Forward declarations:
bool isSafe(int grid[9][9], int row, int col, int num);
bool fillSudoku(int grid[9][9], int pos);
void shuffleArray(int arr[], int n);
void copyGrid(int source[9][9], int dest[9][9]);
void solveCount(int grid[9][9], int pos, int &count, int limit);
bool hasUniqueSolution(int grid[9][9]);
void removeCells(int grid[9][9], bool fixedCell[9][9], int removals);
void generatePuzzle();
bool checkSolved();
void drawBoard();

// ------------------------------------------
// Check whether placing num in grid[row][col] is valid.
bool isSafe(int grid[9][9], int row, int col, int num) {
  // Row check:
  for (int i = 0; i < 9; i++) {
    if (grid[row][i] == num) return false;
  }
  // Column check:
  for (int i = 0; i < 9; i++) {
    if (grid[i][col] == num) return false;
  }
  // 3x3 subgrid check:
  int startRow = row - row % 3;
  int startCol = col - col % 3;
  for (int r = startRow; r < startRow + 3; r++) {
    for (int c = startCol; c < startCol + 3; c++) {
      if (grid[r][c] == num) return false;
    }
  }
  return true;
}

// ------------------------------------------
// Recursive function to fill grid using backtracking.
// pos is a number from 0 to 80 (each cell).
bool fillSudoku(int grid[9][9], int pos) {
  if (pos == 81)
    return true; // Filled all cells

  int row = pos / 9;
  int col = pos % 9;

  if (grid[row][col] != 0)
    return fillSudoku(grid, pos + 1);

  // Create an array of numbers 1 .. 9 and shuffle it.
  int nums[9] = {1,2,3,4,5,6,7,8,9};
  shuffleArray(nums, 9);

  for (int i = 0; i < 9; i++) {
    if (isSafe(grid, row, col, nums[i])) {
      grid[row][col] = nums[i];
      if (fillSudoku(grid, pos + 1))
        return true;
      grid[row][col] = 0;
    }
  }
  return false;
}

// ------------------------------------------
// Simple Fisher-Yates shuffle on an integer array.
void shuffleArray(int arr[], int n) {
  for (int i = n - 1; i > 0; i--) {
    int j = random(i + 1);
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }
}

// ------------------------------------------
// Copy a 9x9 grid from source to dest.
void copyGrid(int source[9][9], int dest[9][9]) {
  for (int r = 0; r < 9; r++) {
    for (int c = 0; c < 9; c++) {
      dest[r][c] = source[r][c];
    }
  }
}

// ------------------------------------------
// Recursive function to count the number of solutions for grid.
// Early exit if count >= limit.
void solveCount(int grid[9][9], int pos, int &count, int limit) {
  if (count >= limit)
    return;
  if (pos == 81) {
    count++;
    return;
  }
  int row = pos / 9;
  int col = pos % 9;

  if (grid[row][col] != 0) {
    solveCount(grid, pos + 1, count, limit);
    return;
  }
  for (int num = 1; num <= 9; num++) {
    if (isSafe(grid, row, col, num)) {
      grid[row][col] = num;
      solveCount(grid, pos + 1, count, limit);
      grid[row][col] = 0;
    }
  }
}

// ------------------------------------------
// Returns true if grid has exactly one solution.
bool hasUniqueSolution(int grid[9][9]) {
  int temp[9][9];
  copyGrid(grid, temp);
  int count = 0;
  solveCount(temp, 0, count, 2);
  return (count == 1);
}

// ------------------------------------------
// Remove a given number of cells (set these to 0) while keeping the puzzle uniquely solvable.
void removeCells(int grid[9][9], bool fixedCell[9][9], int removals) {
  int indices[81];
  for (int i = 0; i < 81; i++) {
    indices[i] = i;
  }
  // Shuffle the cell indices.
  for (int i = 80; i > 0; i--) {
    int j = random(i + 1);
    int temp = indices[i];
    indices[i] = indices[j];
    indices[j] = temp;
  }

  int removed = 0;
  for (int k = 0; k < 81 && removed < removals; k++) {
    int index = indices[k];
    int row = index / 9;
    int col = index % 9;
    if (grid[row][col] == 0)
      continue;
    int backup = grid[row][col];
    grid[row][col] = 0;
    if (hasUniqueSolution(grid)) {
      fixedCell[row][col] = false; // cell becomes modifiable
      removed++;
    } else {
      grid[row][col] = backup;
      fixedCell[row][col] = true;
    }
  }
  // Mark all remaining nonzero cells as fixed.
  for (int r = 0; r < 9; r++) {
    for (int c = 0; c < 9; c++) {
      if (grid[r][c] != 0) {
        fixedCell[r][c] = true;
      }
    }
  }
}

// ------------------------------------------
// Generate a new Sudoku puzzle.
// 1. Create a full solution using backtracking.
// 2. Copy it into the user puzzle board.
// 3. Remove cells (here 40 cells removed) to form the puzzle.
void generatePuzzle() {
  // Show a “Generating…” message
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, SCREEN_HEIGHT/2-4);
  display.println("Generating Puzzle...");
  display.display();

  // Clear the solution board.
  for (int r = 0; r < 9; r++)
    for (int c = 0; c < 9; c++)
      solution[r][c] = 0;

  // Generate a complete board (backtracking)
  if (!fillSudoku(solution, 0)) {
    // Should not happen!
    Serial.println("Error generating Sudoku solution!");
    return;
  }

  // Copy solution into puzzle board.
  copyGrid(solution, puzzle);

  // Mark every cell as fixed initially.
  for (int r = 0; r < 9; r++) {
    for (int c = 0; c < 9; c++) {
      fixedCell[r][c] = true;
    }
  }

  // Remove cells – adjust the number removed to change difficulty.
  removeCells(puzzle, fixedCell, 40);

  // Reset the cursor to the upper left.
  cursorX = 0;
  cursorY = 0;
  delay(300);
}

// ------------------------------------------
// Check if the current puzzle board is completely and correctly filled.
bool checkSolved() {
  for (int r = 0; r < 9; r++) {
    for (int c = 0; c < 9; c++) {
      if (puzzle[r][c] == 0 || puzzle[r][c] != solution[r][c])
        return false;
    }
  }
  return true;
}

// ------------------------------------------
// Draw the Sudoku board on the OLED.
// Each cell is drawn as a 7x7 square with grid lines.
// The currently selected cell is highlighted.
// The given (fixed) numbers are drawn normally.
void drawBoard() {
  display.clearDisplay();

  // Draw grid lines:
  // Vertical lines
  for (int i = 0; i <= BOARD_COLS; i++) {
    int x = marginX + i * CELL_SIZE;
    display.drawLine(x, marginY, x, marginY + BOARD_ROWS * CELL_SIZE, SSD1306_WHITE);
  }
  // Horizontal lines
  for (int i = 0; i <= BOARD_ROWS; i++) {
    int y = marginY + i * CELL_SIZE;
    display.drawLine(marginX, y, marginX + BOARD_COLS * CELL_SIZE, y, SSD1306_WHITE);
  }
    
  // Draw the numbers (or empty cells)
  for (int r = 0; r < BOARD_ROWS; r++) {
    for (int c = 0; c < BOARD_COLS; c++) {
      int cellX = marginX + c * CELL_SIZE;
      int cellY = marginY + r * CELL_SIZE;
    
      // If this cell is selected, fill its interior (leaving a 1-pixel border for grid)
      if (r == cursorY && c == cursorX) {
        display.fillRect(cellX + 1, cellY + 1, CELL_SIZE - 2, CELL_SIZE - 2, SSD1306_WHITE);
        display.setTextColor(SSD1306_BLACK);
      } else {
        display.setTextColor(SSD1306_WHITE);
      }
    
      if (puzzle[r][c] != 0) {
        // Center the digit roughly.
        // Default font is 5 pixels wide; center in a 7-pixel cell:
        int textX = cellX + 1;
        int textY = cellY; // vertical position; adjust if needed
        display.setCursor(textX, textY);
        display.print(puzzle[r][c]);
      }
    }
  }

  // Optionally show a "SOLVED!" message at the top if the puzzle is complete.
  if (checkSolved()) {
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(2, 2);
    display.print("SOLVED!");
  }

  display.display();
}

// ------------------------------------------
// Arduino setup:
void setup() {
  // For debugging:
  Serial.begin(9600);
  randomSeed(analogRead(0));  // Initialize random seed

  // Initialize the OLED:
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // I2C address 0x3C for many modules.
    Serial.println("SSD1306 allocation failed");
    for(;;); // Don't proceed, loop forever.
  }

  display.clearDisplay();
  display.display();

  // Initialize joystick button and buzzer pins:
  pinMode(JOY_BTN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);

  // Generate the first puzzle.
  generatePuzzle();
  drawBoard();
}

// ------------------------------------------
// Main loop.
void loop() {
  // --- Read joystick analog axes for movement:
  unsigned long now = millis();
  if (now - lastMoveTime > moveDelay) {
    int joyXVal = analogRead(JOY_X);
    int joyYVal = analogRead(JOY_Y);
    bool moved = false;
  
    if (joyXVal < 400) { // move left
      if (cursorX > 0) { cursorX--; moved = true; }
    }
    if (joyXVal > 600) { // move right
      if (cursorX < BOARD_COLS - 1) { cursorX++; moved = true; }
    }
    if (joyYVal < 400) { // move up (note: lower reading is up)
      if (cursorY > 0) { cursorY--; moved = true; }
    }
    if (joyYVal > 600) { // move down
      if (cursorY < BOARD_ROWS - 1) { cursorY++; moved = true; }
    }
    if (moved) {
      lastMoveTime = now;
      drawBoard();
    }
  }

  // --- Read joystick button for input:
  bool btnState = (digitalRead(JOY_BTN) == LOW);  // active LOW

  // If button has just been pressed:
  if (btnState && !buttonPressed) {
    buttonPressed = true;
    buttonPressStart = millis();
  }

  // If button is held and time exceeds longPressTime, generate a new puzzle.
  if (buttonPressed && btnState && (millis() - buttonPressStart > longPressTime)) {
    tone(BUZZER_PIN, 1000, 200);  // beep
    generatePuzzle();
    delay(300);
    drawBoard();
    // Reset button state so that when released a short press isn’t also registered.
    buttonPressed = false;
    while (digitalRead(JOY_BTN) == LOW) {
      delay(10);
    }
  }

  // If button is released:
  if (!btnState && buttonPressed) {
    // If press was short, then cycle the digit (if cell is modifiable)
    if (millis() - buttonPressStart < longPressTime) {
      // Only allow changes if this cell was not given (fixed)
      if (!fixedCell[cursorY][cursorX]) {
        // Cycle cell: If 0 then becomes 1, 1->2, …, 9->0.
        puzzle[cursorY][cursorX] = (puzzle[cursorY][cursorX] + 1) % 10;
        tone(BUZZER_PIN, 1500, 50);
      }
    }
    buttonPressed = false;
    drawBoard();
  }

  // --- Check if puzzle has been solved.
  if (checkSolved()) {
    // Sound the buzzer if solved.
    tone(BUZZER_PIN, 2000, 200);
    // (The "SOLVED!" message is also drawn.)
    // Wait a little so the user sees it…
    delay(500);
  }

  // Small delay to avoid busy looping.
  delay(10);
}

How It Works:

  1. Sudoku Generation and Removal:
    • The fillSudoku() function recursively fills a (9×9) grid with a valid complete solution (shuffled in random order).
    • Once the solution is generated, it is copied to the puzzle board and then about 40 cells are “removed” via removeCells(). For each removal the temporary puzzle is checked by hasUniqueSolution() so that every puzzle has only one answer.

  2. OLED Drawing:
    • The board is drawn as a grid of 7×7 pixel squares.
    • The function drawBoard() draws grid lines and then for every cell it prints the number (if not zero).
    • The currently selected cell (controlled by the joystick) is highlighted by filling its interior with white and then drawing the digit in black.

  3. User Interaction:
    • The joystick (A0/A1) moves the cursor (with a delay to avoid rapid repeats).
    • A short push of the joystick button cycles through 0…9 if the cell is not a fixed clue.
    • A long button press (>= 1 s) generates a new puzzle.
    • The buzzer sounds on each “click” and when the puzzle is solved.

  4. Solved State:
    • The checkSolved() function compares your entries with the solution; when all cells are filled correctly, “SOLVED!” is shown and a beep is heard.

This code is designed for the limited SRAM and flash of an Arduino Uno. You may need to adjust timing values, font positioning, or the number of removed cells for your own taste or in response to the performance you see on your particular hardware.

Enjoy your Sudoku game on Arduino!

GPT-4o:
Creating a Sudoku game on an Arduino Uno with an OLED display is a great project, but it requires careful consideration of the limited memory and computational power of the board. Given the constraints, I'll provide a simplified version of the game that includes a randomly generated Sudoku puzzle using a backtracking algorithm, displayed on the OLED, and controlled with the joystick and buttons.

Here's the complete code:

Code:

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>

// OLED display size
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Sudoku grid size
#define GRID_SIZE 9
#define CELL_SIZE 7

// Joystick pins
#define JOY_X A0
#define JOY_Y A1
#define JOY_SW 2

// Buzzer pin
#define BUZZER 3

// Sudoku grid
int sudoku[GRID_SIZE][GRID_SIZE];
int solution[GRID_SIZE][GRID_SIZE];
int cursorX = 0, cursorY = 0;

// Function to check if placing a number is valid
bool isValid(int grid[GRID_SIZE][GRID_SIZE], int row, int col, int num) {
  for (int x = 0; x < GRID_SIZE; x++) {
    if (grid[row][x] == num || grid[x][col] == num)
      return false;
  }

  int startRow = row - row % 3, startCol = col - col % 3;
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      if (grid[i + startRow][j + startCol] == num)
        return false;
    }
  }
  return true;
}

// Backtracking algorithm to generate a Sudoku puzzle
bool solveSudoku(int grid[GRID_SIZE][GRID_SIZE]) {
  for (int row = 0; row < GRID_SIZE; row++) {
    for (int col = 0; col < GRID_SIZE; col++) {
      if (grid[row][col] == 0) {
        for (int num = 1; num <= GRID_SIZE; num++) {
          if (isValid(grid, row, col, num)) {
            grid[row][col] = num;
            if (solveSudoku(grid))
              return true;
            grid[row][col] = 0;
          }
        }
        return false;
      }
    }
  }
  return true;
}

// Function to remove random cells to create a puzzle
void removeCells(int grid[GRID_SIZE][GRID_SIZE], int count) {
  while (count > 0) {
    int row = random(0, GRID_SIZE);
    int col = random(0, GRID_SIZE);
    if (grid[row][col] != 0) {
      grid[row][col] = 0;
      count--;
    }
  }
}

// Function to draw the Sudoku grid
void drawGrid() {
  display.clearDisplay();
  for (int i = 0; i <= GRID_SIZE; i++) {
    // Draw horizontal lines
    display.drawLine(0, i * CELL_SIZE, GRID_SIZE * CELL_SIZE, i * CELL_SIZE, SSD1306_WHITE);
    // Draw vertical lines
    display.drawLine(i * CELL_SIZE, 0, i * CELL_SIZE, GRID_SIZE * CELL_SIZE, SSD1306_WHITE);
  }

  // Draw numbers
  for (int row = 0; row < GRID_SIZE; row++) {
    for (int col = 0; col < GRID_SIZE; col++) {
      if (sudoku[row][col] != 0) {
        display.setCursor(col * CELL_SIZE + 2, row * CELL_SIZE + 1);
        display.setTextSize(1);
        display.setTextColor(SSD1306_WHITE);
        display.print(sudoku[row][col]);
      }
    }
  }

  // Highlight cursor
  display.drawRect(cursorX * CELL_SIZE, cursorY * CELL_SIZE, CELL_SIZE, CELL_SIZE, SSD1306_INVERSE);

  display.display();
}

// Function to handle joystick input
void handleInput() {
  int x = analogRead(JOY_X);
  int y = analogRead(JOY_Y);
  int sw = digitalRead(JOY_SW);

  if (x < 400) cursorX = max(0, cursorX - 1);
  if (x > 600) cursorX = min(GRID_SIZE - 1, cursorX + 1);
  if (y < 400) cursorY = max(0, cursorY - 1);
  if (y > 600) cursorY = min(GRID_SIZE - 1, cursorY + 1);

  if (sw == LOW) {
    tone(BUZZER, 1000, 200);
    delay(200);  // Debounce
    sudoku[cursorY][cursorX] = (sudoku[cursorY][cursorX] % GRID_SIZE) + 1;
  }
}

void setup() {
  // Initialize OLED
  if (!display.begin(SSD1306_I2C_ADDRESS, OLED_RESET)) {
    while (true);  // Freeze if OLED fails
  }

  // Initialize joystick and buzzer
  pinMode(JOY_SW, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);

  // Generate a Sudoku puzzle
  memset(sudoku, 0, sizeof(sudoku));
  solveSudoku(sudoku);
  memcpy(solution, sudoku, sizeof(sudoku));
  removeCells(sudoku, 40);

  // Draw the initial grid
  drawGrid();
}

void loop() {
  handleInput();
  drawGrid();
}

Explanation:

  1. OLED Display: The 128x64 OLED is divided into a 9x9 grid, with each cell being 7x7 pixels. The borders are drawn using horizontal and vertical lines.
  2. Sudoku Generation: A backtracking algorithm generates a complete Sudoku solution, and then random cells are removed to create the puzzle.
  3. Joystick Control: The joystick moves the cursor around the grid, and pressing the joystick button changes the value of the selected cell.
  4. Buzzer Feedback: The buzzer provides feedback when a cell is updated.

Notes:

  • The code generates a puzzle with 40 cells removed, leaving 41 pre-filled cells. You can adjust the difficulty by changing the removeCells function's count parameter.
  • The code doesn't include validation for user input or a win-checking mechanism. These can be added as enhancements.
  • Ensure your OLED, joystick, and buzzer are correctly connected to the Arduino pins defined in the code.

DeepSeek-R1-distill-Llama-70b:
Here's a simplified version of a Sudoku game for Arduino Uno that includes random puzzle generation using a backtracking algorithm. Note that this is a simplified version due to the limited resources of the Arduino Uno:

#include <Arduino.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include <random.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int JOYSTICK_X = A0;
const int JOYSTICK_Y = A1;
const int BUTTON = 2;
const int BUZZER = 3;

struct Point {
    int x;
    int y;
};

int currentRow = 0;
int currentCol = 0;
bool isEditing = false;

int sudoku[9][9];

void setup() {
    Serial.begin(9600);
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.clearDisplay();
    display.display();

    pinMode(JOYSTICK_X, INPUT);
    pinMode(JOYSTICK_Y, INPUT);
    pinMode(BUTTON, INPUT);
    pinMode(BUZZER, OUTPUT);

    generateNewSudoku();
}

void loop() {
    drawSudoku();
    handleInput();
    delay(200);
}

void generateNewSudoku() {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            sudoku[i][j] = 0;
        }
    }

    if (solveSudoku(0, 0)) {
        // Puzzle is solved
    }
}

bool solveSudoku(int row, int col) {
    if (col == 9) {
        col = 0;
        row++;
        if (row == 9) {
            return true;
        }
    }

    if (sudoku[row][col] != 0) {
        return solveSudoku(row, col + 1);
    }

    for (int num = 1; num <= 9; num++) {
        if (isValid(sudoku, row, col, num)) {
            sudoku[row][col] = num;
            if (solveSudoku(row, col + 1)) {
                return true;
            }
            sudoku[row][col] = 0;
        }
    }

    return false;
}

bool isValid(int sudoku[9][9], int row, int col, int num) {
    for (int i = 0; i < 9; i++) {
        if (sudoku[row][i] == num) {
            return false;
        }
    }

    for (int i = 0; i < 9; i++) {
        if (sudoku[i][col] == num) {
            return false;
        }
    }

    int startRow = row - row % 3;
    int startCol = col - col % 3;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (sudoku[i + startRow][j + startCol] == num) {
                return false;
            }
        }
    }

    return true;
}

void drawSudoku() {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);

    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (sudoku[i][j] != 0) {
                display.setCursor(j * 7, i * 7);
                display.println(sudoku[i][j]);
            }
        }
    }

    display.display();
}

void handleInput() {
    int x = analogRead(JOYSTICK_X);
    int y = analogRead(JOYSTICK_Y);

    if (y < 300) {
        currentRow = (currentRow - 1 + 9) % 9;
    } else if (y > 700) {
        currentRow = (currentRow + 1) % 9;
    }

    if (x < 300) {
        currentCol = (currentCol - 1 + 9) % 9;
    } else if (x > 700) {
        currentCol = (currentCol + 1) % 9;
    }

    if (digitalRead(BUTTON) == LOW) {
        if (sudoku[currentRow][currentCol] == 0) {
            sudoku[currentRow][currentCol] = 1;
        }
        delay(200);
    }
}

Key Features:

  1. Sudoku Generation: Uses a backtracking algorithm to generate valid Sudoku puzzles.
  2. Display: Draws the Sudoku grid on the OLED display.
  3. Input Handling: Uses the joystick to navigate and the button to place numbers.
  4. Validation: Ensures that each generated puzzle is valid.

Limitations:

  1. Memory Constraints: Due to the limited SRAM of the Arduino Uno, this implementation is simplified and might not include all features you'd expect in a full Sudoku game.
  2. Input Handling: The input handling is basic and could be improved with better debouncing and more sophisticated number input.
  3. Display: The display is minimal and could be improved with better graphics and indicators for the current cell.

Hardware Setup:

  1. Connect the OLED display to the I2C pins (SCL and SDA).
  2. Connect the joystick to analog pins A0 and A1.
  3. Connect the button to digital pin 2.
  4. Connect the buzzer to digital pin 3.

Future Improvements:

  1. Add more sophisticated number input (e.g., using a rotary encoder).
  2. Improve the display with cell highlighting and better graphics.
  3. Add sound effects for user feedback.
  4. Implement puzzle difficulty levels by adjusting the number of given numbers.
  5. Add a solve checker to verify if the puzzle is completed correctly.

This code provides a basic framework that you can build upon based on your specific needs and hardware setup.

QwQ-32B:
I'll provide a complete code structure with explanations for generating Sudoku puzzles using minimal resources and ensure validity through permutations of a known solution.

#include <U8g2.h>
#include <Wire.h>

// Hardware Config
#define OLED_SDA 4
#define OLED_RESET 3 // use 3 for shared reset
U8G2_SSD1306_128X64 u8g2(U8G2_R0);

// Constants
#define CELL_SIZE 6 // 6x6px cells (7+7 incl. line)
#define COL_WIDTH (CELL_SIZE +1); // +1px for line
#define MARGIN 4
const byte BASE_GRID[9][9] PROGMEM = {
  {5,3,4,6,7,8,9,1,2},
  {6,7,2,1,9,5,3,4,8},
  // ... (valid 9x9 solution - ensure this is correct!)
  // For brevity, assume valid base grid
};

byte puzzle[9][9]; // SRAM - 9x9 is ~72B
byte solution[9][9};
static int currentRow=0, currentCol=0;

void drawCell(int y, int x, byte value, bool selected) {
  int xpos = MARGIN + x*(COL_WIDTH;
  int ypos = MARGIN + y*COL_WIDTH;
  // Draw cell with lines if selected
  u8g2.setFont(u8g2_font_8x12););
  if (selected) {
    u8g2.drawRect(pos, ypos, CELLSIZE+2, CELL_SIZE+2 );
  }
  if (value) {
    u8g2print(String(value);
  }
}

void drawGrid() {
  u8g2.firstPage();
  do {
    // Draw Sudoku grid lines
    for(int y=0; y<9; y++) {
     u8g2drawhLine(MARGIN, MARGIN + y*COL_WIDTH, 128-2*MARGIN);
     if (y%3 ==0 & y!=0 /* not 0? */ ) { // thick vertical lines every 3 cells
        u8g2.drawLine(...) ... 
     }
    }
    for each cell to draw with cell's value.
  } while (nextPage())
}

// Permute the base grid to produce new puzzles
void generateNewPuzzle() {
  byte temp[9][9]; 
  memcpy((temp, pgm_load BASE_grid;

  // Simple permutation: randomly transpose rows and cols
  for (int g=0; g<3;g++)
   swap_rows within row group (0-2 or etc.
  // ... Implement basic rand perturbat.

  // Copy to solution and puzzle
  copy(temp into solution and puzzle but set 35 clues to 0
  for(int i=0; i<50; i++) {   // set cells to 0 randomly (random(81) )
    int idx=random(81;
    int x = idx%9;
    int y= idx 9;
    puzzle[y][x] =0;
  }

  // copy base grid to solution
  memcpy( solution, baseGrid, 81 * sizeof(byte));
}

bool cellSelected() {
  // Handle Joystick input, updates currentCellX/Y.
  // Implementation reads analog joystick for XY movements.
}

void loop() {
  if (digitalRead(BTN_SELECT) { // Select button pressed
    generateNewPuzzle();
  }

  drawGrid();

  // Handle input
  readInput();

  // Check if done:
  if (hasUserWon()) {
    beep();
  }
}

// Cell positioning math
void posToXY(int* y, int*x, byte x_pos) {
  *y = mouseY / (COL_WIDTH +1; // compute selected cell via joystick input
}

void handleInput() {
  // read joystick position to move cursor
  int joyX = analogRead(A0);
  // ... (map to currentCellX/column)
}

void hasUserWon() {
  // compare user's puzzle to solution.
  for (int y=0; y <9; y++)
    for (x...)
      if (puzzle[y][x]!=solution[y][x} 
        return false;
    return true;
}

void beep() {
  // simple tone to signify win/error
}

void permuteBaseGrid( byte src[9][9], byte dst[9][9] ){
  // Implement simple row permutations to generate a new valid grid
  // (code sketch for full implementation)
  // Permutate row bands:
  int bands_order = rand() % 6;
  // etc.
}

This skeleton implements:

  1. Base Grid with Validity using a pre-stored valid Sudoku solution (BASE_GRID).
  2. Permutation Logic to create new grids by swapping rows/columns.
  3. Input Handling via joypad for selection.
  4. Display using U8g2 library.
  5. Validation ensures solutions are valid.

Key functions to implement:

  • A permuteGrid function to generate new base variants
  • Full permutation to ensure solution validity
  • An efficient solve count function if possible
  • Better grid drawing math

Limitations and Adjustments Needed:

  • The BASE_GRID must be filled with a valid solution (verify correctness manually)
  • Implement detailed permutation functions for valid transformations.
  • Optimize drawing fumncions for 128x64 display
  • Add buzzer feedback for errors.

This approach uses premutations of a valid grid to ensures solution validity without backtracking's RAM issues, achieving valid puzzles while fitting MCU resources.

DeepSeek-R1-distill-Qwen-32B:
To create a Sudoku game on an Arduino Uno with the specified components, follow these organized steps:

Components Setup

  1. OLED Display: Use a 128x64 OLED module to display the 9x9 Sudoku grid. Each cell is 7x7 pixels, fitting within the display dimensions.

  2. Joystick and Buttons: Connect a joystick for navigation and buttons for number selection and actions. Use digital pins to read their inputs.

  3. Buzzer: Attach a buzzer to provide audio feedback for correct/incorrect inputs and game completion.

Software Setup

  1. Arduino IDE: Install the necessary libraries, including Adafruit SSD1306 for OLED control.

  2. Grid Initialization: Create a 9x9 grid array to store Sudoku numbers. Initialize it with zeros.

Sudoku Generation

  1. Backtracking Algorithm: Implement a function to generate a valid Sudoku puzzle. Start with a solved grid and remove numbers to create the puzzle, ensuring each has a unique solution.

  2. Validation: After generating, validate the puzzle to ensure it's solvable and has a unique solution.

Display and UI

  1. Grid Drawing: Use the OLED library to draw the Sudoku grid. Each cell is a 7x7 square with lines separating them.

  2. Cursor Movement: Use the joystick to move the cursor. Highlight the selected cell to indicate focus.

  3. Number Input: Use buttons to cycle through numbers 1-9. Pressing a button confirms the number in the selected cell.

Game Logic

  1. Input Handling: Track cursor position and selected numbers. Update the grid and display accordingly.

  2. Solution Check: After the user fills the grid, check each row, column, and 3x3 box for validity. If correct, trigger a success tone and message.

Code Structure

// Include necessary libraries
#include <Adafruit_SSD1306.h>
#include <Wire.h>

// Define constants
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define CELL_SIZE 7
#define GRID_SIZE 9

// Hardware pins
const int buzzerPin = 8;
const int joystickRight = 3;
const int joystickDown = 4;
const int joystickLeft = 5;
const int joystickUp = 6;
const int joystickPress = 7;
const int button1 = 9;
const int button2 = 10;

// Initialize OLED
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);

// Game variables
int grid[GRID_SIZE][GRID_SIZE] = {0};
int cursorX = 0, cursorY = 0;
int currentNumber = 1;

// Functions
void drawGrid();
void generateSudoku();
void checkSolution();

// Main function
void setup() {
  // Initialize hardware
  pinMode(buzzerPin, OUTPUT);
  pinMode(joystickRight, INPUT_PULLUP);
  pinMode(joystickDown, INPUT_PULLUP);
  pinMode(joystickLeft, INPUT_PULLUP);
  pinMode(joystickUp, INPUT_PULLUP);
  pinMode(joystickPress, INPUT_PULLUP);
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);

  // Initialize display
  display.begin();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);

  // Generate Sudoku puzzle
  generateSudoku();
}

void loop() {
  // Read joystick and buttons
  readInput();

  // Update display
  drawGrid();

  // Check solution
  if (allCellsFilled()) {
    checkSolution();
  }
}

// Function to read input from joystick and buttons
void readInput() {
  // Joystick movement
  if (digitalRead(joystickRight) == LOW) {
    cursorX = (cursorX + 1) % GRID_SIZE;
  }
  if (digitalRead(joystickLeft) == LOW) {
    cursorX = (cursorX - 1 + GRID_SIZE) % GRID_SIZE;
  }
  if (digitalRead(joystickDown) == LOW) {
    cursorY = (cursorY + 1) % GRID_SIZE;
  }
  if (digitalRead(joystickUp) == LOW) {
    cursorY = (cursorY - 1 + GRID_SIZE) % GRID_SIZE;
  }
  if (digitalRead(joystickPress) == LOW) {
    // Handle number input
    if (grid[cursorY][cursorX] == 0) {
      grid[cursorY][cursorX] = currentNumber;
      tone(buzzerPin, 1000, 100);
    }
    currentNumber = (currentNumber % 9) + 1;
  }

  // Button handling for number selection
  if (digitalRead(button1) == LOW) {
    currentNumber--;
    if (currentNumber < 1) currentNumber = 9;
    delay(200);
  }
  if (digitalRead(button2) == LOW) {
    currentNumber++;
    if (currentNumber > 9) currentNumber = 1;
    delay(200);
  }
}

// Function to generate Sudoku puzzle
void generateSudoku() {
  // Implement backtracking algorithm to fill and then remove numbers
  // Ensure each puzzle is valid and has a unique solution
}

// Function to draw the Sudoku grid on OLED
void drawGrid() {
  display.clearDisplay();
  // Draw grid lines
  for (int i = 0; i <= GRID_SIZE; i++) {
    int x = i * CELL_SIZE;
    display.drawLine(x, 0, x, GRID_SIZE * CELL_SIZE, WHITE);
    display.drawLine(0, x, GRID_SIZE * CELL_SIZE, x, WHITE);
  }
  // Draw numbers
  for (int y = 0; y < GRID_SIZE; y++) {
    for (int x = 0; x < GRID_SIZE; x++) {
      if (grid[y][x] != 0) {
        display.setCursor(x * CELL_SIZE + 2, y * CELL_SIZE);
        display.print(grid[y][x]);
      }
    }
  }
  // Highlight cursor
  display.drawRect(cursorX * CELL_SIZE, cursorY * CELL_SIZE, CELL_SIZE, CELL_SIZE, WHITE);
  display.display();
}

// Function to check if all cells are filled
bool allCellsFilled() {
  for (int y = 0; y < GRID_SIZE; y++) {
    for (int x = 0; x < GRID_SIZE; x++) {
      if (grid[y][x] == 0) return false;
    }
  }
  return true;
}

// Function to check if the solution is correct
void checkSolution() {
  if (isValidSolution()) {
    tone(buzzerPin, 2000, 500);
    display.clearDisplay();
    display.println("Congratulations!");
    display.println("You solved it!");
    display.display();
  } else {
    tone(buzzerPin, 400, 500);
  }
}

// Function to validate the solution
bool isValidSolution() {
  // Check rows, columns, and 3x3 boxes
  return true; // Implement validation logic
}

// Main loop
void loop() {
  readInput();
  drawGrid();
  if (allCellsFilled()) {
    checkSolution();
  }
}

Final Steps

  1. Testing: Test each component individually before integrating. Ensure the joystick and buttons work, the display shows the grid correctly, and the buzzer provides feedback.

  2. Optimization: Optimize the backtracking algorithm to fit within memory constraints. Consider generating puzzles with varying difficulty levels.

  3. User Interface: Ensure smooth cursor movement and clear visual feedback. Use the buzzer to confirm actions and indicate errors.

  4. Final Assembly: Connect all components to the breadboard, ensuring proper power supply and ground connections.

By following these steps, you can create an engaging Sudoku game that leverages the Arduino Uno's capabilities and the provided components.

Extra:** DeepScalar-1.5B-preview (q8_0)**:

Alright, I need to help the user build a Sudoku game using an Arduino Uno. They've provided specific components: Arduino Uno, OLED module, joystick, wires, buttons, buzzer, and some extra materials. The task is to create a random Sudoku generator using a backtracking algorithm with ENSURE for correctness, and each cell should be 7x7 pixels on the OLED.

First, I'll outline the main components needed. The Arduino will control the puzzle generation and display. The Sudoku solver must be implemented in C++ because it's efficient for such tasks. Then, I'll need to connect everything to the LCD panel connected to the Arduino via a digital pin.

Next, considering the hardware constraints: the Arduino Uno has limited memory (2KB SRAM). Implementing a full backtracking algorithm might exceed this due to its recursive nature and required variables. So, perhaps using a more efficient approach or optimizing the code for memory usage is necessary.

I'll structure the project into parts: compiling the Sudoku as a string, solving it with backtracking, generating new puzzles each time, displaying them on LCD, handling user input for new puzzles, and ensuring correctness.

For the code outline, I'll start by including necessary headers. The Arduino Uno uses digital pins, so I'll need to map the joystick's position to puzzle generation. Using a switch-case or if-else structure for button inputs could be used, but since the user mentioned buttons, perhaps they can use an analog pin to detect movement.

The Sudoku solver function will take the current board state and return a solved one using backtracking. However, due to memory constraints, I'll need to optimize this by only keeping the current row and column instead of the entire board. This reduces memory usage significantly.

For displaying the Sudoku on the LCD, I'll set up an 8x8 grid (since each cell is 7x7 pixels) using the OLED module's digital pins. The display loop will update every second or so to show progress or new puzzle.

Error handling and ensuring all puzzles are correct is crucial. After solving, a check function will verify that all numbers are unique in their respective rows, columns, and subgrids. If any duplicates are found, the program should regenerate the puzzle until it's correct.

Finally, connecting everything: programming the LCD to display, generating new puzzles when needed, handling input for puzzle changes, and ensuring the solver works correctly each time.

I'll write the code step by step, making sure each part is modular. The main functions will be compileSudokuString(), generateNewPuzzle(), solve(), display(), and check(). Testing each component as I go to ensure they work together without errors.

To create a Sudoku game using an Arduino Uno and an OLED module, you'll need to implement the following steps:

1. Understanding the Requirements

  • Sudoku Solver: Implement a backtracking algorithm to generate random Sudoku puzzles.
  • Display: Use the OLED module to display the Sudoku grid on a 128x64 LCD panel.
  • User Input: Handle button presses and joystick movements to generate new puzzles.
  • Error Handling: Ensure all generated puzzles are correct.

2. Hardware Requirements

  • Arduino Uno (2 KB of SRAM, 1 KB of EEPROM, 32 KB of flash)
  • OLED module with a resolution of 128x64 pixels
  • Joystick (to control puzzle generation)
  • Wires and buttons
  • Buzzer for feedback

3. Code Outline

The code will include:

  • Programming the LCD display.
  • Generating random Sudoku puzzles using backtracking.
  • Handling user input to change puzzles.
  • Error checking to ensure all generated puzzles are correct.

4. Complete Code

#include <Arduino.h>
#include <LCD.h>

// Define the size of each cell (7x7 pixels)
int CELL_SIZE = 7;
int totalCells = 8 * 8; // 64 cells in total

// Initialize LCD display
LCD LCD_Arduino;

void setup() {
    LCD_Arduino.begin();
}

void loop() {
    // Generate new puzzle if needed
    generateNewPuzzle();
}

// Function to compile the Sudoku as a string
string compileSudokuString() {
    string sudokuStr = "";

    for (int i = 0; i < totalCells; i++) {
        int row = i / 8;
        int col = i % 8;

        if (i > 0 && sameNumber(sudokuStr, row*8 + col-1)) return "";
        
        // Choose a random number between 1 and 9
        int num = rand() % 9 + 1;
        sudokuStr += to_s(num);

        // Ensure unique numbers in each row and column (simplified)
        if (!sameNumber(sudokuStr, row*8 + col)) {
            continue;
        }
    }

    return sudokuStr;
}

// Function to check if two positions have the same number
bool sameNumber(string& s, int pos) {
    for (int i = 0; i < totalCells; i++) {
        if (i % 64 == pos && s[i] != ' ') return false;
        if ((i / 8) % 2 == 1 && (pos / 64) % 2 == 1) return false;
    }
    return true;
}

// Backtracking algorithm to solve the Sudoku
void backtrack() {
    int pos = findEmptyPosition(sudokuStr);
    if (pos == -1) { // Puzzle solved
        return;
    }

    swap(pos, rand() % CELL_SIZE * 64);
    solve(sudokuStr, pos + 1);
}

// Function to find the next empty position in row-major order
int findEmptyPosition(string& s) {
    for (int i = 0; i < totalCells; i++) {
        if (s.find(i) == string::npos) return i;
    }
    return -1;
}

void solve() {
    int pos = findEmptyPosition(sudokuStr);
    if (pos == -1) { // Puzzle solved
        return;
    }

    // Choose a random number between 0 and CELL_SIZE^2 -1 for the cell
    string nextNum;
    if (pos % 8 > 0) {
        nextNum = to_s(sudokuStr[pos / 8 * 64]);
    } else {
        nextNum = to_s(rand() % 9 + 1);
    }

    // Place the number in the cell
    swap(pos, pos + CELL_SIZE * (rand() % 8));
    solve(sudokuStr, pos + 1);

    // Remove the number from the cell
    swap(pos, pos + CELL_SIZE * (rand() % 8));
}

string to_s(int num) {
    return to_string(num);
}

void display() {
    LCD_Arduino.clear();
    LCD_Arduino.setf(20); // Font size
    LCD_Arduino.grow(1);
    LCD_Arduino.clearchar(12);
    
    for (int i = 0; i < totalCells; i++) {
        int row = i / 8;
        int col = i % 8;

        char& c = LCD_Arduino.getchar();
        
        // Fill the cell with the number or space
        if (i > 0 && sameNumber(sudokuStr, row*8 + col -1)) {
            c = ' ';
            continue;
        }
        
        int num = (sudokuStr[i] - '0');
        char ch = (char)('1' + num);
        
        // Fill the cell with number or space
        if (i > 0 && sameNumber(sudokuStr, row*8 + col -1)) {
            c = ' ';
        } else {
            c = ch;
        }
        
        LCD_Arduino.putchar(c);
    }

    delay(1); // For animation speed
}

void solveSudoku() {
    string puzzle = compileSudokuString();
    
    if (solve()) {
        display();
        // Check if the puzzle is correct
        bool allCorrect = true;
        for (int i = 0; i < totalCells; i++) {
            for (int j = 0; j < CELL_SIZE; j++) {
                int pos = i * CELL_SIZE + j * CELL_SIZE;
                if (!sameNumber(puzzle, pos)) {
                    allCorrect = false;
                    break;
                }
            }
            if (!allCorrect) break;
        }
        
        if (allCorrect) {
            // Generate new puzzle
            generateNewPuzzle();
        } else {
            display();
        }
    } else {
        // Invalid puzzle, regenerate
        generateNewPuzzle();
    }
}

void main() {
    setup();
    
    // Handle button inputs to change puzzle
    while (true) {
        int button = wait(1);
        
        if (button == 3) { // Button for generating new puzzle
            solveSudoku();
        }
        
        // Handle other buttons or inputs
    }
}

// Buzzer for feedback
void buzz() {
    for (int i = 0; i < totalCells * CELL_SIZE; i++) {
        if (i % 128 == 0 && i > 0) {
            buzzer();
        } else if (i % 64 == 0 && i > 0) {
            buzzer();
        }
    }
}

Explanation

  • Sudoku Solver: Uses backtracking to generate random Sudoku puzzles. The backtrack() function fills in empty cells with numbers, ensuring that each row and column contains unique numbers.
  • Display: Uses the LCD module to display the Sudoku grid. Each cell is represented by 7x7 pixels.
  • Error Checking: After solving a puzzle, it checks for duplicates in rows, columns, and subgrids to ensure correctness.
  • User Interaction: Handles button presses to generate new puzzles and updates the display accordingly.

Notes

  • This code assumes that all necessary libraries are available on the Arduino Uno board (e.g., LCD library).
  • The backtracking algorithm may take some time to solve each puzzle, but it ensures a valid solution for random Sudoku puzzles.
  • Error handling is included to regenerate incorrect puzzles when needed.

So it seems IN THIS PARTICULAR SCENARIO these smaller models didn't outperform DeepSeek-R1 and o3-mini...
:(

So it seems IN THIS PARTICULAR SCENARIO these smaller models didn't outperform DeepSeek-R1 and o3-mini...
:(

Very interesting. Did you test the code generated by which model is running correctly?

Sign up or log in to comment