Browse Source

Counting Squares initial repository

Jose Ortiz 8 years ago
commit
75c89c00fb
16 changed files with 857 additions and 0 deletions
  1. 217
    0
      README.md
  2. 31
    0
      countingSquares.pro
  3. 8
    0
      countingSquares.qrc
  4. BIN
      explosion.png
  5. 67
    0
      genericscrollingobject.cpp
  6. 45
    0
      genericscrollingobject.h
  7. BIN
      horse.jpeg
  8. BIN
      horse.png
  9. BIN
      images/cuarto.png
  10. BIN
      images/main1.png
  11. BIN
      images/main2.png
  12. BIN
      images/main3.png
  13. 45
    0
      main.cpp
  14. 378
    0
      maingamewindow.cpp
  15. 66
    0
      maingamewindow.h
  16. BIN
      robot.png

+ 217
- 0
README.md View File

@@ -0,0 +1,217 @@
1
+[English](#markdown-header-repetition-structures-robot-counting-squares) | [Español](#markdown-header-estructuras-de-repeticion-robot-cuenta-cuartos)
2
+
3
+#Estructuras de Repetición - Robot cuenta cuartos
4
+
5
+![main1.png](images/main1.png)
6
+![main2.png](images/main2.png)
7
+![main3.png](images/main3.png)
8
+
9
+Una de las ventajas de utilizar programas de computadoras es que podemos realizar tareas repetitivas fácilmente. Los ciclos como `for`, `while`, y `do-while` son  estructuras de control que nos permiten repetir un conjunto de instrucciones. A estas estructuras también se les llama *estructuras de repetición*.
10
+
11
+Los algoritmos son uno de los conceptos más fundamentales en la Ciencia de Cómputos. Dado un pequeño conjunto de instrucciones y las estructuras básicas de programación, podemos resolver una gran cantidad de problemas. En esta experiencia de laboratorio vas a practicar la creación de algoritmos simulando un robot que debe explorar un espacio utilizando un conjunto bien limitado de instrucciones.
12
+
13
+##Objetivos:
14
+
15
+1. Diseñar algoritmos usando estructuras secuenciales, de decisión y repetición.
16
+2. Analizar el número de pasos de los algoritmos propuestos y tratar de minimizarlos.
17
+3. Practicar la invocación de métodos a un objeto.
18
+
19
+Esta experiencia de laboratorio es una adaptación de http://nifty.stanford.edu/2015/tychonievich-sherriff-layer-counting-squares/ .
20
+
21
+
22
+##Pre-Lab:
23
+
24
+Antes de llegar al laboratorio debes haber:
25
+
26
+1. Repasado las estructuras básicas de decisión y repetición en C++.
27
+2. Repasado la creación de objetos e invocación de sus métodos.
28
+3. Estudiado los conceptos e instrucciones para la sesión de laboratorio.
29
+
30
+
31
+---
32
+
33
+---
34
+
35
+
36
+## Robot cuenta cuartos
37
+
38
+En esta experiencia de laboratorio estaremos programando un robot que ha sido puesto en una cuadrícula (grid) de habitaciones cuadradas. Cada una de las cuatro paredes de cada cuarto puede tener una puerta. Solo las paredes que colindan con otros cuartos tienen puertas. Las paredes que forman la parte exterior de la cuadrícula  no tienen puertas.
39
+
40
+---
41
+
42
+![](images/cuarto.png)
43
+
44
+**Figura 1.** El robot está en el cuarto en el extremo superior izquierdo de la cuadrícula de 36 cuartos.
45
+
46
+---
47
+
48
+Los únicos comandos que entiende el robot son:
49
+
50
+1. Verificar si hay una puerta en la pared del norte (N), sur (S), este (E) u oeste (W) del cuarto donde se encuentra.
51
+2. Moverse al cuarto que queda justo al norte (N), sur (S), este (E) u oeste (W) del cuarto actual.
52
+4. Crear variables y asignarle valores.
53
+3. Realizar operaciones suma, resta, multiplicación y resta.
54
+5. Usar estructuras de decisión y repetición.
55
+6. Desplegar resultados a pantalla.
56
+
57
+
58
+## Objetos y métodos
59
+
60
+A continuación mostramos la función `main` de un programa básico como el que estarás creando. Durante esta experiencia de laboratorio solo tienes que programar la función `main` (dentro del archivo `main.cpp`). Los demás archivos contienen funciones que implementan la funcionalidad de las instrucciones que entiende el robot.
61
+
62
+---
63
+
64
+```cpp
65
+int main(int argc, char *argv[]) {
66
+    QApplication   a(argc, argv);
67
+
68
+    // Crear la cuadrícula y robot
69
+    MainGameWindow *w = new MainGameWindow(Mode::RECT_RANDOM);
70
+    w->show();
71
+
72
+    // Mostrar la palabra "Start"
73
+    w->display("Start");
74
+
75
+    // Mover el robot hacia el oeste cuanto se pueda
76
+    // mientras contamos el número de movidas
77
+
78
+    int ctr = 0;
79
+    while (w->canMove('W')) {
80
+        w->moveRobot('W');
81
+        ctr = ctr + 1;
82
+    }
83
+
84
+    // Desplegar el total de movidas
85
+    w->display("Total: " + QString::number(ctr));
86
+
87
+    return a.exec();
88
+}
89
+
90
+```
91
+
92
+**Figura 2** Ejemplo de una función `main`.
93
+
94
+---
95
+
96
+En el ejemplo estamos creando un robot dentro de un espacio cuadrado que solo sabe verificar si hay una puerta hacia el oeste y (si hay puerta) caminar hacia esa misma dirección.  Veamos la función, línea por línea.
97
+
98
+La primera línea crea el único objeto que debes crear, un objeto de clase `MainGameWindow`. El parámetro `Mode::SQUARE_TOP_LEFT` especifica que la cuadrícula será cuadrada y que el robot comenzará en la esquina superior izquierda. Otras opciones para el parámetro son `RECT_TOP_LEFT`, `RECT_RANDOM` y `PYRAMID_RANDOM`.
99
+
100
+```cpp
101
+MainGameWindow *w = new MainGameWindow(Mode::SQUARE_TOP_LEFT);
102
+```
103
+
104
+La siguiente es para mostrar el objeto `w`.
105
+
106
+```cpp
107
+w->show();
108
+```
109
+
110
+El método `void display(QString)` sirve para desplegar mensajes cortos a la pantalla. Por ejemplo:
111
+
112
+```cpp
113
+w->display("Start");
114
+```
115
+
116
+muestra la palabra "Start" antes de comenzar a mover el robot. El pedazo de código que le sigue:
117
+
118
+```cpp
119
+int ctr = 0;
120
+while ( w->canMove('W') ) {
121
+    w->moveRobot('W');
122
+    ctr = ctr + 1;
123
+}
124
+```
125
+
126
+ilustra el uso de los métodos `bool canMove(char)` y `void moveRobot(char)`:
127
+
128
+* `bool canMove(char)` - acepta como parámetro una de las siguientes letras: `'N'`, `'S'`, `'E'` o `'W'` y devuelve `true` si existe una puerta en esa dirección del cuarto donde se encuentra el robot.
129
+* `void moveRobot(char)` - acepta como parámetro una de las letras `'N'`, `'S'`, `'E'` o `'W'` y mueve el robot al cuarto próximo que se encuentra en esa dirección.
130
+
131
+En el ejemplo, el código está tratando de mover al robot todas las veces que pueda hacia el oeste (`W`) y contándo cada cuarto en esa dirección.
132
+
133
+---
134
+
135
+---
136
+
137
+
138
+## Sesión de laboratorio
139
+
140
+### Ejercicio 1 - Cuadrícula cuadrada de cuartos
141
+
142
+Supón que el robot se encuentra en el cuarto superior izquierdo (extremo noroeste) de un espacio **cuadrado** de cuartos, i.e. el espacio contiene igual número de filas y columnas de cuartos (como el de la Figura 1). Diseña un algoritmo para que el robot pueda computar el número de cuartos que hay en la cuadrícula.
143
+
144
+**Instrucciones**
145
+
146
+1. Descarga la carpeta `Repetitions-CountingSquares` de `Bitbucket` usando un terminal, moviéndote al directorio `Documents/eip`, y escribiendo el comando `git clone http://bitbucket.org/eip-uprrp/repetitions-countingsquares`.
147
+
148
+2. Carga a Qt creator el proyecto `CountingSquares`  haciendo doble "click" en el archivo `CountingSquares.pro` que se encuentra en la carpeta  `Documents/eip/Repetitions-CountingSquares` de tu computadora. 
149
+
150
+3. Configura el proyecto. El proyecto consiste de varios archivos. **Solo escribirás código en el archivo** `main.cpp`. Los demás archivos contienen funciones que implementan la funcionalidad de las instrucciones que entiende el robot.
151
+
152
+4. Al escribir tu algoritmo debes asegurarte de que el objeto `MainGameWindow` es creado usando el argumento `Mode::SQUARE_TOP_LEFT`.  Recuerda, el robot no sabe de antemano cuantos cuartos hay. Prueba tu algoritmo con algunos ejemplos.
153
+
154
+5. Si el tamaño de la cuadrícula es 3x3, ¿cuántos cuartos debe visitar el robot para completar tu algoritmo?. ¿Qué tal 4x4? ¿Qué tal $n \times n$ cuartos?
155
+
156
+6. Presume que deseamos ahorrar en la energía que utiliza el robot. ¿Puedes hacer un algoritmo que utilice menos movidas para el mismo tamaño de cuadrícula?
157
+
158
+7. Una vez hayas terminado el algoritmo, lo hayas hecho correcto y eficiente, entrégalo usando Entrega 1 en Moodle. En el encabezado del algoritmo escribe y explica la expresión que hayaste sobre cuántos cuartos debe visitar el robot para completar su tarea para una cuadrícula $n \times n$ (algo así como "El robot toma 2n+5 movidas, 5 para llegar al medio y 2n para contar el resto")
159
+
160
+
161
+### Ejercicio 2 -  Cuadrícula rectangular de cuartos
162
+
163
+**Instrucciones**
164
+
165
+1. Supón que ahora el robot se encuentra en el cuarto superior izquierdo (extremo noroeste) de un espacio **rectangular**  (no necesariamente cuadrado) de cuartos. Diseña un algoritmo para que el robot pueda computar el número de cuartos que hay en la cuadrícula.
166
+
167
+2. Para probar esta parte en programación debes asegurarte que objeto `MainGameWindow` es creado usando el argumento `Mode::RECT_TOP_LEFT`.
168
+
169
+3. Una vez hayas terminado el algoritmo, lo hayas hecho correcto y eficiente, impleméntalo en la función `main`. En el encabezado del programa escribe y explica la expresión que hayaste sobre cuántos cuartos debe visitar el robot para completar su tarea en una cuadrícula $m \times n$. 
170
+
171
+4. Entrega el archivo `main.cpp` con el código para calcular el número de cuartos del rectángulo usando Entrega 2 en Moodle.
172
+
173
+### Ejercicio 3 - Cuadrícula rectangular de cuartos, posición aleatoria
174
+
175
+**Instrucciones**
176
+
177
+1. Supón que ahora el robot comienza su recorrido en cualquiera de los cuartos de una cuadrícula **rectangular** (no necesariamente cuadrada).  Diseña un algoritmo para que el robot pueda computar el número de cuartos que hay en la cuadrícula.
178
+
179
+2. Para probar esta parte en programación debes asegurarte que objeto `MainGameWindow` es creado usando el argumento `Mode::RECT_RANDOM`.
180
+
181
+3. Una vez hayas terminado el algoritmo, lo hayas hecho correcto y eficiente, impleméntalo en la función `main`. En el encabezado del programa escribe y explica la expresión que hayaste sobre cuántos cuartos debe visitar el robot para completar su tarea en una cuadrícula $m \times n$. En este caso, el número de cuartos a visitar va a depender de la posición inicial del robot, así que expresa el peor de los casos, i.e. ¿cuántos cuartos debe visitar tu algoritmo si el robot comienza en el *peor* de los cuartos. 
182
+
183
+4. Entrega el archivo `main.cpp` con el código para calcular el número de cuartos del rectángulo con robot en posición aleatoria usando Entrega 3 en Moodle.
184
+
185
+
186
+
187
+### Ejercicio 4 -  Cuadrícula en forma de pirámide, posición aleatoria
188
+
189
+**Instrucciones**
190
+
191
+1. Supón que ahora el robot comienza su recorrido en cualquiera de los cuartos de una cuadrícula en forma de pirámide.  Diseña un algoritmo para que el robot pueda computar el número de cuartos que hay en la cuadrícula.
192
+
193
+2. Para probar esta parte en programación debes asegurarte que objeto `MainGameWindow` es creado usando el argumento `Mode::PYRAMID_RANDOM`.
194
+
195
+3. Una vez hayas terminado el algoritmo, lo hayas hecho correcto y eficiente, impleméntalo en la función `main`. En el encabezado del programa escribe y explica la expresión que hayaste sobre cuántos cuartos debe visitar el robot para completar su tarea en una cuadrícula $m \times n$. En este caso, el número de cuartos a visitar va a depender de la posición inicial del robot, así que expresa el peor de los caso, i.e. ¿cuántos cuartos visitaría tu algoritmo si el robot comienza en el *peor* de los cuartos.
196
+
197
+4. Entrega el archivo `main.cpp` con el código para calcular el número de cuartos de la pirámide con robot en posición aleatoria usando Entrega 4 en Moodle.
198
+
199
+
200
+
201
+---
202
+
203
+---
204
+
205
+## Entregas
206
+
207
+Utiliza los enlaces "Entrega" en Moodle para entregar el algoritmo del Ejercicio 1 y los  archivos `main.cpp` que contienen el código que implementaste en los ejercicios 2, 3 y 4. Recuerda utilizar buenas prácticas de programación, incluir el nombre de los programadores y documentar tu programa.
208
+
209
+
210
+
211
+---
212
+
213
+---
214
+
215
+## Referencias
216
+
217
+[1] Luther A. Tychonievich, Mark S. Sherriff, and Ryan M. Layer, http://nifty.stanford.edu/2011/feinberg-generic-scrolling-game/

+ 31
- 0
countingSquares.pro View File

@@ -0,0 +1,31 @@
1
+#-------------------------------------------------
2
+#
3
+# Project created by QtCreator 2014-09-07T18:12:22
4
+#
5
+#-------------------------------------------------
6
+
7
+QT       += core gui
8
+
9
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10
+
11
+TARGET = countingSquares
12
+TEMPLATE = app
13
+
14
+CONFIG += c++11
15
+SOURCES += main.cpp \
16
+    maingamewindow.cpp \
17
+    genericscrollingobject.cpp
18
+
19
+
20
+RESOURCES += \
21
+    countingSquares.qrc
22
+
23
+
24
+HEADERS += \
25
+    maingamewindow.h \
26
+    genericscrollingobject.h
27
+
28
+INCLUDEPATH += /usr/local/Cellar/box2d/2.3.0/include
29
+
30
+
31
+DEFINES += QT_NO_DEBUG_OUTPUT

+ 8
- 0
countingSquares.qrc View File

@@ -0,0 +1,8 @@
1
+<RCC>
2
+    <qresource prefix="/">
3
+        <file>explosion.png</file>
4
+        <file>horse.png</file>
5
+        <file>horse.jpeg</file>
6
+        <file>robot.png</file>
7
+    </qresource>
8
+</RCC>

BIN
explosion.png View File


+ 67
- 0
genericscrollingobject.cpp View File

@@ -0,0 +1,67 @@
1
+#include "genericscrollingobject.h"
2
+#include "maingamewindow.h"
3
+#include <QDebug>
4
+
5
+//
6
+// A class for the items that move.
7
+
8
+GenericScrollingObject::GenericScrollingObject(const std::string& filename, QGraphicsScene *scene,
9
+                                               int x, int y, int w, int h,
10
+                                               const QColor& transparency_color ,
11
+                                               MainGameWindow *parent
12
+                                               )
13
+{
14
+    scene->addItem(this);
15
+    myScene = scene;
16
+    alive = true;
17
+
18
+    // create a pixmap with invisible background
19
+    QPixmap pixmap(filename.c_str());
20
+    pixmap = pixmap.scaled(w,h);
21
+    const QBitmap mask = pixmap.createMaskFromColor(transparency_color);
22
+    pixmap.setMask(mask);
23
+    this->setPixmap(pixmap);
24
+
25
+    // set position and speed
26
+    myX = x;
27
+    myY = y;
28
+    toX = toY = 0;
29
+    myDirY = 0;
30
+    myDirX = 0;
31
+    myParent = parent;
32
+    setPos(myX,myY);
33
+}
34
+
35
+
36
+//
37
+// This method that is automatically called on each tick
38
+//
39
+void GenericScrollingObject::advance(int) {
40
+
41
+    myX = myX + myDirX;
42
+    myY = myY + myDirY;
43
+
44
+    if (myDirX != 0 && abs(myX-toX) < 10) { myDirX = 0; myX = toX;}
45
+    if (myDirY != 0 && abs(myY-toY) < 10) { myDirY = 0; myY = toY;}
46
+    
47
+    this->setPos(myX,myY);
48
+}
49
+
50
+
51
+void GenericScrollingObject::kill() {
52
+    alive = false;
53
+
54
+    // Show the explosion, instead of the robot
55
+    QPixmap pixmap(":explosion.png");
56
+    pixmap = pixmap.scaled(boundingRect().width(),boundingRect().height(),Qt::IgnoreAspectRatio,Qt::FastTransformation);
57
+
58
+    const QBitmap mask = pixmap.createMaskFromColor(QColor(Qt::black));
59
+    pixmap.setMask(mask);
60
+
61
+    setPixmap(pixmap);
62
+}
63
+
64
+
65
+
66
+
67
+

+ 45
- 0
genericscrollingobject.h View File

@@ -0,0 +1,45 @@
1
+#ifndef GENERICSCROLLINGOBJECT_H
2
+#define GENERICSCROLLINGOBJECT_H
3
+#include <QGraphicsPixmapItem>
4
+#include <QGraphicsScene>
5
+#include <QBitmap>
6
+
7
+
8
+// A class for the items that move.
9
+
10
+class MainGameWindow;
11
+
12
+class GenericScrollingObject : public QGraphicsPixmapItem {
13
+public:
14
+    GenericScrollingObject(const std::string& filename, QGraphicsScene *scene,
15
+                           int x, int y, int w, int h,
16
+                           const QColor& transparency_color = QColor(0,255,0),
17
+                           MainGameWindow *parent = 0
18
+            );
19
+
20
+    int x() const { return myX; }
21
+    int y() const { return myY; }
22
+
23
+    //
24
+    // This method that is automatically called on each tick
25
+    //
26
+    void advance(int phase);
27
+
28
+
29
+    // given an integer number of pixels, move the item by that amount, vertically
30
+    void kill();
31
+    bool isAlive() {return alive;}
32
+    int myDirX, myDirY;
33
+    int myX, myY;
34
+    int toX, toY;
35
+
36
+private:
37
+    bool alive;
38
+    QGraphicsScene *myScene;
39
+    MainGameWindow *myParent;
40
+};
41
+
42
+
43
+
44
+
45
+#endif // GENERICSCROLLINGOBJECT_H

BIN
horse.jpeg View File


BIN
horse.png View File


BIN
images/cuarto.png View File


BIN
images/main1.png View File


BIN
images/main2.png View File


BIN
images/main3.png View File


+ 45
- 0
main.cpp View File

@@ -0,0 +1,45 @@
1
+#include <QApplication>
2
+#include "maingamewindow.h"
3
+#include <cmath>
4
+
5
+
6
+
7
+int main(int argc, char *argv[]) {
8
+    QApplication   a(argc, argv);
9
+
10
+    //MainGameWindow *w = new MainGameWindow(4,2);
11
+    //MainGameWindow *w = new MainGameWindow("xx x\nxx x\nx xx\n");
12
+    MainGameWindow *w = new MainGameWindow(Mode::SQUARE_TOP_LEFT);
13
+
14
+    w->show();
15
+
16
+    while (w->canMove('W'))
17
+        w->moveRobot('W');
18
+
19
+
20
+    while (w->canMove('N'))
21
+        w->moveRobot('N');
22
+    //w->moveRobot('N');
23
+
24
+    int width = 1;
25
+    w->display(width);
26
+    while (w->canMove('E')) {
27
+        width++;
28
+        w->moveRobot('E');
29
+        w->display(width);
30
+    }
31
+
32
+
33
+    int height = 1;
34
+    w->display(height);
35
+    while (w->canMove('S')) {
36
+        height++;
37
+        w->moveRobot('S');
38
+        w->display(height);
39
+    }
40
+
41
+    w->display("Total: " + QString::number(width * height));
42
+    w->moveRobot('J');
43
+
44
+    return a.exec();
45
+}

+ 378
- 0
maingamewindow.cpp View File

@@ -0,0 +1,378 @@
1
+// Todo implement game modes: 1= square upper left, 2 = rect upper left, etc..
2
+
3
+#include "maingamewindow.h"
4
+#include <QDebug>
5
+#include <QTimer>
6
+#include <QTime>
7
+#include <QEventLoop>
8
+#include <QApplication>
9
+
10
+//
11
+// Initialices some of the data members
12
+//
13
+
14
+void MainGameWindow::initMembers() {
15
+    s = new QGraphicsScene(this);
16
+
17
+    s->setSceneRect(0,0,600,600);
18
+    this->setGeometry(0,0,600,600);
19
+
20
+    v = new QGraphicsView(s,this);
21
+    v->setGeometry(0,0,600,600);
22
+
23
+    pct_margin = .1;
24
+
25
+    srand(time(NULL));
26
+
27
+}
28
+
29
+//
30
+// Starts the timer that is used for animation purposes.
31
+//
32
+
33
+void MainGameWindow::startTheTimer() {
34
+    timer = new QTimer(s);
35
+    timer->connect(timer, SIGNAL(timeout()), s, SLOT(advance()));
36
+    timer->start(10);
37
+}
38
+
39
+//
40
+// Constructor that accepts a game mode argument. See the modes
41
+// definition in the .h.
42
+//
43
+
44
+MainGameWindow::MainGameWindow(Mode gameMode) : QMainWindow(0) {
45
+    initMembers();
46
+
47
+    // the initial row/col positions of the robot
48
+    uint initialX, initialY;
49
+
50
+    _rows = rand() % 9 + 2;
51
+    switch (gameMode) {
52
+        case Mode::SQUARE_TOP_LEFT:
53
+            _cols = _rows;
54
+            initialX = initialY = 0;
55
+            break;
56
+        case Mode::RECT_TOP_LEFT:
57
+            _cols = rand() % 9 + 2;
58
+            initialX = initialY = 0;
59
+            break;
60
+        case Mode::RECT_RANDOM:
61
+            _cols = rand() % 9 + 2;
62
+            initialX = rand() % _cols;
63
+            initialY = rand() % _rows;
64
+            break;
65
+        case Mode::PYRAMID_RANDOM:
66
+            _cols = (rand() % 4 + 2) * 2 + 1;
67
+            createPiramid();
68
+            assignValidPos(initialX, initialY);
69
+            break;
70
+    }
71
+
72
+    // This creates rectangular mazes
73
+    if (_maze == "") {
74
+        for (uint r = 0; r < _rows; r++) {
75
+            for (uint c = 0; c < _cols; c++) {
76
+                _maze.push_back('x');
77
+            }
78
+            _maze.push_back('\n');
79
+        }
80
+    }
81
+
82
+    qDebug() << "MainGameWindow::MainGameWindow(): width: " << this->width();
83
+    qDebug() << "_maze: " << _maze;
84
+
85
+    paintMaze(initialX, initialY);
86
+
87
+    startTheTimer();
88
+
89
+    v->show();
90
+}
91
+
92
+
93
+// Creates this type of pyramid, e.g. _cols = 7
94
+// 000x000
95
+// 00xxx00
96
+// 0xxxxx0
97
+// xxxxxxx
98
+
99
+void MainGameWindow::createPiramid() {
100
+    _maze = "";
101
+    _rows = _cols/2;
102
+
103
+
104
+    for (uint r = 0; r <= _rows + 1; r++) {
105
+        for (uint c = 0; c < _cols; c++) {
106
+            _maze.push_back( abs((int)c - (int)_rows) <= (int)r ? 'x':' ');
107
+        }
108
+        _maze.push_back('\n');
109
+    }
110
+
111
+    _rows++;
112
+}
113
+
114
+
115
+//
116
+// Randomly determines a valid initial position for the robot
117
+//
118
+
119
+void MainGameWindow::assignValidPos(uint &initialX, uint &initialY) {
120
+    qDebug() << _maze;
121
+    if (_cols <= 0 || _rows <= 0) {
122
+        qDebug() << "assignValidPos was called with 0 rows or cols!";
123
+        exit(1);
124
+    }
125
+
126
+    // throw the dice to determine initial random position
127
+    do {
128
+        initialX = rand() % _cols;
129
+        initialY = rand() % _rows;
130
+    } while (_maze.toStdString()[initialY * (_cols + 1) + initialX] != 'x');
131
+}
132
+
133
+//
134
+// Constructor that accepts number of rows and columns.
135
+//
136
+
137
+MainGameWindow::MainGameWindow(uint rows, uint cols) : QMainWindow(0) {
138
+    _rows = rows;
139
+    _cols = cols;
140
+
141
+    initMembers();
142
+
143
+    _maze = "";
144
+    for (uint r = 0; r < _rows; r++) {
145
+        for (uint c = 0; c < _cols; c++) {
146
+            _maze.push_back('x');
147
+        }
148
+        _maze.push_back('\n');
149
+    }
150
+
151
+    qDebug() << "MainGameWindow::MainGameWindow(): width: " << this->width();
152
+    qDebug() << "_maze: " << _maze;
153
+
154
+    paintMaze(0,0);
155
+
156
+    startTheTimer();
157
+
158
+    v->show();
159
+}
160
+
161
+MainGameWindow::MainGameWindow(const QString &maze) {
162
+    _maze = maze;
163
+    initMembers();
164
+
165
+    if (validMaze() ) {
166
+        qDebug() << "valid maze!!!!";
167
+        paintMaze(0,0);
168
+        startTheTimer();
169
+    }
170
+
171
+}
172
+
173
+//
174
+// Given a string that represents the maze, determines the number
175
+// of rows and cols. Returns false if the maze is malformed.
176
+//
177
+
178
+bool MainGameWindow::validMaze() {
179
+    char c;
180
+    uint ctr = 0;
181
+    _cols = 0; _rows = 0;
182
+    for (int i = 0; i < _maze.length(); i++){
183
+        c = _maze.toStdString()[i];
184
+        if (c == 'x' || c == ' ') ctr++;
185
+        else if (c == '\n') {
186
+            if (_cols == 0) _cols = ctr;
187
+            else if (_cols != ctr) return false;
188
+            ctr = 0;
189
+            _rows++;
190
+        }
191
+    }
192
+    qDebug() << "rows:" << _rows << " cols: " << _cols;
193
+    return true;
194
+}
195
+
196
+//
197
+// This is a delay that lets other events in the event loop
198
+// continue executing.
199
+//
200
+
201
+void delay(int ms)
202
+{
203
+    QTime dieTime= QTime::currentTime().addMSecs(ms);
204
+    while( QTime::currentTime() < dieTime )
205
+        QApplication::processEvents(QEventLoop::AllEvents,10);
206
+}
207
+
208
+//
209
+// Determines the underlying character of the maze.
210
+// This is used to determine if the robot is off the grid
211
+// or has entered a wall.
212
+//
213
+
214
+char MainGameWindow::posToChar() {
215
+    uint r, c;
216
+
217
+    posToRC(r, c);
218
+
219
+    if (r >= _rows || c >= _cols) return -1;
220
+    return _maze.toStdString()[r * (_cols + 1) + c];
221
+
222
+}
223
+
224
+//
225
+// Determines the poisition in row, column, based on the x, y position
226
+// of the robot.
227
+//
228
+
229
+void MainGameWindow::posToRC(uint &r, uint &c) {
230
+    uint realX = robot->myX - s->width() *  pct_margin;
231
+    uint realY = robot->myY - s->height() * pct_margin ;
232
+
233
+    r = round(static_cast<float>(realY) / rowHeight);
234
+    c = round(static_cast<float>(realX) / colWidth);
235
+}
236
+
237
+//
238
+// Given the direction determines if the robot may move in that
239
+// direction.
240
+//
241
+
242
+bool MainGameWindow::canMove(char dir) {
243
+
244
+    uint r, c;
245
+
246
+    posToRC(r, c);
247
+
248
+    switch(dir) {
249
+    case 'W': c--; break;
250
+    case 'E': c++; break;
251
+    case 'N': r--; break;
252
+    case 'S': r++; break;
253
+    default:
254
+        display("Bad direction: " + QString(dir));
255
+        return false;
256
+    }
257
+
258
+    if (r >= _rows || c >= _cols) return false;
259
+    else return _maze.toStdString()[r * (_cols + 1) + c] == 'x';
260
+}
261
+
262
+
263
+//
264
+// Given a character 'N', 'S', 'E', or 'W', moves the robot
265
+// one cell in that direction. If the target cell was invalid
266
+// then it destroys the robot.
267
+//
268
+
269
+void MainGameWindow::moveRobot(char dir) {
270
+    if (robot->isAlive()) {
271
+        uint deltaX = colWidth / 10;
272
+        uint deltaY = rowHeight / 10;
273
+
274
+        qDebug() << "car at:" << robot->myX;
275
+        switch(dir) {
276
+        case 'N': robot->toY = robot->myY - rowHeight; robot->myDirY = -deltaY; break;
277
+        case 'S': robot->toY = robot->myY + rowHeight; robot->myDirY = +deltaY; break;
278
+        case 'E': robot->toX = robot->myX + colWidth;  robot->myDirX = +deltaX; break;
279
+        case 'W': robot->toX = robot->myX - colWidth;  robot->myDirX = -deltaX; break;
280
+        default: display("Bad direction: " + QString(dir)); return;
281
+        }
282
+
283
+        qDebug() <<"colwidth" << colWidth;
284
+        qDebug() << "move to at:" << robot->toX;
285
+
286
+        while (robot->myDirX != 0 || robot->myDirY != 0)
287
+            delay(500);
288
+        robot->myDirX = robot->myDirY = 0;
289
+
290
+        if (posToChar() != 'x')
291
+            robot->kill();
292
+   }
293
+}
294
+
295
+//
296
+// Given a string, displays it in large letters.
297
+//
298
+
299
+void MainGameWindow::display(const QString &st) {
300
+    if (robot->isAlive()) {
301
+        msg->setHtml("<center>" + st + "</center>");
302
+        msg->show();
303
+        delay(500);
304
+        msg->hide();
305
+    }
306
+}
307
+
308
+//
309
+// Given an int, displays it in big letters.
310
+//
311
+
312
+void MainGameWindow::display(int n) {
313
+    display(QString::number(n));
314
+}
315
+
316
+
317
+// Paints the maze based on the contents of the _maze string.
318
+// Also creates the robot and the text box for display.
319
+
320
+void MainGameWindow::paintMaze(uint initialX, uint initialY) {
321
+
322
+    pct_margin = 1.0/( _cols > _rows ? _cols + 2 : _rows + 2);
323
+
324
+    qDebug() << "pct_margin " << pct_margin;
325
+    uint fromY = s->height()*pct_margin, toY = s->height()*(1-pct_margin);
326
+
327
+    qDebug() << "toX, toY" << fromY << "," << toY ;
328
+    uint fromX = s->width()*pct_margin,  toX = s->width()*(1-pct_margin);
329
+
330
+    rowHeight = (toY - fromY) / _rows;
331
+    colWidth =  (toX - fromX) / _cols;
332
+
333
+
334
+    uint strPos = 0;
335
+    QBrush black(Qt::black);
336
+    QBrush white(Qt::white);
337
+
338
+    for (uint i = 0; i < _rows; i++) {
339
+        uint y = i * rowHeight + s->height()*pct_margin;
340
+        for (uint j = 0; j < _cols; j++) {
341
+            uint x = j * colWidth + s->width() * pct_margin;
342
+            qDebug() << x << " " << y;
343
+            s->addRect(x, y, colWidth, rowHeight, QPen(Qt::SolidLine),
344
+                       _maze.at(strPos) == 'x' ? white : black);
345
+            strPos++;
346
+        }
347
+        strPos++;
348
+    }
349
+
350
+    // // Create the robot
351
+    //
352
+    // int initialX, initialY;
353
+    //
354
+    // // throw the dice to determine initial random position
355
+    // do {
356
+    //     initialX = rand() % _cols;
357
+    //     initialY = rand() % _rows;
358
+    //
359
+    // } while (_maze.toStdString()[initialY * (_cols + 1) + initialX] != 'x');
360
+
361
+    robot = new GenericScrollingObject(":robot.png", s,
362
+                                       colWidth * initialX  + s->width() * pct_margin,
363
+                                       rowHeight * initialY + s->height() * pct_margin, colWidth,rowHeight,
364
+                                       QColor(Qt::white), this);
365
+
366
+
367
+    // Create the text box that will be used for the display
368
+
369
+    msg = new QGraphicsTextItem;
370
+    msg->setPos(0, s->height()/2);
371
+    msg->setTextWidth(s->width());
372
+    msg->setHtml("<center>Barev</center>");
373
+    msg->setFont(QFont("Helvetica",90));
374
+    msg->setDefaultTextColor(Qt::green);
375
+    msg->hide();
376
+    s->addItem(msg);
377
+
378
+}

+ 66
- 0
maingamewindow.h View File

@@ -0,0 +1,66 @@
1
+#ifndef MAINGAMEWINDOW_H
2
+#define MAINGAMEWINDOW_H
3
+#include <cmath>
4
+#include <QGraphicsView>
5
+#include <QMainWindow>
6
+#include <QGraphicsScene>
7
+#include <QBitmap>
8
+#include <QGraphicsView>
9
+#include <genericscrollingobject.h>
10
+//
11
+// Constants for the types of objects. We use them to determine what collisions are
12
+// worth processing.
13
+//
14
+const int RECT_MODE = 1;
15
+
16
+class GenericScrollingObject;
17
+
18
+typedef unsigned int uint;
19
+
20
+enum class Mode {SQUARE_TOP_LEFT,  RECT_TOP_LEFT, RECT_RANDOM, PYRAMID_RANDOM};
21
+
22
+class MainGameWindow: public QMainWindow {
23
+
24
+public:
25
+
26
+    MainGameWindow(uint rows, uint cols);
27
+    MainGameWindow(const QString &maze);
28
+    MainGameWindow(Mode gameMode);
29
+
30
+
31
+    void moveRobot(char dir);
32
+    bool canMove(char dir);
33
+
34
+    void display(const QString &st);
35
+    void display(int n);
36
+
37
+private:
38
+    QGraphicsScene *s;
39
+    QGraphicsView  *v;
40
+    uint _rows, _cols;
41
+
42
+    QString _maze;
43
+    GenericScrollingObject *robot;
44
+    QTimer *timer;
45
+
46
+    uint rowHeight, colWidth;
47
+    float pct_margin;
48
+    QGraphicsTextItem *msg;
49
+
50
+    void paintMaze(uint initialX, uint initialY);
51
+    void initMembers();
52
+    bool validMaze();
53
+    void createPiramid();
54
+    void assignValidPos(uint &initialX, uint &initialY);
55
+    void startTheTimer();
56
+    void posToRC(uint &r, uint &c);
57
+    char posToChar();
58
+    void setMaze(const QString &maze) { _maze = maze; }
59
+
60
+};
61
+
62
+void delay(int ms);
63
+
64
+#define PCT_MARGIN 0.1
65
+
66
+#endif // MAINGAMEWINDOW_H

BIN
robot.png View File