Add proxy bug list and lightsout game (desktop + Android)
This commit is contained in:
1 parent
e1946b208d
commit
d8cbe2e589
23 files changed
+1076
No files matched your search
@@ -0,0 +1,141 @@
|
||||
#include "boardwidget.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
namespace {
|
||||
constexpr int kMargin = 8; // внешний отступ поля
|
||||
constexpr int kGap = 4; // зазор между клетками
|
||||
constexpr int kMinCell = 36; // минимальный размер клетки (пикс.)
|
||||
constexpr int kMaxCell = 72; // максимальный размер клетки (пикс.)
|
||||
}
|
||||
|
||||
BoardWidget::BoardWidget(QWidget *parent)
|
||||
: QWidget(parent) {
|
||||
setMinimumSize(220, 220);
|
||||
}
|
||||
|
||||
// Создаёт новую партию: сбрасывает поле, затем случайными одиночными
|
||||
// переключениями формирует решаемую стартовую позицию.
|
||||
void BoardWidget::newGame(int size) {
|
||||
m_size = size;
|
||||
m_moves = 0;
|
||||
m_real.fill(0, m_size * m_size);
|
||||
|
||||
// Позиция строится переключением случайных клеток из нулевого состояния —
|
||||
// обратная последовательность ходов гарантированно решает её.
|
||||
const int scrambles = m_size * m_size * 3;
|
||||
for (int i = 0; i < scrambles; ++i) {
|
||||
const int idx = QRandomGenerator::global()->bounded(m_size * m_size);
|
||||
m_real[idx] ^= 1;
|
||||
}
|
||||
|
||||
update();
|
||||
emit stateChanged(isSolved());
|
||||
}
|
||||
|
||||
// Включает/выключает показ подсказки.
|
||||
void BoardWidget::setHintEnabled(bool enabled) {
|
||||
if (m_hintEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
m_hintEnabled = enabled;
|
||||
update();
|
||||
}
|
||||
|
||||
// Отображаемое значение клетки — XOR её самой с четырьмя соседями.
|
||||
int BoardWidget::displayValue(int row, int col) const {
|
||||
int v = m_real[row * m_size + col];
|
||||
if (row > 0) v ^= m_real[(row - 1) * m_size + col];
|
||||
if (row < m_size - 1) v ^= m_real[(row + 1) * m_size + col];
|
||||
if (col > 0) v ^= m_real[row * m_size + (col - 1)];
|
||||
if (col < m_size - 1) v ^= m_real[row * m_size + (col + 1)];
|
||||
return v;
|
||||
}
|
||||
|
||||
// Переключает клетку по клику и проверяет победу.
|
||||
void BoardWidget::toggleCell(int row, int col) {
|
||||
m_real[row * m_size + col] ^= 1;
|
||||
++m_moves;
|
||||
update();
|
||||
emit stateChanged(isSolved());
|
||||
}
|
||||
|
||||
// Победа — все отображаемые клетки погашены.
|
||||
bool BoardWidget::isSolved() const {
|
||||
for (int r = 0; r < m_size; ++r) {
|
||||
for (int c = 0; c < m_size; ++c) {
|
||||
if (displayValue(r, c) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BoardWidget::mousePressEvent(QMouseEvent *event) {
|
||||
if (m_size <= 0 || event->button() != Qt::LeftButton) {
|
||||
QWidget::mousePressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
const QRectF board = boardRect();
|
||||
if (!board.contains(event->pos())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const double cell = (board.width() - (m_size - 1) * kGap) / m_size;
|
||||
const int col = static_cast<int>((event->pos().x() - board.left()) / (cell + kGap));
|
||||
const int row = static_cast<int>((event->pos().y() - board.top()) / (cell + kGap));
|
||||
|
||||
if (row >= 0 && row < m_size && col >= 0 && col < m_size) {
|
||||
toggleCell(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
void BoardWidget::paintEvent(QPaintEvent *) {
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
if (m_size <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QRectF board = boardRect();
|
||||
const double cell = (board.width() - (m_size - 1) * kGap) / m_size;
|
||||
|
||||
const QColor onColor(255, 214, 92); // «включена» — тёплый жёлтый
|
||||
const QColor offColor(44, 48, 56); // «выключена» — тёмно-серый
|
||||
const QColor hintColor(120, 220, 120); // подсказка — зелёная точка
|
||||
|
||||
for (int r = 0; r < m_size; ++r) {
|
||||
for (int c = 0; c < m_size; ++c) {
|
||||
const QRectF rect(
|
||||
board.left() + c * (cell + kGap),
|
||||
board.top() + r * (cell + kGap),
|
||||
cell, cell);
|
||||
|
||||
painter.setPen(QPen(QColor(20, 22, 26), 1.5));
|
||||
painter.setBrush(displayValue(r, c) ? onColor : offColor);
|
||||
painter.drawRoundedRect(rect, 6, 6);
|
||||
|
||||
// Подсказка: точка на клетках, чьё истинное значение равно 0.
|
||||
if (m_hintEnabled && m_real[r * m_size + c] == 0) {
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(hintColor);
|
||||
const double d = cell * 0.22;
|
||||
painter.drawEllipse(rect.center(), d / 2, d / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Прямоугольник, занимаемый сеткой клеток (центрированный квадрат).
|
||||
QRectF BoardWidget::boardRect() const {
|
||||
const int cell = kMinCell;
|
||||
const double side = cell * m_size + kGap * (m_size - 1);
|
||||
const double x = (width() - side) / 2.0;
|
||||
const double y = (height() - side) / 2.0;
|
||||
return QRectF(x, y, side, side);
|
||||
}
|
||||
Reference in new issue
Block a user