Last active
April 19, 2016 16:11
-
-
Save arhadthedev/e7683da755a99db769d59527b09539c7 to your computer and use it in GitHub Desktop.
Шаблон для игры «Жизнь» Александру
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <Strsafe.h> | |
#include <bitset> | |
// ********************************************** | |
// | |
// Логика приложения | |
// | |
// ********************************************** | |
template <size_t Rows, size_t Columns> | |
class GameOfLife | |
{ | |
public: | |
GameOfLife() | |
: _currentField(0), _generation(1) | |
{ | |
for(size_t i = 0; i < _fields[0].size(); ++i) | |
_fields[0].set(i, std::rand() & 1); | |
} | |
unsigned generation() const | |
{ | |
return _generation; | |
} | |
size_t rows() const | |
{ | |
return Rows; | |
} | |
size_t columns() const | |
{ | |
return Columns; | |
} | |
const std::bitset<Rows * Columns>& field() const | |
{ | |
return _fields[_currentField]; | |
} | |
void process() | |
{ | |
++_generation; | |
std::bitset<Rows * Columns>& prevGenField = _fields[_currentField]; | |
_currentField = (_currentField == 0) ? 1 : 0; | |
std::bitset<Rows * Columns>& nextGenField = _fields[_currentField]; | |
for(size_t row = 0; row < Rows; ++row) | |
{ | |
for(size_t column = 0; column < Columns; ++column) | |
{ | |
// Считаем количество соседей очередной клетки. Воспользуемся | |
// тем свойством, что true преобразуется в 1, а false - в 0. | |
const unsigned neightboursCount | |
= prevGenField.test(CellByPosition(row - 1, column - 1)) | |
+ prevGenField.test(CellByPosition(row - 1, column )) | |
+ prevGenField.test(CellByPosition(row - 1, column + 1)) | |
+ prevGenField.test(CellByPosition(row, column - 1)) | |
+ prevGenField.test(CellByPosition(row, column )) | |
+ prevGenField.test(CellByPosition(row, column + 1)) | |
+ prevGenField.test(CellByPosition(row + 1, column - 1)) | |
+ prevGenField.test(CellByPosition(row + 1, column )) | |
+ prevGenField.test(CellByPosition(row + 1, column + 1)); | |
// 1. "Мёртвая" клетка с тремя соседями "оживает". | |
// 2. "Живая" клетка с менее, чем двумя, или более, чем тремя, | |
// соседями "умирает". | |
const bool wasAlive | |
= prevGenField.test(CellByPosition(row, column)); | |
const bool isAlive = (neightboursCount == 3) | |
|| (neightboursCount == 2 && wasAlive); | |
nextGenField.set(CellByPosition(row, column), isAlive); | |
} | |
} | |
} | |
private: | |
static size_t CellByPosition(size_t row, size_t column) | |
{ | |
const size_t warpedRow = row % Rows; | |
const size_t warpedColumn = column % Columns; | |
return warpedRow * Columns + warpedColumn; | |
} | |
std::bitset<Rows * Columns> _fields[2]; | |
size_t _currentField; | |
unsigned _generation; | |
}; | |
// ********************************************** | |
// | |
// Графический интерфейс пользователя | |
// | |
// ********************************************** | |
#define UNUSED(expr) (void)(expr) | |
// ============================================== | |
enum | |
{ | |
MainWindowStyle = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX, | |
Interval = 500, | |
CellSize = 10, | |
FieldRows = 20, | |
FieldColumns = 40 | |
}; | |
static GameOfLife<FieldRows, FieldColumns> game; | |
// ============================================== | |
static LRESULT CALLBACK MainWindowProc | |
(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
{ | |
switch(uMsg) | |
{ | |
case WM_PAINT: | |
{ | |
PAINTSTRUCT ps; | |
const HDC hdc = BeginPaint(hWnd, &ps); | |
SelectObject(hdc, GetStockObject(WHITE_BRUSH)); | |
size_t i = 0; | |
const std::bitset<FieldRows * FieldColumns>& field = game.field(); | |
for(size_t row = 0; row < game.rows(); ++row) | |
{ | |
for(size_t column = 0; column < game.columns(); ++column) | |
{ | |
if(field.test(i++)) | |
{ | |
Rectangle( | |
hdc, | |
column * CellSize, | |
row * CellSize, | |
column * CellSize + CellSize, | |
row * CellSize + CellSize | |
); | |
} | |
} | |
} | |
EndPaint(hWnd, &ps); | |
return 0; | |
} | |
case WM_TIMER: | |
{ | |
game.process(); | |
TCHAR captionBuffer[sizeof(TEXT("Generation: \0\0\0\0\0\0\0"))]; | |
StringCbPrintf( | |
captionBuffer, | |
sizeof captionBuffer, | |
TEXT("Generation: %u"), | |
game.generation() | |
); | |
SetWindowText(hWnd, captionBuffer); | |
InvalidateRect(hWnd, NULL, TRUE); | |
return 0; | |
} | |
case WM_DESTROY: | |
PostQuitMessage(0); | |
return 0; | |
default: | |
return DefWindowProc(hWnd, uMsg, wParam, lParam); | |
} | |
} | |
static HWND createWindow(HINSTANCE hInstance) | |
{ | |
WNDCLASS cls; | |
cls.style = 0; | |
cls.lpfnWndProc = MainWindowProc; | |
cls.cbClsExtra = 0; | |
cls.cbWndExtra = 0; | |
cls.hInstance = hInstance; | |
cls.hIcon = NULL; | |
cls.hCursor = LoadCursor(NULL, IDC_ARROW); | |
cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | |
cls.lpszMenuName = NULL; | |
cls.lpszClassName = TEXT("MainWindowClass"); | |
RECT rect; | |
rect.left = 0; | |
rect.top = 0; | |
rect.right = game.columns() * CellSize; | |
rect.bottom = game.rows() * CellSize; | |
AdjustWindowRect(&rect, MainWindowStyle, false); | |
return CreateWindow( | |
MAKEINTATOM(RegisterClass(&cls)), | |
TEXT("Generation: 1"), | |
MainWindowStyle, | |
CW_USEDEFAULT, CW_USEDEFAULT, | |
rect.right - rect.left, rect.bottom - rect.top, | |
NULL, | |
NULL, | |
hInstance, | |
NULL | |
); | |
} | |
int CALLBACK WinMain( | |
HINSTANCE hInstance, | |
HINSTANCE hPrevInstance, | |
LPSTR lpCmdLine, | |
int nCmdShow | |
) | |
{ | |
UNUSED(hPrevInstance); | |
UNUSED(lpCmdLine); | |
const HWND mainWindow = createWindow(hInstance); | |
SetTimer(mainWindow, 0, Interval, NULL); | |
ShowWindow(mainWindow, nCmdShow); | |
MSG msg; | |
bool process = true; | |
while(process) | |
{ | |
const WINBOOL bRet = GetMessage(&msg, NULL, 0, 0); | |
if(bRet > 0) | |
{ | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
else if(bRet < 0) | |
{ | |
const TCHAR Message[] | |
= TEXT("Error occured while processing a window message"); | |
DWORD dummy; | |
const HANDLE winStdErr = GetStdHandle(STD_ERROR_HANDLE); | |
WriteConsole(winStdErr, Message, sizeof Message, &dummy, NULL); | |
} | |
else | |
process = false; | |
} | |
return msg.wParam; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment