#include #include #include // Wi-Fi credentials const char* ssid = "EngineeringStudent"; const char* password = "cls2024!"; // Web server WebServer server(80); // Pins and thresholds const int servoPins[] = {7, 44, 43}; // Servo pins const int touchPins[] = {2, 3, 4}; // Touch input pins const long touchThresholds[] = {35000, 35000, 60000}; // Adjust if needed const int numMoles = 3; Servo servos[numMoles]; // Angles const int popUpAngle = 130; // Mole visible (servo up) const int hideAngle = 20; // Mole hidden (servo down) // Game state int currentMole = -1; int score = 0; int highScore = 0; bool gameRunning = false; // Track if game is running bool lastTouchState = false; // Track previous touch state to prevent multiple triggers // Timer variables unsigned long gameStartTime = 0; const unsigned long gameDuration = 30000; // 30 seconds in milliseconds void setup() { Serial.begin(115200); randomSeed(analogRead(0)); // Attach servos and ensure all start hidden for (int i = 0; i < numMoles; i++) { servos[i].attach(servoPins[i]); servos[i].write(hideAngle); } delay(500); // Give servos time to move to hide position // Wi-Fi WiFi.begin(ssid, password); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println("\nConnected! IP: " + WiFi.localIP().toString()); // Define routes server.on("/", handleRoot); server.on("/start", handleStart); server.on("/stop", handleStop); server.begin(); // Initially game is stopped currentMole = -1; } void loop() { server.handleClient(); if (!gameRunning) return; // Skip mole logic if game stopped // Check if time is up unsigned long elapsed = millis() - gameStartTime; if (elapsed >= gameDuration) { Serial.println("Time's up! Stopping game."); stopGame(); return; } // Only check for touches if there's an active mole if (currentMole == -1) return; // Only check the touch sensor corresponding to the current active mole long touchVal = touchRead(touchPins[currentMole]); bool currentTouchState = (touchVal > touchThresholds[currentMole]); // Debug output to help calibrate thresholds Serial.printf("Mole %d - Touch value: %ld (threshold: %ld) - %s\n", currentMole, touchVal, touchThresholds[currentMole], currentTouchState ? "TOUCHED" : "not touched"); // Only trigger on a new touch (edge detection) if (currentTouchState && !lastTouchState) { Serial.printf("Hit mole %d! Score: %d -> %d\n", currentMole, score, score + 1); // Hide the hit mole immediately servos[currentMole].write(hideAngle); score++; // Update high score if (score > highScore) { highScore = score; } // Reset touch state lastTouchState = false; // Brief delay for visual feedback and debouncing delay(300); // Spawn the next mole spawnNewMole(); } else { lastTouchState = currentTouchState; } delay(50); // Small delay to prevent overwhelming serial output } void spawnNewMole() { // Ensure all servos are hidden first for (int i = 0; i < numMoles; i++) { servos[i].write(hideAngle); } // Small delay to ensure servos have moved delay(200); // Select next mole (different from current one) int nextMole; do { nextMole = random(numMoles); } while (nextMole == currentMole && numMoles > 1); // Avoid repeating if possible // Update current mole and pop it up currentMole = nextMole; servos[currentMole].write(popUpAngle); // Reset touch state when spawning new mole lastTouchState = false; Serial.printf("Mole %d popped up!\n", currentMole); } void hideAllMoles() { for (int i = 0; i < numMoles; i++) { servos[i].write(hideAngle); } currentMole = -1; } void stopGame() { gameRunning = false; hideAllMoles(); } void handleStart() { if (!gameRunning) { score = 0; gameRunning = true; gameStartTime = millis(); spawnNewMole(); } server.sendHeader("Location", "/"); server.send(302, "text/plain", ""); } void handleStop() { if (gameRunning) { stopGame(); } server.sendHeader("Location", "/"); server.send(302, "text/plain", ""); } void handleRoot() { unsigned long remaining = 0; if (gameRunning) { unsigned long elapsed = millis() - gameStartTime; if (elapsed < gameDuration) { remaining = (gameDuration - elapsed) / 1000; } } String html = "" "" ""; html += "

Whack-a-Mole

"; html += "

Score: " + String(score) + "

"; html += "

High Score: " + String(highScore) + "

"; html += "

Current Mole: " + (currentMole == -1 ? "None" : String(currentMole + 1)) + "

"; if (gameRunning) { html += "

Time Remaining: " + String(remaining) + " seconds

"; html += "

"; } else { html += "

"; } html += ""; server.send(200, "text/html", html); }