From 67bea2978845ef16cdcaa6a3a9913adeac0fb68c Mon Sep 17 00:00:00 2001 From: Dhanveer Ramnauth Date: Sat, 9 Apr 2022 22:41:38 +1000 Subject: [PATCH] tetris baby --- Tetris/Tetris.sln | 4 +- Tetris/Tetris/Source.cpp | 230 ++++++++++++++++++++++++++++++++++- Tetris/Tetris/Tetris.vcxproj | 1 + 3 files changed, 231 insertions(+), 4 deletions(-) diff --git a/Tetris/Tetris.sln b/Tetris/Tetris.sln index 2d88dc4..939a435 100644 --- a/Tetris/Tetris.sln +++ b/Tetris/Tetris.sln @@ -13,8 +13,8 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Debug|x64.ActiveCfg = Debug|x64 - {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Debug|x64.Build.0 = Debug|x64 + {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Debug|x64.ActiveCfg = Release|Win32 + {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Debug|x64.Build.0 = Release|Win32 {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Debug|x86.ActiveCfg = Debug|Win32 {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Debug|x86.Build.0 = Debug|Win32 {A563C8D1-58A0-44D7-AA0C-6D3721CEEAA9}.Release|x64.ActiveCfg = Release|x64 diff --git a/Tetris/Tetris/Source.cpp b/Tetris/Tetris/Source.cpp index d21373f..6038373 100644 --- a/Tetris/Tetris/Source.cpp +++ b/Tetris/Tetris/Source.cpp @@ -1,8 +1,234 @@ #include +#include +#include +#include +#include -int main() +#include + + + +std::wstring tetromino[7]; +int nFieldWidth = 12; +int nFieldHeight = 18; +unsigned char* pField = nullptr; + +int nScreenWidth = 120; +int nScreenHeight = 30; + +int Rotate(int px, int py, int r) { - std::cout << "Hello World" << std::endl; + switch (r % 4) + { + case 0: return py * 4 + px; + case 1: return 12 + py - (px * 4); + case 2: return 15 - (py * 4) - px; + case 3: return 3 - py + (px * 4); + } return 0; } +bool DoesPieceFit(int nTetromino, int nRotation, int nPosX, int nPosY) +{ + for (int px = 0; px < 4; px++) + { + for (int py = 0; py < 4; py++) + { + int pi = Rotate(px, py, nRotation); + int fi = (nPosY + py) * nFieldWidth + (nPosX + px); + if (nPosX + px >= 0 && nPosX + px < nFieldWidth) + { + if (nPosY + py >= 0 && nPosY + py < nFieldHeight) + { + if (tetromino[nTetromino][pi] == L'X' && pField[fi] != 0) + return false; + } + } + } + } + + return true; +} + +int main() +{ + wchar_t* screen = new wchar_t[nScreenWidth * nScreenHeight]; + for (int i = 0; i < nScreenWidth * nScreenHeight; i++) screen[i] = L' '; + HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + SetConsoleActiveScreenBuffer(hConsole); + DWORD dwBytesWritten = 0; + + //create assets + tetromino[0].append(L"..X."); + tetromino[0].append(L"..X."); + tetromino[0].append(L"..X."); + tetromino[0].append(L"..X."); + + tetromino[1].append(L"..X."); + tetromino[1].append(L".XX."); + tetromino[1].append(L".X.."); + tetromino[1].append(L"...."); + + tetromino[2].append(L".X.."); + tetromino[2].append(L".XX."); + tetromino[2].append(L"..X."); + tetromino[2].append(L"...."); + + tetromino[3].append(L"...."); + tetromino[3].append(L".XX."); + tetromino[3].append(L".XX."); + tetromino[3].append(L"...."); + + tetromino[4].append(L"..X."); + tetromino[4].append(L".XX."); + tetromino[4].append(L"..X."); + tetromino[4].append(L"...."); + + tetromino[5].append(L"...."); + tetromino[5].append(L".XX."); + tetromino[5].append(L"..X."); + tetromino[5].append(L"..X."); + + tetromino[6].append(L"...."); + tetromino[6].append(L".XX."); + tetromino[6].append(L".X.."); + tetromino[6].append(L".X.."); + + pField = new unsigned char[nFieldWidth * nFieldHeight]; // Create play field buffer + for (int x = 0; x < nFieldWidth; x++) // Board Boundary + for (int y = 0; y < nFieldHeight; y++) + pField[y * nFieldWidth + x] = (x == 0 || x == nFieldWidth - 1 || y == nFieldHeight - 1) ? 9 : 0; + + + bool bGameOver = false; + + bool bKey[4]; + int nCurrentPiece = 0; + int nCurrentRotation = 0; + int nCurrentX = nFieldWidth / 2; + int nCurrentY = 0; + bool bRotateHold = true; + int nSpeedCounter = 0; + int nSpeed = 20; + bool bForce = false; + std::vector vLines; + int nScore = 0; + int nPieceCount = 0; + while (!bGameOver) + { + //timing + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + nSpeedCounter++; + bForce = (nSpeedCounter == nSpeed); + + + //input + + for (int k = 0; k < 4; k++) // R L D Z + bKey[k] = (0x8000 & GetAsyncKeyState((unsigned char)("\x27\x25\x28Z"[k]))) != 0; + + //game logic + + nCurrentX += (bKey[0] && DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX + 1, nCurrentY)) ? 1 : 0; + nCurrentX -= (bKey[1] && DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX - 1, nCurrentY)) ? 1 : 0; + nCurrentY += (bKey[2] && DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1)) ? 1 : 0; + + if (bKey[3]) + { + nCurrentRotation += (bRotateHold && DoesPieceFit(nCurrentPiece, nCurrentRotation + 1, nCurrentX, nCurrentY)) ? 1 : 0; + bRotateHold = false; + } + else + bRotateHold = true; + + if (bForce) + { + if (DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1)) + { + nCurrentY++; + } + else + { + for (int px = 0; px < 4; px++) + for (int py = 0; py < 4; py++) + if (tetromino[nCurrentPiece][Rotate(px, py, nCurrentRotation)] == L'X') + pField[(nCurrentY + py) * nFieldWidth + (nCurrentX + px)] = nCurrentPiece + 1; + + nPieceCount++; + if (nPieceCount % 10 == 0) + if (nSpeed >= 10) nSpeed++; + + for (int py = 0; py < 4; py++) + if (nCurrentY + py < nFieldHeight - 1) + { + bool bLine = true; + for (int px = 1; px < nFieldWidth - 1; px++) + bLine &= (pField[(nCurrentY + py) * nFieldWidth + px]) != 0; + + if (bLine) + { + for (int px = 1; px < nFieldWidth - 1; px++) + pField[(nCurrentY + py) * nFieldWidth + px] = 8; + + vLines.push_back(nCurrentY + py); + } + } + + nScore += 25; + if (!vLines.empty()) + nScore += (1 << vLines.size()) * 100; + + nCurrentX = nFieldWidth / 2; + nCurrentY = 0; + nCurrentRotation = 0; + nCurrentPiece = rand() % 7; + + bGameOver = !DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY); + + + } + nSpeedCounter = 0; + } + + //render output + + // field drawing + for (int x = 0; x < nFieldWidth; x++) + for (int y = 0; y < nFieldHeight; y++) + screen[(y + 2) * nScreenWidth + (x + 2)] = L" ABCDEFG=#"[pField[y * nFieldWidth + x]]; + + for (int px = 0; px < 4; px++) + for (int py = 0; py < 4; py++) + if (tetromino[nCurrentPiece][Rotate(px, py, nCurrentRotation)] != L'.') + screen[(nCurrentY + py + 2) * nScreenWidth + (nCurrentX + px + 2)] = nCurrentPiece + 65; + + swprintf_s(&screen[2 * nScreenWidth + nFieldWidth + 6], 16, L"SCORE: %8d", nScore); + + if (!vLines.empty()) + { + // Display Frame (cheekily to draw lines) + WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0,0 }, &dwBytesWritten); + std::this_thread::sleep_for(std::chrono::milliseconds(400)); // Delay a bit + + for (const auto& v : vLines) + for (int px = 1; px < nFieldWidth - 1; px++) + { + + for (int py = v; py > 0; py--) + pField[py * nFieldWidth + px] = pField[(py - 1) * nFieldWidth + px]; + + pField[px] = 0; + + } + + + for (int x = 0; x < nFieldWidth; x++) + for (int y = 0; y < nFieldHeight; y++) + screen[(y + 2) * nScreenWidth + (x + 2)] = L" ABCDEFG=#"[pField[y * nFieldWidth + x]]; + vLines.clear(); + } + + WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0,0 }, &dwBytesWritten); + } +} + diff --git a/Tetris/Tetris/Tetris.vcxproj b/Tetris/Tetris/Tetris.vcxproj index 7c7df36..db782e5 100644 --- a/Tetris/Tetris/Tetris.vcxproj +++ b/Tetris/Tetris/Tetris.vcxproj @@ -102,6 +102,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + MultiThreadedDebug Console