2 Copyright 2010 Serge Ziryukin <ftrvxmtrx@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
15 #include <QDataStream>
19 #include <QPaintEvent>
20 #include <QMessageBox>
22 #include "colorscheme.hpp"
24 static const int fieldWidth = 420;
26 const int Field::numRects[Field::NUM_SIZES] = { 14, 21, 28 };
27 const int Field::numTurns[Field::NUM_SIZES] = { 25, 35, 50 };
29 // we declare out QVector<FieldRect> metatype
30 // and stream operators to save whole field to settings
31 Q_DECLARE_METATYPE(Field::RectVector);
33 static QDataStream &operator<< (QDataStream &out, const Field::RectVector &rv)
35 for (QVector<Field::FieldRect>::const_iterator rect = rv.begin();
46 static QDataStream &operator>> (QDataStream &in, Field::RectVector &rv)
54 in >> r.brush >> r.flood;
63 Field::Field (QWidget *parent, int *turns)
69 setFixedSize(fieldWidth, fieldWidth);
71 // restore field size and field itself from settings
73 qRegisterMetaType<RectVector>("Field::RectVector");
74 qRegisterMetaTypeStreamOperators<RectVector>("Field::RectVector");
78 int size = settings.value("field/size", SIZE_SMALL).toInt();
80 if (size < SIZE_SMALL || size >= NUM_SIZES)
83 this->size = (FieldSize)size;
85 if (settings.contains("field/data"))
86 data = settings.value("field/data").value<RectVector>();
88 this->turns = settings.value("field/turns", 0).toInt();
90 if (data.size() != numRects[size] * numRects[size])
102 settings.setValue("field/size", size);
106 settings.setValue("field/data", v);
108 settings.setValue("field/turns", turns);
112 Field::FieldSize Field::getSize () const
117 void Field::setSize (int size)
119 Q_ASSERT(size >= 0 && size < NUM_SIZES);
121 if (this->size == size)
124 this->size = (FieldSize)size;
128 void Field::randomize ()
136 data = RectVector(numRects[size] * numRects[size], rect);
138 qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
140 int numBrushes = ColorScheme::instance().getScheme().size();
142 for (QVector<FieldRect>::iterator rect = data.begin();
146 (*rect).brush = qrand() % numBrushes;
151 emit turnsChanged(turns);
153 // flood from top-left
154 data[0].flood = true;
155 floodNeighbours(data[0].brush, 0, 0);
160 int Field::getNumRectsOfSize (FieldSize size)
162 return numRects[size];
165 int Field::getNumTurnsOfSize (FieldSize size)
167 return numTurns[size];
170 int Field::getRectSize (FieldSize size)
172 return fieldWidth / numRects[size];
175 void Field::tryFloodRecurse (quint8 brush, int x, int y)
177 FieldRect &rect = data[x + y*numRects[size]];
179 if (!rect.flood && rect.brush == brush)
182 floodNeighbours(brush, x, y);
186 void Field::floodNeighbours (quint8 brush, int x, int y)
188 int s = numRects[size];
190 data[x + y*s].brush = brush;
193 tryFloodRecurse(brush, x - 1, y);
196 tryFloodRecurse(brush, x, y - 1);
199 tryFloodRecurse(brush, x + 1, y);
202 tryFloodRecurse(brush, x, y + 1);
205 void Field::paintEvent (QPaintEvent *event)
210 QRect rect = QRect(0, 0, getRectSize(size), getRectSize(size));
212 const QVector<QBrush> &scheme = ColorScheme::instance().getScheme();
214 for (int y = 0; y < numRects[size] ;y++)
216 int n = y * numRects[size];
218 for (int x = 0; x < numRects[size] ;x++, n++)
220 rect.moveTo(x * rect.width(), y * rect.height());
222 if (rect.intersects(event->rect()))
223 painter.fillRect(rect, scheme.at(data[n].brush));
230 void Field::flood (int colorIndex)
232 // don't fill with the same color over and over again
233 if (colorIndex == data[0].brush)
239 emit turnsChanged(++turns);
241 // flood with new color
242 for (int y = 0; y < numRects[size] ;y++)
244 int n = y * numRects[size];
246 for (int x = 0; x < numRects[size] ;x++, n++)
249 floodNeighbours(colorIndex, x, y);
255 bool allFlooded = true;
257 // check if all field flooded
258 for (QVector<Field::FieldRect>::const_iterator rect = data.begin();
275 msg = tr("You won!");
277 else if (getNumTurnsOfSize(size) == turns)
281 msg = tr("You lost!");
287 box.setWindowTitle("Color Flood");