[gnome-nibbles/arnaudb/fix-level-25: 8/8] Add collision tests.



commit 04c24927a71967ee9da951bd2f366eb72c9f64cd
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Mon Jun 22 19:27:57 2020 +0200

    Add collision tests.
    
    Also allows to finish level 25
    without the need to kill worm.

 src/nibbles-game.vala |  56 +++++++++-----
 src/nibbles-test.vala | 206 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/worm.vala         |  14 ----
 3 files changed, 235 insertions(+), 41 deletions(-)
---
diff --git a/src/nibbles-game.vala b/src/nibbles-game.vala
index 368e574..a3f8e46 100644
--- a/src/nibbles-game.vala
+++ b/src/nibbles-game.vala
@@ -390,40 +390,56 @@ private class NibblesGame : Object
             add_bonus (true);
 
         var dead_worms = new Gee.LinkedList<Worm> ();
+
+        /* make AIs decide what they will do */
         foreach (var worm in worms)
         {
-            if (worm.is_stopped)
-                continue;
-
-            if (worm.list.is_empty)
+            if (worm.is_stopped
+             || worm.list.is_empty)
                 continue;
 
             if (!worm.is_human)
                 worm.ai_move (board, numworms, worms);
+        }
 
-            foreach (var other_worm in worms)
-            {
-                if (worm != other_worm
-                    && !other_worm.is_stopped
-                    && worm.will_collide_with_head (other_worm))
-                    {
-                        if (!dead_worms.contains (worm))
-                            dead_worms.add (worm);
-                        if (!dead_worms.contains (other_worm))
-                            dead_worms.add (other_worm);
-                        continue;
-                    }
-            }
+        /* kill worms which are hitting wall */
+        foreach (var worm in worms)
+        {
+            if (worm.is_stopped
+             || worm.list.is_empty)
+                continue;
 
             if (!worm.can_move_to (board, numworms))
-            {
                 dead_worms.add (worm);
+        }
+
+        /* move worms */
+        foreach (var worm in worms)
+        {
+            if (worm.is_stopped
+             || worm.list.is_empty)
                 continue;
-            }
 
             worm.move (board);
+
+            /* kill worms on heads collision */
+            foreach (var other_worm in worms)
+            {
+                if (worm != other_worm
+                 && !other_worm.is_stopped
+                 && !other_worm.list.is_empty
+                 && worm.head.x == other_worm.head.x
+                 && worm.head.y == other_worm.head.y)
+                {
+                    if (!dead_worms.contains (worm))
+                        dead_worms.add (worm);
+                    if (!dead_worms.contains (other_worm))
+                        dead_worms.add (other_worm);
+                }
+            }
         }
 
+        /* remove dead worms */
         foreach (var worm in dead_worms)
         {
             if (numworms > 1)
@@ -619,6 +635,8 @@ private class NibblesGame : Object
                 worms_left += 1;
             else if (worm.is_human && worm.lives <= 0)
                 return GameStatus.GAMEOVER;
+            else if (numhumans == 0 && worm.lives <= 0)
+                return GameStatus.GAMEOVER;
         }
 
         if (worms_left == 1 && numworms > 1)
diff --git a/src/nibbles-test.vala b/src/nibbles-test.vala
index d28445b..a006bc4 100644
--- a/src/nibbles-test.vala
+++ b/src/nibbles-test.vala
@@ -27,6 +27,8 @@ namespace NibblesTest
                                  test_tests);
         Test.add_func ("/Nibbles/test games",
                                  test_games);
+        Test.add_func ("/Nibbles/test heads",
+                                 test_heads);
         return Test.run ();
     }
 
@@ -49,11 +51,16 @@ namespace NibblesTest
 
         game.load_board (level_008, /* regular bonus = 8 + numworms */ 12);
 
+        ulong [] worms_handlers = new ulong [game.worms.size];
+        foreach (Worm worm in game.worms)
+            // FIXME we should not have to connect to anything 1/2
+            worms_handlers [worm.id] = worm.finish_added.connect (() => { worm.dematerialize (game.board, 
3); worm.is_stopped = false; });
+
         assert_true (game.numworms == 4);
         assert_true (game.worms.size == 4);
 
         uint8 applied_bonus = 0;
