Initial commit
[vexed] / playfield.cpp
diff --git a/playfield.cpp b/playfield.cpp
new file mode 100644 (file)
index 0000000..2f4e381
--- /dev/null
@@ -0,0 +1,187 @@
+#include "playfield.h"
+#include <stdio.h>
+PlayField::PlayField(const QString &_title, const QString &_board, const QString &_solution):title(_title),solution(_solution)
+{
+    for(int w=0;w<PF::FIELD_WIDTH;w++)
+        for(int h=0;h<PF::FIELD_HEIGHT;h++)
+            field[w][h]=PF::CELL_WALL;
+    QStringList rows=_board.split("/");
+    QListIterator<QString> rowI(rows);
+    int h=0;
+    while(rowI.hasNext())
+    {
+        QString row=rowI.next();
+        int w=0;
+        for(int i=0;i<row.size();i++)
+        {
+            char ch=row[i].toAscii();
+            int c=0;
+            while(ch>='0' && ch<='9')
+            {
+                c=c*10+ch-'0';
+                ch=row[++i].toAscii();
+                if(i>=row.size()) break;
+            }
+            w+=c;
+            if(ch=='~')
+            {
+                field[w++][h]=PF::CELL_EMPTY;
+            }
+            if(ch>='a' && ch <= 'h')
+            {
+                field[w++][h]=ch-'a'+2;
+            }
+        }
+        h++;
+    }
+}
+
+void PlayField::move(int w, int h, int w_new)
+{
+        if((w_new < 0) ||
+           (w_new >= PF::FIELD_WIDTH) || w == w_new)
+        {
+                return;
+        }
+        if(get(w,h)==PF::CELL_EMPTY ||
+           get(w,h)==PF::CELL_WALL)
+        {
+                return;
+        }
+        int d=w>w_new?-1:1;
+
+        Field temp;
+        int movesTemp=moves;
+        copy(field,temp);
+
+        bool moved=false;
+        bool cont;
+
+        int h_below=h+1;
+        do
+        {            
+            cont=moveBlock(w,h,d,0);
+            w+=d;
+            if(cont){
+                moves++;
+                moved=true;
+            }//if coordination has changed, inc the moves
+        } while(cont && (w!=w_new) && ((h_below >= PF::FIELD_HEIGHT) || get(w,h_below)!=PF::CELL_EMPTY));
+        do
+        {
+            cont=false;
+            cont|=checkGlobalFall();
+            cont|=checkTouch();
+        } while(cont);
+        if(moved)
+        {
+            if(totalUndo<PF::MAX_UNDO) totalUndo++;
+            copy(temp,undos[currentUndo]);
+            undoMade[currentUndo]=movesTemp;
+            currentUndo=(currentUndo + 1) % PF::MAX_UNDO;
+        }
+}
+
+bool PlayField::moveBlock(int w, int h, int dw, int dh)
+{
+    int wn=w+dw;
+    int hn=h+dh;
+
+    if(wn<0 || wn >= PF::FIELD_WIDTH || hn < 0 || hn >= PF::FIELD_HEIGHT)
+        return false;
+
+    if(get(wn,hn)!=PF::CELL_EMPTY)
+        return false;
+    set(wn, hn, get(w,h));
+    set(w,h,PF::CELL_EMPTY);
+    emit cellMoved(w,h,wn,hn);
+    return true;
+}
+bool PlayField::checkGlobalFall()
+{
+    bool fall;
+    bool fallen=false;
+    do
+    {
+        fall=false;
+        for(int w=0;w<PF::FIELD_WIDTH;w++)
+            for(int h=0;h<PF::FIELD_HEIGHT;h++)
+                if(checkFall(w,h))
+                {
+                    if(moveBlock(w,h,0,1))
+                    {
+                        fall=true;
+                        fallen=true;
+                    }
+                }
+    } while(fall);
+    return fallen;
+}
+
+bool PlayField::checkFall(int w, int h)
+{
+    int cell=get(w,h);
+    return (cell!=PF::CELL_EMPTY) &&
+            (cell!=PF::CELL_WALL) &&
+            (h!=(PF::FIELD_HEIGHT-1)) &&
+            (get(w,h+1)==PF::CELL_EMPTY);
+}
+bool PlayField::checkTouch()
+{
+    int toHide[PF::FIELD_WIDTH][PF::FIELD_HEIGHT];
+
+    for (int w = 0; w < PF::FIELD_WIDTH; w++) {
+            for (int h = 0; h < PF::FIELD_HEIGHT; h++) {
+                    toHide[w][h] = PF::CELL_EMPTY;
+                    if ((get(w,h) != PF::CELL_EMPTY) && (get(w,h)!=PF::CELL_WALL)) {
+                            if (h != 0) {
+                                    toHide[w][h] |= (get(w,h-1) == get(w,h));
+                            }
+                            if (h != PF::FIELD_HEIGHT - 1) {
+                                    toHide[w][h] |= (get(w,h+1) == get(w,h));
+                            }
+                            if (w != 0) {
+                                    toHide[w][h] |= (get(w-1,h) == get(w,h));
+                            }
+                            if (w != PF::FIELD_WIDTH - 1) {
+                                    toHide[w][h] |= (get(w+1,h) == get(w,h));
+                            }
+                    }
+            }
+    }
+
+    bool touched=false;
+    for (int w = 0; w < PF::FIELD_WIDTH; w++) {
+            for (int h = 0; h < PF::FIELD_HEIGHT; h++) {
+                    if(toHide[w][h])
+                    {
+                            set(w,h,PF::CELL_EMPTY);
+                            emit cellGone(w,h);
+                            touched=true;
+                    }
+            }
+    }
+    return touched;
+}
+
+bool PlayField::checkSolved()
+{
+        for(int w=0;w<PF::FIELD_WIDTH-1;w++)
+                for(int h=0;h<PF::FIELD_HEIGHT-1;h++)
+                {
+                        int cell=get(w,h);
+                        if((cell!=PF::CELL_EMPTY) && (cell!=PF::CELL_WALL)) return false;
+                }
+        return true;
+}
+
+void PlayField::undo()
+{
+    if(totalUndo > 0)
+    {
+        totalUndo--;
+        currentUndo=(currentUndo - 1 + PF::MAX_UNDO) % PF::MAX_UNDO;
+        copy(undos[currentUndo],field);
+        moves=undoMade[currentUndo];
+    }
+}