diff --git a/src/main.cpp b/src/main.cpp
index f5ce14097e7165d4b2f2b870a8ae9a6685bc7412..929b5842bab179c824fdc07b8b7030c520c8af3f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -21,16 +21,25 @@ void handleButton();
 Task taskButton(TASK_IMMEDIATE, TASK_FOREVER, &handleButton);
 void handleStep();
 Task taskStep(25, TASK_FOREVER, &handleStep);
-void handleInternalLostAnimation();
-Task taskInternalLostAnimation(10, 100, &handleInternalLostAnimation);
-void handleExternalLostAnimation();
-Task taskExternalLostAnimation(10, 100, &handleExternalLostAnimation);
+void handleInternalMissedAnimation();
+Task taskInternalMissedAnimation(10, 100, &handleInternalMissedAnimation);
+void handleExternalMissedAnimation();
+Task taskExternalMissedAnimation(10, 100, &handleExternalMissedAnimation);
+void handleExternalWinAnimation();
+Task taskExternalWinAnimation(8, 2000, &handleExternalWinAnimation);
+void handleInternalWinAnimation();
+Task taskInternalWinAnimation(8, 2000, &handleInternalWinAnimation);
+void handleBlinkPoint();
+Task taskBlinkPoint(300, TASK_FOREVER, &handleBlinkPoint);
 