-        game.bonus_applied.connect ((bonus, worm) => { applied_bonus++; Test.message (@"worm $(worm.id) took 
bonus at [$(bonus.x), $(bonus.y)]"); });
+        ulong game_handler_1 = game.bonus_applied.connect ((bonus, worm) => { applied_bonus++; Test.message 
(@"worm $(worm.id) took bonus at [$(bonus.x), $(bonus.y)]"); });
 
         game.add_worms ();
         game.start (/* add initial bonus */ true);
@@ -65,22 +72,27 @@ namespace NibblesTest
 
         // run until game is finished
         bool completed = false;
-        game.level_completed.connect (() => { completed = true; });
+        ulong game_handler_2 = game.level_completed.connect (() => { completed = true; });
         MainContext context = MainContext.@default ();
         while (!completed)
             context.iteration (/* may block */ false);
 
-        assert_true (applied_bonus == 17);
+        assert_true (applied_bonus == 15);
 
         assert_true (game.worms.@get (0).lives == 6);
-        assert_true (game.worms.@get (1).lives == 6);
+        assert_true (game.worms.@get (1).lives == 5);
         assert_true (game.worms.@get (2).lives == 6);
         assert_true (game.worms.@get (3).lives == 6);
 
-        assert_true (game.worms.@get (0).score == 14);
-        assert_true (game.worms.@get (1).score == 21);
-        assert_true (game.worms.@get (2).score == 37);
-        assert_true (game.worms.@get (3).score == 16);
+        assert_true (game.worms.@get (0).score ==  11);
+        assert_true (game.worms.@get (1).score ==  14);
+        assert_true (game.worms.@get (2).score == 119);
+        assert_true (game.worms.@get (3).score ==  19);
+
+        foreach (Worm worm in game.worms)
+            worm.disconnect (worms_handlers [worm.id]);
+        game.disconnect (game_handler_1);
+        game.disconnect (game_handler_2);
     }
 
     private const int level_008_width  = 92;
@@ -153,4 +165,182 @@ namespace NibblesTest
             "┃..........................................................................................┃",
             "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓........┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
         };
+
+    /*\
+    * * test heads
+    \*/
+
+    private static void test_heads ()
+    {
+        Test.message ("test heads 1");
+        _test_heads (test_heads_1, /* worm 0 */ 6, 4, /* worm 1 */ 11, 4, /* lives */ 6, 6);
+
+        Test.message ("test heads 2");
+        _test_heads (test_heads_2, /* worm 0 */ 6, 4, /* worm 1 */ 11, 4, /* lives */ 6, 5);
+
+        Test.message ("test heads 3");
+        _test_heads (test_heads_3, /* worm 0 */ 6, 4, /* worm 1 */ 10, 4, /* lives */ 6, 6);
+
+        Test.message ("test heads 4");
+        _test_heads (test_heads_4, /* worm 0 */ 6, 4, /* worm 1 */ 10, 4, /* lives */ 0, 0);
+
+        Test.message ("test heads 5");
+        _test_heads (test_heads_5, /* worm 0 */ 6, 1, /* worm 1 */  6, 4, /* lives */ 6, 6);
+
+        Test.message ("test heads 6");
+        _test_heads (test_heads_6, /* worm 0 */ 6, 1, /* worm 1 */  6, 4, /* lives */ 4, 6);
+
+        Test.message ("test heads 9");
+        _test_heads (test_heads_9, /* worm 0 */ 6, 1, /* worm 1 */  6, 4, /* lives */ 6, 5);
+
+        Test.message ("test heads 7");
+        _test_heads (test_heads_7, /* worm 0 */ 6, 2, /* worm 1 */  6, 4, /* lives */ 6, 6);
+
+        Test.message ("test heads 8");
+        _test_heads (test_heads_8, /* worm 0 */ 6, 2, /* worm 1 */  6, 4, /* lives */ 0, 0);
+
+        Test.message ("test heads 0");
+        _test_heads (test_heads_0, /* worm 0 */ 6, 2, /* worm 1 */  6, 4, /* lives */ 6, 6);
+    }
+
+    private static void _test_heads (string [] board,
+                                     int worm_0_x,
+                                     int worm_0_y,
+                                     int worm_1_x,
+                                     int worm_1_y,
+                                     int first_worm_lives,
+                                     int second_worm_lives)
+    {
+        NibblesGame game = new NibblesGame (/* start level */ 0, /* speed */ 0, /* fakes */ false, 
test_heads_width, test_heads_height, /* no random */ true);
+
+        game.numhumans = 0;
+        game.numai = 2;
+        game.create_worms ();
+
+        game.load_board (board, /* regular bonus */ 1);
+
+        ulong [] worms_handlers = new ulong [game.worms.size];
+        foreach (Worm worm in game.worms)
+            // FIXME we should not have to connect to anything 2/2
+            worms_handlers [worm.id] = worm.finish_added.connect (() => { worm.dematerialize (game.board, 
3); worm.is_stopped = false; });
+
+        assert_true (game.numworms == 2);
+        assert_true (game.worms.size == 2);
+
+        ulong game_handler_1 = game.bonus_applied.connect ((bonus, worm) => { Test.message (@"worm 
$(worm.id) took bonus at [$(bonus.x), $(bonus.y)]"); });
+
+        game.add_worms ();
+        game.start (/* add initial bonus */ true);
+
+        assert_true (game.worms.@get (0).lives == 6);
+        assert_true (game.worms.@get (1).lives == 6);
+
+        assert_true (game.worms.@get (0).score == 0);
+        assert_true (game.worms.@get (1).score == 0);
+
+        assert_true (game.worms.@get (0).head.x == worm_0_x && game.worms.@get (0).head.y == worm_0_y);
+        assert_true (game.worms.@get (1).head.x == worm_1_x && game.worms.@get (1).head.y == worm_1_y);
+
+        // run until game is finished
+        bool completed = false;
+        ulong game_handler_2 = game.level_completed.connect (() => { completed = true; });
+        MainContext context = MainContext.@default ();
+        do context.iteration (/* may block */ false);
+        while (!completed && (game.get_game_status () != GameStatus.GAMEOVER));
+
+        assert_true (game.worms.@get (0).lives == first_worm_lives);
+        assert_true (game.worms.@get (1).lives == second_worm_lives);
+
+        // FIXME looks like last bonus is not counted...
+        assert_true (game.worms.@get (0).score == 0);
+        assert_true (game.worms.@get (1).score == 0);
+
+        foreach (Worm worm in game.worms)
+            worm.disconnect (worms_handlers [worm.id]);
+        game.disconnect (game_handler_1);
+        game.disconnect (game_handler_2);
+    }
+
+    private const int test_heads_width = 18;
+    private const int test_heads_height = 6;
+    private const string [] test_heads_1 = {
+            "┏━━━━━━━━━━━━━━━━┓",
+            "┃................┃",
+            "┃................┃",
+            "┣━━━━━━━..━━━━━━━┫",
+            "┃▶..............◀┃",
+            "┗━━━━━━━━━━━━━━━━┛"
+        };  /* expected: 6, 6 */
+    private const string [] test_heads_2 = {
+            "┏━━━━━━━━━━━━━━━━┓",
+            "┃................┃",
+            "┃................┃",
+            "┣━━━━━━━.━━━━━━━━┫",
+            "┃▶..............◀┃",
+            "┗━━━━━━━━━━━━━━━━┛"
+        };  /* expected: 6, 5 */
+    private const string [] test_heads_3 = {
+            "┏━━━━━━━━━━━━━━━━┓",
+            "┃................┃",
+            "┃................┃",
+            "┣━━━━━━━..━━━━━━┳┫",
+            "┃▶.............◀┣┫",
+            "┗━━━━━━━━━━━━━━━┻┛"
+        };  /* expected: 6, 6 */
+    private const string [] test_heads_4 = {
+            "┏━━━━━━━━━━━━━━━━┓",
+            "┃................┃",
+            "┃................┃",
+            "┣━━━━━━━.━━━━━━━┳┫",
+            "┃▶.............◀┣┫",
+            "┗━━━━━━━━━━━━━━━┻┛"
+        };  /* expected: 0, 0 */
+    private const string [] test_heads_5 = {
+            "┏━━━━━━━┳━━━━━━━━┓",
+            "┃▶......┃........┃",
+            "┗━━━━━┓..........┃",
+            "┏━━━━━┛..........┃",
+            "┃▶......┃........┃",
+            "┗━━━━━━━┻━━━━━━━━┛"
+        };  /* expected: 6, 6 */
+    private const string [] test_heads_6 = {
+            "┏━━━━━━━┳━━━━━━━━┓",
+            "┃▶......┃........┃",
+            "┗━━━━━┓.┃........┃",
+            "┏━━━━━┛..........┃",
+            "┃▶......┃........┃",
+            "┗━━━━━━━┻━━━━━━━━┛"
+        };  /* expected: 4, 6 */
+    private const string [] test_heads_9 = {
+            "┏━━━━━━━┳━━━━━━━━┓",
+            "┃▶......┃........┃",
+            "┗━━━━━┓..........┃",
+            "┏━━━━━┛.┃........┃",
+            "┃▶......┃........┃",
+            "┗━━━━━━━┻━━━━━━━━┛"
+        };  /* expected: 6, 5 */
+    private const string [] test_heads_7 = {
+            "........┏━━━━━━━━┓",
+            "┏━━━━━━━┛........┃",
+            "┃▶...............┃",
+            "┣━━━━━━..........┃",
+            "┃▶......┃........┃",
+            "┗━━━━━━━┻━━━━━━━━┛"
+        };  /* expected: 6, 6 */
+    private const string [] test_heads_8 = {
+            "........┏━━━━━━━━┓",
+            "┏━━━━━━━┫........┃",
+            "┃▶......┃........┃",
+            "┣━━━━━━..........┃",
+            "┃▶......┃........┃",
+            "┗━━━━━━━┻━━━━━━━━┛"
+        };  /* expected: 0, 0 */
+    private const string [] test_heads_0 = {
+            "........┏━━━━━━━━┓",
+            "┏━━━━━━━┫........┃",
+            "┃▶......┃........┃",
+            "┣━━━━━━..........┃",
+            "┃▶...............┃",
+            "┗━━━━━━━━━━━━━━━━┛"
+        };  /* expected: 6, 6 */
 }
diff --git a/src/worm.vala b/src/worm.vala
index 445b160..94b2c6d 100644
--- a/src/worm.vala
+++ b/src/worm.vala
@@ -291,20 +291,6 @@ private class Worm : Object
         return true;
     }
 
-    internal bool will_collide_with_head (Worm other_worm)
-    {
-        if (!is_materialized || !other_worm.is_materialized)
-            return false;
-
-        var worm_pos = position_move ();
-        var other_worm_pos = other_worm.position_move ();
-
-        if (worm_pos == other_worm_pos)
-            return true;
-
-        return false;
-    }
-
     internal void spawn (int[,] board)
     {
         change = STARTING_LENGTH - 1;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]