cedric pushed a commit to branch master.

commit 97c64195961677d6953ee794109450c91082df26
Author: Cedric BAIL <[email protected]>
Date:   Fri Mar 22 19:12:29 2013 +0900

    elemines: implement an Eina_Iterator for walking the matrix.
    
    I was clearly a little bit lazy of not wanting to implement first, but
    definitively the code is more readable with it. This should serve as an
    example on how to write your own iterator in your application.
---
 src/elemines.h |  20 +++++++---
 src/game.c     |  85 +++++++++++++++++++++++-------------------
 src/init.c     | 102 ++++++++++++++++++++++++++------------------------
 src/main.c     | 116 ++++++++++++++++++++++++++++++++++++++++++++-------------
 4 files changed, 205 insertions(+), 118 deletions(-)

diff --git a/src/elemines.h b/src/elemines.h
index a0278df..71bb2e9 100644
--- a/src/elemines.h
+++ b/src/elemines.h
@@ -59,8 +59,11 @@
 #define STANDARD "Standard"
 #define CUSTOM "Custom"
 
+typedef struct _Elemines_Cell Elemines_Cell;
+typedef struct _Elemines_Walker Elemines_Walker;
+
 /* structure to hold datas for each cell */
-struct cell_struct {
+struct _Elemines_Cell {
    unsigned char neighbours : 4;  /* (0-8, 9 for bomb) */
    Eina_Bool mine : 1;            /* (0/1) */
    Eina_Bool flag : 1;            /* (0/1) */
@@ -68,7 +71,7 @@ struct cell_struct {
 };
 
 /* main matrix of data */
-extern struct cell_struct matrix[SIZE_X+2][SIZE_Y+2];
+extern Elemines_Cell matrix[SIZE_X+2][SIZE_Y+2];
 
 /* global variables */
 struct ui_struct {
@@ -105,17 +108,24 @@ struct game_struct {
    struct clock_struct clock;
    struct trophy_struct trophy;
 };
+
 struct game_struct game;
 
+struct _Elemines_Walker
+{
+   Elemines_Cell *cell;
+   const char *target;
+   unsigned char x;
+   unsigned char y;
+};
+
 /* global functions */
 void show_help(void);
 void show_version(void);
 void init(void *data, Evas_Object *obj, void *event_info);
 Eina_Bool gui(char *theme, Eina_Bool fullscreen);
 void _click(void *data, Evas_Object *obj, const char *emission, const char 
*source);
-void _walk(unsigned char x, unsigned char y, unsigned char w, unsigned char h,
-           void (*callback)(const char *target, unsigned char x, unsigned char 
y, void *data),
-           const void *data);
+Eina_Iterator *_walk(unsigned char x, unsigned char y, unsigned char w, 
unsigned char h);
 
 #endif
 
diff --git a/src/game.c b/src/game.c
index 6e82200..38de35d 100644
--- a/src/game.c
+++ b/src/game.c
@@ -94,30 +94,10 @@ _timer(void *data __UNUSED__)
 }
 
 static void
-_finish_grid(const char *target, unsigned char x, unsigned char y, void *data)
-{
-   Eina_Bool *win = data;
-   char tmp[128];
-
-   if (*win == EINA_TRUE)
-     {
-        sprintf(tmp, "%s:win", target);
-     }
-   else
-     {
-        if (matrix[x][y].mine == 1)
-          {
-             sprintf(tmp, "%s:bomb", target);
-             elm_object_signal_emit(game.ui.table, tmp, "");
-          }
-        sprintf(tmp, "%s:lose", target);
-     }
-   elm_object_signal_emit(game.ui.table, tmp, "");
-}
-
-static void
 _finish(const char *target, Eina_Bool win)
 {
+   Elemines_Walker *walker;
+   Eina_Iterator *it;
    Evas_Object *edje;
    int score;
    char str[255];
@@ -129,7 +109,25 @@ _finish(const char *target, Eina_Bool win)
    edje_object_signal_callback_del_full(edje, "mouse,clicked,*", 
"board\\[*\\]:overlay", _click, NULL);
 
    /* show bombs */
-   _walk(1, 1, SIZE_X, SIZE_Y, _finish_grid, &win);
+   it = _walk(1, 1, SIZE_X, SIZE_Y);
+   EINA_ITERATOR_FOREACH(it, walker)
+     {
+        if (win == EINA_TRUE)
+          {
+             sprintf(str, "%s:win", walker->target);
+          }
+        else
+          {
+             if (walker->cell->mine == 1)
+               {
+                  sprintf(str, "%s:bomb", walker->target);
+                  elm_object_signal_emit(game.ui.table, str, "");
+               }
+             sprintf(str, "%s:lose", walker->target);
+          }
+        elm_object_signal_emit(game.ui.table, str, "");
+     }
+   eina_iterator_free(it);
 
    /* highlight the fatal bomb */
    if (win == EINA_FALSE)
@@ -168,7 +166,7 @@ _finish(const char *target, Eina_Bool win)
 }
 
 static void
-_clean_walk(const char *target, unsigned char x, unsigned char y, void *data 
EINA_UNUSED)
+_clean_walk(const char *target, unsigned char x, unsigned char y)
 {
    /* we are out of board */
    if (x == 0 || x == SIZE_X+1 || y == 0 || y == SIZE_Y+1)
@@ -211,7 +209,13 @@ _clean_walk(const char *target, unsigned char x, unsigned 
char y, void *data EIN
         /* no neighbour */
         else
           {
-             _walk(x - 1, y - 1, 3, 3, _clean_walk, NULL);
+             Elemines_Walker *walker;
+             Eina_Iterator *it;
+
+             it =  _walk(x - 1, y - 1, 3, 3);
+             EINA_ITERATOR_FOREACH(it, walker)
+               _clean_walk(walker->target, walker->x, walker->y);
+             eina_iterator_free(it);
           }
         /* keep track of this empty spot */
         game.datas.counter--;
@@ -225,15 +229,6 @@ _clean_walk(const char *target, unsigned char x, unsigned 
char y, void *data EIN
    return;   
 }
 
-static void
-_flags_count(const char *target EINA_UNUSED, unsigned char x, unsigned char y, 
void *data)
-{
-   int *flags = data;
-
-   if (matrix[x][y].flag == 1)
-     (*flags)++;
-}
-
 void
 _click(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char 
*emission, const char *source)
 {
@@ -254,7 +249,7 @@ _click(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, const char *emissio
           }
 
         sprintf(str, "board[%i/%i]", x, y);
-        _clean_walk(str, x, y, NULL);
+        _clean_walk(str, x, y);
      }
 
    /* second button: put a flag */
@@ -286,15 +281,29 @@ _click(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, const char *emissio
    /* middle button: open rest if we have enough mines */
    if (!strcmp(emission, "mouse,clicked,2") && (matrix[x][y].uncover == 1) )
      {
+        Elemines_Walker *walker;
+        Eina_Iterator *it;
         int flags = 0;
 
         /* count surrounding flags */
-        _walk(x - 1, y - 1, 3, 3, _flags_count, &flags);
-        if (matrix[x][y].flag == 1) flags--;
+        it = _walk(x - 1, y - 1, 3, 3);
+        EINA_ITERATOR_FOREACH(it, walker)
+          {
+             if (walker->x == x && walker->y == y)
+               continue ;
+             if (walker->cell->flag == 1)
+               flags++;
+          }
+        eina_iterator_free(it);
 
         /* open surrounding squares if correct number of flags is set */
         if (flags == matrix[x][y].neighbours)
-          _walk(x - 1, y - 1, 3, 3, _clean_walk, NULL);
+          {
+             it = _walk(x - 1, y - 1, 3, 3);
+             EINA_ITERATOR_FOREACH(it, walker)
+               _clean_walk(walker->target, walker->x, walker->y);
+             eina_iterator_free(it);
+          }
      }
 }
 
diff --git a/src/init.c b/src/init.c
index 42002a3..8951917 100644
--- a/src/init.c
+++ b/src/init.c
@@ -28,35 +28,13 @@
 
 #include "elemines.h"
 
-struct cell_struct matrix[SIZE_X+2][SIZE_Y+2];
-
-static void
-_mine_count(const char *target EINA_UNUSED, unsigned char x, unsigned char y, 
void *data)
-{
-   int *count = data;
-
-   if (matrix[x][y].mine)
-     (*count)++;
-}
-
-static void
-_update_mine_count(const char *target EINA_UNUSED, unsigned char x, unsigned 
char y, void *data EINA_UNUSED)
-{
-   int neighbours = 9;
-
-   /* mark a mine place with a 9 */
-   if (!matrix[x][y].mine)
-     {
-        neighbours = 0;
-        _walk(x - 1, y - 1, 3, 3, _mine_count, &neighbours);
-     }
-
-   matrix[x][y].neighbours = neighbours;
-}
+Elemines_Cell matrix[SIZE_X+2][SIZE_Y+2];
 
 static Eina_Bool
 _generate(void)
 {
+   Elemines_Walker *walker;
+   Eina_Iterator *it;
    int i, x, y;
 
    /* empty the matrix */
@@ -77,36 +55,39 @@ _generate(void)
      }
 
    /* 2nd table: neighbours */
-   _walk(1, 1, SIZE_X, SIZE_Y, _update_mine_count, NULL);
-   return EINA_TRUE;
-}
-
-static void
-_reset(const char *target, unsigned char x EINA_UNUSED, unsigned char y 
EINA_UNUSED, void *data EINA_UNUSED)
-{
-   char tmp[128];
-   int scenery;
-
-   sprintf(tmp, "%s:reset", target);
-   elm_object_signal_emit(game.ui.table, tmp, "");
-
-   /* add some random scenery */
-   scenery = (int)((double)100 * rand() / RAND_MAX + 1);
-   if (scenery < 15)
+   it = _walk(1, 1, SIZE_X, SIZE_Y);
+   EINA_ITERATOR_FOREACH(it, walker)
      {
-        sprintf(tmp, "%s:flowers", target);
-        elm_object_signal_emit(game.ui.table, tmp, "");
-     }
-   if ((scenery > 12) && (scenery < 18))
-     {
-        sprintf(tmp, "%s:mushrooms", target);
-        elm_object_signal_emit(game.ui.table, tmp, "");
+        int neighbours = 9;
+
+        /* mark a mine place with a 9 */
+        if (!walker->cell->mine)
+          {
+             Elemines_Walker *walkerc;
+             Eina_Iterator *itc;
+
+             neighbours = 0;
+             itc = _walk(walker->x - 1, walker->y - 1, 3, 3);
+             EINA_ITERATOR_FOREACH(itc, walkerc)
+               {
+                  if (walkerc->cell->mine)
+                    neighbours++;
+               }
+             eina_iterator_free(itc);
+          }
+
+        walker->cell->neighbours = neighbours;
      }
+   eina_iterator_free(it);      
+
+   return EINA_TRUE;
 }
 
 static Eina_Bool
 _board(void)
 {
+   Elemines_Walker *walker;
+   Eina_Iterator *it;
    Evas_Object *edje;
 
    edje = elm_layout_edje_get(game.ui.table);
@@ -116,7 +97,30 @@ _board(void)
    edje_object_signal_callback_add(edje, "mouse,clicked,*", 
"board\\[*\\]:overlay", _click, NULL);
 
    /* prepare the board */
-   _walk(1, 1, SIZE_X, SIZE_Y, _reset, NULL);
+   it = _walk(1, 1, SIZE_X, SIZE_Y);
+   EINA_ITERATOR_FOREACH(it, walker)
+     {
+        char tmp[128];
+        int scenery;
+
+        sprintf(tmp, "%s:reset", walker->target);
+        elm_object_signal_emit(game.ui.table, tmp, "");
+
+        /* add some random scenery */
+        scenery = (int)((double)100 * rand() / RAND_MAX + 1);
+        if (scenery < 15)
+          {
+             sprintf(tmp, "%s:flowers", walker->target);
+             elm_object_signal_emit(game.ui.table, tmp, "");
+          }
+        if ((scenery > 12) && (scenery < 18))
+          {
+             sprintf(tmp, "%s:mushrooms", walker->target);
+             elm_object_signal_emit(game.ui.table, tmp, "");
+          }
+     }
+   eina_iterator_free(it);
+
    return EINA_TRUE;
 }
 
diff --git a/src/main.c b/src/main.c
index 3640d3b..0e284e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,55 +26,119 @@
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <Eina.h>
 #include <Ecore_Getopt.h>
 
 #include "elemines.h"
 
-// This would have been cleaner with an Eina_Iterator
-void
-_walk(unsigned char x, unsigned char y, unsigned char w, unsigned char h,
-      void (*callback)(const char *target, unsigned char x, unsigned char y, 
void *data),
-      const void *data)
+typedef struct _Elemines_Iterator Elemines_Iterator;
+struct _Elemines_Iterator
 {
-   unsigned char i;
-   unsigned char j;
+   Eina_Iterator iterator;
+
+   Elemines_Walker walker;
+
+   unsigned char col;
+   unsigned char row;
+   unsigned char x;
+   unsigned char y;
+   unsigned char width;
+   unsigned char height;
+};
+
+static Eina_Bool
+_walk_iterator_next(Elemines_Iterator *it, void **data)
+{
+   if (!(it->col < it->x + it->width &&
+         it->row < it->y + it->height))
+     return EINA_FALSE;
+
+   *data = &it->walker;
 
-   for (j = y; j < y + h; j++)
-     for (i = x; i < x + w; i++)
-       {
-          char tmp[128];
+   it->walker.cell = &matrix[it->col][it->row];
+   it->walker.x = it->col;
+   it->walker.y = it->row;
+   sprintf((char*) it->walker.target, "board[%i/%i]", it->walker.x, 
it->walker.y);
 
-          sprintf(tmp, "board[%i/%i]", i, j);
-          callback(tmp, i, j, (void*) data);
-       }
+   it->col++;
+   if (it->col == it->x + it->width)
+     {
+        it->col = it->x;
+        it->row++;
+     }
+
+   return EINA_TRUE;
 }
 
-static unsigned char prev_y = 0;
-static void
-_printf_mine(const char *target EINA_UNUSED, unsigned char x, unsigned char y, 
void *data EINA_UNUSED)
+static void *
+_walk_iterator_container(Elemines_Iterator *it EINA_UNUSED)
 {
-   if (prev_y != y) printf("\n");
-   printf("%d ", matrix[x][y].mine);
-   prev_y = y;
+   return matrix;
 }
 
 static void
-_printf_neighbours(const char *target EINA_UNUSED, unsigned char x, unsigned 
char y, void *data EINA_UNUSED)
+_walk_iterator_free(Elemines_Iterator *it)
 {
-   if (prev_y != y) printf("\n");
-   printf("%d ", matrix[x][y].neighbours);
-   prev_y = y;
+   EINA_MAGIC_SET(&it->iterator, 0);
+   free(it);
+}
+
+// This would have been cleaner with an Eina_Iterator
+Eina_Iterator *
+_walk(unsigned char x, unsigned char y, unsigned char w, unsigned char h)
+{
+   Elemines_Iterator *r;
+
+   r = calloc(1, sizeof (Elemines_Iterator) + strlen("board[00,00]") + 1);
+   if (!r) return NULL;
+
+   r->iterator.version = EINA_ITERATOR_VERSION;
+   r->iterator.next = FUNC_ITERATOR_NEXT(_walk_iterator_next);
+   r->iterator.get_container = 
FUNC_ITERATOR_GET_CONTAINER(_walk_iterator_container);
+   r->iterator.free = FUNC_ITERATOR_FREE(_walk_iterator_free);
+
+   EINA_MAGIC_SET(&r->iterator, EINA_MAGIC_ITERATOR);
+
+   r->col = x;
+   r->row = y;
+   r->x = x;
+   r->y = y;
+   r->width = w;
+   r->height = h;
+   r->walker.target = (char *) (r + 1);
+   r->walker.x = x;
+   r->walker.y = y;
+
+   return &r->iterator;
 }
 
 static void
 _debug(void)
 {
+   Eina_Iterator *it;
+   Elemines_Walker *walker;
+   unsigned char prev_y = 0;
+
    printf("== bomb positions =====\n");
-   _walk(0, 0, SIZE_X+2, SIZE_Y+2, _printf_mine, NULL);
+   it = _walk(0, 0, SIZE_X+2, SIZE_Y+2);
+   EINA_ITERATOR_FOREACH(it, walker)
+     {
+        if (prev_y != walker->y) printf("\n");
+        printf("%d ", walker->cell->mine);
+        prev_y = walker->y;
+     }
+   eina_iterator_free(it);
 
    printf("\n\n== neighbours count ===\n");
    prev_y = 0;
-   _walk(0, 0, SIZE_X+2, SIZE_Y+2, _printf_neighbours, NULL);
+   it = _walk(0, 0, SIZE_X+2, SIZE_Y+2);
+   EINA_ITERATOR_FOREACH(it, walker)
+     {
+        if (prev_y != walker->y) printf("\n");
+        printf("%d ", walker->cell->neighbours);
+        prev_y = walker->y;
+     }
+   eina_iterator_free(it);
    printf("\n");
 }
 

-- 

------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_mar

Reply via email to