File indexing completed on 2024-04-14 03:59:23

0001 /***************************************************************************
0002 *   KBlocks, a falling blocks game by KDE                                *
0003 *   SPDX-FileCopyrightText: 2010 Zhongjie Cai <squall.leonhart.cai@gmail.com>       *
0004 *                                                                         *
0005 *   SPDX-License-Identifier: GPL-2.0-or-later
0006 ***************************************************************************/
0007 #include "KBlocksField.h"
0008 
0009 KBlocksField::KBlocksField(int width, int height)
0010 {
0011     mWidth = width;
0012     mHeight = height;
0013 
0014     mCurModifyID = 0;
0015     mLastModifyID = -1;
0016 
0017     maEncodeData = new unsigned char[mWidth * mHeight / 8 + 1];
0018     for (int i = 0; i < mWidth * mHeight / 8 + 1; ++i) {
0019         maEncodeData[i] = 0;
0020     }
0021 
0022     maBoard = new bool*[mHeight];
0023     for (int i = 0; i < mHeight; i++) {
0024         maBoard[i] = new bool[mWidth];
0025         for (int j = 0; j < mWidth; j++) {
0026             maBoard[i][j] = false;
0027         }
0028     }
0029 }
0030 
0031 KBlocksField::KBlocksField(FieldInterface *p)
0032 {
0033     mWidth = p->getWidth();
0034     mHeight = p->getHeight();
0035 
0036     mCurModifyID = 0;
0037     mLastModifyID = -1;
0038 
0039     maEncodeData = new unsigned char[mWidth * mHeight / 8 + 1];
0040     for (int i = 0; i < mWidth * mHeight / 8 + 1; ++i) {
0041         maEncodeData[i] = 0;
0042     }
0043 
0044     maBoard = new bool*[mHeight];
0045     for (int i = 0; i < mHeight; i++) {
0046         maBoard[i] = new bool[mWidth];
0047         for (int j = 0; j < mWidth; j++) {
0048             maBoard[i][j] = p->getCell(j, i);
0049         }
0050     }
0051 }
0052 
0053 KBlocksField::~KBlocksField()
0054 {
0055     for (int i = 0; i < mHeight; i++) {
0056         delete [] maBoard[i];
0057     }
0058     delete [] maBoard;
0059     delete [] maEncodeData;
0060 }
0061 
0062 bool KBlocksField::getCell(int xPos, int yPos)
0063 {
0064     if ((xPos < 0) || (xPos >= mWidth) || (yPos >= mHeight)) {
0065         return true;
0066     }
0067     if (yPos < 0) {
0068         return false; // Allow blocks to be placed above top
0069     }
0070 
0071     return maBoard[yPos][xPos];
0072 }
0073 
0074 void KBlocksField::setCell(int xPos, int yPos, bool value)
0075 {
0076     if (((xPos < 0) || (xPos >= mWidth))
0077             || ((yPos < 0) || (yPos >= mHeight))) {
0078         return;
0079     }
0080     maBoard[yPos][xPos] = value;
0081     mCurModifyID += 1;
0082 }
0083 
0084 void KBlocksField::copy(FieldInterface *p)
0085 {
0086     for (int i = 0; i < mHeight; i++) {
0087         for (int j = 0; j < mWidth; j++) {
0088             maBoard[i][j] = p->getCell(j, i);
0089         }
0090     }
0091 }
0092 
0093 void KBlocksField::clear()
0094 {
0095     for (int i = 0; i < mHeight; i++) {
0096         for (int j = 0; j < mWidth; j++) {
0097             maBoard[i][j] = false;
0098         }
0099     }
0100     mCurModifyID = 0;
0101 }
0102 
0103 bool KBlocksField::checkFilledLine(int lineID)
0104 {
0105     for (int i = 0; i < mWidth; i++) {
0106         if (maBoard[lineID][i] == false) {
0107             return false;
0108         }
0109     }
0110     return true;
0111 }
0112 
0113 void KBlocksField::removeFilledLine(int lineID)
0114 {
0115     // This function removes line number lineID which has been identified as
0116     // containing no empty cells (by KBlocksField::checkFilledLine).
0117     //
0118     // The line is removed by moving the contents of all cells above
0119     // line #lineID one line down, effectively overwriting the contents
0120     // of line #lineID.
0121     //
0122     // To this end we iterate over all lines, starting at line #lineID and
0123     // ending with the line just below the top line.
0124 
0125     for (int i = lineID; i > 0; i--) {
0126 
0127         // For each line we iterate over all cells ...
0128 
0129         for (int j = 0; j < mWidth; j++) {
0130 
0131             // ... and set the content of the cell to the content of the
0132             // same cell one line above.
0133 
0134             maBoard[i][j] = maBoard[i - 1][j];
0135         }
0136     }
0137 
0138     // Finally, the top line is filled with empty cells ...
0139     for (int j = 0; j < mWidth; j++) {
0140         maBoard[0][j] = false;
0141     }
0142 
0143     // ... and the modification ID is increased by one.
0144     mCurModifyID += 1;
0145 }
0146 
0147 bool KBlocksField::addPunishLine(int lineCount, int punishSeed)
0148 {
0149     bool result = true;
0150 
0151     for (int i = 0; i < mWidth; i++) {
0152         if (maBoard[0][i]) {
0153             result = false;
0154             break;
0155         }
0156     }
0157 
0158     for (int i = 0; i < mHeight - 1; i++) {
0159         for (int j = 0; j < mWidth; j++) {
0160             maBoard[i][j] = maBoard[i + 1][j];
0161         }
0162     }
0163 
0164     for (int i = 0; i < mWidth; i++) {
0165         maBoard[mHeight - 1][i] = true;
0166     }
0167 
0168     for (int i = 0; i < lineCount; i++) {
0169         maBoard[mHeight - 1][punishSeed] = false;
0170         punishSeed = (punishSeed + lineCount) % mWidth;
0171     }
0172 
0173     mCurModifyID += 1;
0174 
0175     return result;
0176 }
0177 
0178 int KBlocksField::getModifyID()
0179 {
0180     return mCurModifyID;
0181 }
0182 
0183 int KBlocksField::encodeData(unsigned char *data)
0184 {
0185     int byteCounter = 0;
0186     int loopCounter = 0;
0187 
0188     if (mLastModifyID != mCurModifyID) {
0189         mLastModifyID = mCurModifyID;
0190         for (int i = 0; i < mHeight; i++) {
0191             for (int j = 0; j < mWidth; j++) {
0192                 byteCounter = loopCounter / 8;
0193                 if (maBoard[i][j]) {
0194                     maEncodeData[byteCounter] |= (1 << (loopCounter % 8));
0195                 } else {
0196                     maEncodeData[byteCounter] &= ~(1 << (loopCounter % 8));
0197                 }
0198                 loopCounter++;
0199             }
0200         }
0201     }
0202 
0203     byteCounter = mWidth * mHeight / 8;
0204     for (int i = 0; i < byteCounter; i++) {
0205         data[i] = maEncodeData[i];
0206     }
0207 
0208     return byteCounter;
0209 }
0210 
0211 void KBlocksField::decodeData(unsigned char *data)
0212 {
0213     int byteCounter = 0;
0214     int loopCounter = 0;
0215 
0216     for (int i = 0; i < mHeight; i++) {
0217         for (int j = 0; j < mWidth; j++) {
0218             byteCounter = loopCounter / 8;
0219             if (((data[byteCounter] >> (loopCounter % 8)) & 0x01) == 0x01) {
0220                 maBoard[i][j] = true;
0221             } else {
0222                 maBoard[i][j] = false;
0223             }
0224             loopCounter++;
0225         }
0226     }
0227 
0228     for (int i = 0; i < byteCounter; i++) {
0229         maEncodeData[i] = data[i];
0230     }
0231 
0232     mCurModifyID = 0;
0233     mLastModifyID = 0;
0234 }
0235 
0236 int KBlocksField::getWidth()
0237 {
0238     return mWidth;
0239 }
0240 
0241 int KBlocksField::getHeight()
0242 {
0243     return mHeight;
0244 }
0245 
0246 bool KBlocksField::equals(KBlocksField *rhs)
0247 {
0248     if ((rhs->getWidth() != mWidth) || (rhs->getHeight() != mHeight)) {
0249         return false;
0250     }
0251     for (int i = 0; i < mHeight; i++) {
0252         for (int j = 0; j < mWidth; j++) {
0253             if (maBoard[i][j] != rhs->getCell(j, i)) {
0254                 return false;
0255             }
0256         }
0257     }
0258     return true;
0259 }
0260 
0261 int KBlocksField::getBlockHeight(int xPos)
0262 {
0263     for (int i = 0; i < mHeight; ++i) {
0264         if (maBoard[i][xPos]) {
0265             return (mHeight - i);
0266         }
0267     }
0268     return 0;
0269 }
0270 
0271 int KBlocksField::getFreeHeight(int xPos)
0272 {
0273     for (int i = 0; i < mHeight; ++i) {
0274         if (maBoard[i][xPos]) {
0275             return i;
0276         }
0277     }
0278     return mHeight;
0279 }
0280 
0281 void KBlocksField::getSignature(int *data)
0282 {
0283     for (int i = 0; i < mWidth; ++i) {
0284         data[i] = getBlockHeight(i);
0285     }
0286 }