-void doneLostAnimation();
+void doneMissedAnimation();
+void doneWinAnimation();
 void internalMissed();
 void externalMissed();
 
 void setup() {
+  randomSeed(analogRead(0));
+
   pinMode(LED_BUILTIN, OUTPUT);
 
   pinMode(EXTERNAL_BUTTON_PIN_A, OUTPUT);
@@ -47,10 +56,17 @@ void setup() {
   taskButton.enable();
   scheduler.addTask(taskStep);
   taskStep.enable();
-  scheduler.addTask(taskExternalLostAnimation);
-  taskExternalLostAnimation.setOnDisable(&doneLostAnimation);
-  scheduler.addTask(taskInternalLostAnimation);
-  taskInternalLostAnimation.setOnDisable(&doneLostAnimation);
+  scheduler.addTask(taskExternalMissedAnimation);
+  taskExternalMissedAnimation.setOnDisable(&doneMissedAnimation);
+  scheduler.addTask(taskInternalMissedAnimation);
+  taskInternalMissedAnimation.setOnDisable(&doneMissedAnimation);
+
+  scheduler.addTask(taskExternalWinAnimation);
+  taskExternalWinAnimation.setOnDisable(&doneWinAnimation);
+  scheduler.addTask(taskInternalWinAnimation);
+  taskInternalWinAnimation.setOnDisable(&doneWinAnimation);
+  scheduler.addTask(taskBlinkPoint);
+  taskBlinkPoint.enable();
 }
 
 void loop() {
@@ -60,18 +76,38 @@ void loop() {
 int position = 0;
 int greenLength = 10;
 bool singlePlayer = true;
+int pointsInternal = 0;
+int pointsExternal = 0;
+bool lastPointInternal = false;
+bool hideLastPoint = false;
 
 #define STATE_PAUSE 0
 #define STATE_FORWARD 1
 #define STATE_BACKWARD 2
-#define STATE_LOST 3;
+#define STATE_MISSED 3;
+#define STATE_WIN 4;
 int state = STATE_PAUSE;
 
 void show() {
-  for (int i = 0; i < NEOPIXEL_LEN; i++) {
-    pixels.setPixelColor(i, 0);
-  }
-  if (state == STATE_FORWARD || state == STATE_BACKWARD) {
+  pixels.clear();
+  if (state == STATE_PAUSE) {
+    int points = pointsInternal;
+    if (lastPointInternal && hideLastPoint) {
+      points = max(0, points - 1);
+    }
+    for (int i = 0; i < points; i++) {
+      pixels.setPixelColor(i, 0xFFFF00);
+    }
+    
+    points = pointsExternal;
+    if (!lastPointInternal && hideLastPoint) {
+      points = max(0, points - 1);
+    }
+    for (int i = NEOPIXEL_LEN - 1 - points; i < NEOPIXEL_LEN; i++) {
+      pixels.setPixelColor(i, 0xFFFF00);
+    }
+  
+  } else if (state == STATE_FORWARD || state == STATE_BACKWARD) {
     for (int i = 0; i < greenLength; i++) {
       pixels.setPixelColor(i, 0x00FF00);
     }
@@ -91,8 +127,9 @@ void show() {
 
 int currentRound = 0;
 #define MAX_LEVEL 10
-int greenLengths[] =  {10,10, 9, 8, 7, 6, 5, 5, 4, 4, 3};
-int stepIntervals[] = {25,25,20,18,16,14,12,10,10,10,10};
+#define NUM_LEVEL (MAX_LEVEL + 1)
+int greenLengths[NUM_LEVEL] =  {10,10, 9, 8, 7, 6, 5, 5, 4, 4, 3};
+int stepIntervals[NUM_LEVEL] = {25,25,20,18,16,14,12,10,10,10,10};
 
 void setRound(int newRound) {
   currentRound = newRound;
@@ -160,22 +197,18 @@ void handleButton() {
   singlePlayer = digitalRead(EXTERNAL_BUTTON_PIN_NO) == LOW;
 }
 
-void handleExternalLostAnimation() {
-    int step = (100 - taskExternalLostAnimation.getIterations()) % 25;
-    for (int i = 0; i < NEOPIXEL_LEN; i++) {
-      pixels.setPixelColor(i, 0);
-    }
+void handleExternalMissedAnimation() {
+    int step = (100 - taskExternalMissedAnimation.getIterations()) % 25;
+    pixels.clear();
     for (int i = NEOPIXEL_LEN - 1 - 25; i < NEOPIXEL_LEN - 25 + step; i++) {
       pixels.setPixelColor(i, 0xFF0000);
     }
     pixels.show();
 }
 
-void handleInternalLostAnimation() {
-    int step = (100 - taskInternalLostAnimation.getIterations()) % 25;
-    for (int i = 0; i < NEOPIXEL_LEN; i++) {
-      pixels.setPixelColor(i, 0);
-    }
+void handleInternalMissedAnimation() {
+    int step = (100 - taskInternalMissedAnimation.getIterations()) % 25;
+    pixels.clear();
     for (int i = 25 - step; i < 25; i++) {
       pixels.setPixelColor(i, 0xFF0000);
     }
@@ -183,21 +216,31 @@ void handleInternalLostAnimation() {
 }
 
 void externalMissed() {
-  state = STATE_LOST;
-  taskExternalLostAnimation.restart();
+  state = STATE_MISSED;
+  pointsInternal += 1;
+  lastPointInternal = true;
+  taskExternalMissedAnimation.restart();
 }
 
 void internalMissed() {
-  state = STATE_LOST;
-  taskInternalLostAnimation.restart();
+  state = STATE_MISSED;
+  pointsExternal += 1;
+  lastPointInternal = false;
+  taskInternalMissedAnimation.restart();
 }
 
-void doneLostAnimation() {
+void doneMissedAnimation() {
   state = STATE_PAUSE;
+  if (pointsExternal >= 7) {
+    state = STATE_WIN;
+    taskExternalWinAnimation.restart();
+  } else if (pointsInternal >= 7) {
+    state = STATE_WIN;
+    taskInternalWinAnimation.restart();
+  }
 }
 
 void handleStep() {
-  unsigned long now = millis();
   switch (state) {
     case STATE_PAUSE:
       show();
@@ -228,3 +271,96 @@ void handleStep() {
       break;
   }
 }
+
+void handleBlinkPoint() {
+  hideLastPoint = !hideLastPoint;
+}
+
+#define NUM_WIN_POSITIONS 10
+int winPositions[NUM_WIN_POSITIONS] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
+uint32_t winColors[NUM_WIN_POSITIONS];
+int winLengths[NUM_WIN_POSITIONS];
+int untilSpawn = 0;
+
+#define NUM_COLORS 6
+uint32_t colors[NUM_COLORS] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFF00};
+
+void setPixelAnimation(int i, uint32_t color, bool reverse) {
+  if (reverse) {
+    i = NEOPIXEL_LEN - 1 - i;
+  }
+  pixels.setPixelColor(i, color);
+}
+
+void handleWinAnimation(bool external) {
+  // progress
+  for (int i = 0; i < NUM_WIN_POSITIONS; i++) {
+    if (winPositions[i] >= 0) {
+      if (winLengths[i] == 0) {
+        winPositions[i] += 1;
+        if (winPositions[i] > 30 && random(10) == 0) {
+          winLengths[i] += 1;
+        }
+      } else if (winLengths[i] > 0) {
+        winLengths[i] += 1;
+        if (winLengths[i] >= 10 && random(10) == 0) {
+          winPositions[i] = -1;
+          winLengths[i] = 0;
+        }
+      }
+    }
+  }
+  // spawn
+  if (untilSpawn <= 0 && random(10) == 0) {
+    for (int i = 0; i < NUM_WIN_POSITIONS; i++) {
+      if (winPositions[i] == -1) {
+        winPositions[i] = 7;
+        winLengths[i] = 0;
+        winColors[i] = colors[random(NUM_COLORS)];
+        break;
+      }
+    }
+    untilSpawn = 22;
+  }
+  untilSpawn -= 1;
+  // show
+  pixels.clear();
+  for (int i = 0; i < NUM_WIN_POSITIONS; i++) {
+    if (winPositions[i] >= 0) {
+      if (winLengths[i] == 0) {
+        setPixelAnimation(winPositions[i], 0xFFFF00, external);
+      } else {
+        for (int k = winLengths[i]; k > 0; k -= 10) {
+          setPixelAnimation(winPositions[i] - k, winColors[i], external);
+          setPixelAnimation(winPositions[i] + k, winColors[i], external);
+        }
+      }
+    }
+  }
+  // show points
+  for (int i = 0; i < pointsInternal; i++) {
+    pixels.setPixelColor(i, 0xFFFF00);
+  }
+  for (int i = NEOPIXEL_LEN - 1 - pointsExternal; i < NEOPIXEL_LEN; i++) {
+    pixels.setPixelColor(i, 0xFFFF00);
+  }
+  pixels.show();
+}
+
+void handleExternalWinAnimation() {
+  handleWinAnimation(true);
+} 
+
+void handleInternalWinAnimation() {
+  handleWinAnimation(false);
+}
+
+void doneWinAnimation() {
+  pointsExternal = 0;
+  pointsInternal = 0;
+  lastPointInternal = false;
+  state = STATE_PAUSE;
+  for (int i = 0; i < NUM_WIN_POSITIONS; i++) {
+    winPositions[i] = -1;
+  }
+}