File indexing completed on 2022-11-29 18:38:53

0001 /*
0002     KBlackBox - A simple game inspired by an emacs module
0003 
0004     SPDX-FileCopyrightText: 1999-2000 Robert Cimrman <cimrman3@students.zcu.cz>
0005     SPDX-FileCopyrightText: 2007 Nicolas Roffet <nicolas-kde@roffet.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 
0011 #include "kbbballsonboard.h"
0012 
0013 
0014 
0015 #include "kbbgamedoc.h"
0016 
0017 
0018 
0019 //
0020 // Constructor / Destructor
0021 //
0022 
0023 KBBBallsOnBoard::KBBBallsOnBoard(KBBGameDoc* parent, const int columns, const int rows) : QObject(parent)
0024 {
0025     m_columns = columns;
0026     m_rows = rows;
0027 }
0028 
0029 
0030 
0031 //
0032 // Public
0033 //
0034 
0035 int KBBBallsOnBoard::absolutePositionToBorderPosition(int position[DIM_MAX])
0036 {
0037     int borderPosition = KBBGameDoc::HIT_POSITION;
0038     if (position[DIM_Y] == 1)
0039         borderPosition = position[DIM_X] - 2;
0040     else if (position[DIM_X] == m_columns + 2)
0041         borderPosition = position[DIM_Y] - 2 + m_columns;
0042     else if (position[DIM_Y] == m_rows + 2)
0043         borderPosition = 1 - position[DIM_X] + 2 * m_columns + m_rows;
0044     else if (position[DIM_X] == 1)
0045         borderPosition = 1 - position[DIM_Y] + 2*(m_rows + m_columns);
0046     
0047     return borderPosition;
0048 }
0049 
0050 
0051 int KBBBallsOnBoard::absolutePositionToBoxPosition(int position[DIM_MAX])
0052 {
0053     return (position[DIM_X]-2)+(position[DIM_Y]-2)*(m_columns);
0054 }
0055 
0056 
0057 void KBBBallsOnBoard::add(int boxPosition)
0058 {
0059     m_balls.append(boxPosition);
0060     Q_EMIT changes();
0061 }
0062 
0063 
0064 void KBBBallsOnBoard::borderPositionToAbsolutePosition(int borderPosition, int position[DIM_MAX])
0065 {
0066     if (borderPosition < m_columns) {
0067         position[DIM_X] = borderPosition + 2;
0068         position[DIM_Y] = 1;
0069     } else if ((borderPosition >= m_columns) && (borderPosition < m_columns + m_rows)) {
0070         position[DIM_X] = m_columns + 2;
0071         position[DIM_Y] = (borderPosition - m_columns) + 2;
0072     } else if ((borderPosition >= m_columns + m_rows) && (borderPosition < 2*m_columns + m_rows)) {
0073         position[DIM_X] = (m_columns - (borderPosition - m_columns - m_rows)) + 1;
0074         position[DIM_Y] = m_rows + 2;
0075     } else if (borderPosition >= 2*m_columns + m_rows) {
0076         position[DIM_X] = 1;
0077         position[DIM_Y] = (m_rows - (borderPosition - 2*m_columns - m_rows)) + 1;
0078     } else {
0079         position[DIM_X] = KBBGameDoc::HIT_POSITION;
0080         position[DIM_Y] = KBBGameDoc::HIT_POSITION;
0081     }
0082 }
0083 
0084 
0085 int KBBBallsOnBoard::columns()
0086 {
0087     return m_columns;
0088 }
0089 
0090 
0091 bool KBBBallsOnBoard::contains(int boxPosition)
0092 {
0093     return m_balls.contains(boxPosition);
0094 }
0095 
0096 
0097 int KBBBallsOnBoard::count()
0098 {
0099     return m_balls.count();
0100 }
0101 
0102 
0103 void KBBBallsOnBoard::newBoard(const int columns, const int rows)
0104 {
0105     m_balls.clear();
0106     m_columns = columns;
0107     m_rows = rows;
0108     Q_EMIT changes();
0109 }
0110 
0111 
0112 int KBBBallsOnBoard::numberOfBallsNotIn(KBBBallsOnBoard* otherBoard)
0113 {
0114     int diff = 0;
0115     
0116     for (int i=0; i<m_balls.count(); i++)
0117         if (!otherBoard->contains(m_balls[i]))
0118             diff++;
0119     
0120     return diff;
0121 }
0122 
0123 
0124 int KBBBallsOnBoard::oppositeBorderPosition(int borderPosition) {
0125     QList<int> points;
0126     return oppositeBorderPositionWithPoints(borderPosition, points);
0127 }
0128 
0129 
0130 int KBBBallsOnBoard::oppositeBorderPositionWithPoints(const int borderPosition,  QList<int> &points) {
0131     // 1. Conversion "border position -> (Absolute) position"
0132     int position[DIM_MAX];
0133     borderPositionToAbsolutePosition(borderPosition, position);
0134 
0135     // 2. Get start direction
0136     int direction[DIM_MAX];
0137     if (borderPosition < m_columns) {
0138         direction[DIM_X] = 0;
0139         direction[DIM_Y] = 1;
0140     } else if ((borderPosition >= m_columns) && (borderPosition < m_columns + m_rows)) {
0141         direction[DIM_X] = -1;
0142         direction[DIM_Y] = 0;
0143     } else if ((borderPosition >= m_columns + m_rows) && (borderPosition < 2*m_columns + m_rows)) {
0144         direction[DIM_X] = 0;
0145         direction[DIM_Y] = -1;
0146     } else if (borderPosition >= 2*m_columns + m_rows) {
0147         direction[DIM_X] = 1;
0148         direction[DIM_Y] = 0;
0149     }
0150 
0151     // 3. Get the outgoing (absolute) position
0152     getOutgoingPosition(position, direction, points);
0153     
0154     // 4. Conversion "(absolute) position -> border position"
0155     return absolutePositionToBorderPosition(position);
0156 }
0157 
0158 
0159 void KBBBallsOnBoard::ray(const int borderPosition, QList<int> &points)
0160 {
0161     oppositeBorderPositionWithPoints(borderPosition, points);
0162 }
0163 
0164 
0165 void KBBBallsOnBoard::remove(int boxPosition)
0166 {
0167     m_balls.removeAll(boxPosition);
0168     Q_EMIT changes();
0169 }
0170 
0171 
0172 int KBBBallsOnBoard::rows()
0173 {
0174     return m_rows;
0175 }
0176 
0177 
0178 
0179 //
0180 // Private
0181 //
0182 
0183 void KBBBallsOnBoard::getOutgoingPosition( int position[DIM_MAX], int incomingDirection[DIM_MAX], QList<int> &points)
0184 {
0185     int outgoingDirection[DIM_MAX];
0186     
0187     int nextPosition[DIM_MAX];
0188     nextPosition[DIM_X] = position[DIM_X] + incomingDirection[DIM_X];
0189     nextPosition[DIM_Y] = position[DIM_Y] + incomingDirection[DIM_Y];
0190 
0191     int nextLeftPosition[DIM_MAX];
0192     nextLeftPosition[DIM_X] = nextPosition[DIM_X] + incomingDirection[DIM_Y];
0193     nextLeftPosition[DIM_Y] = nextPosition[DIM_Y] + incomingDirection[DIM_X];
0194 
0195     int nextRightPosition[DIM_MAX];
0196     nextRightPosition[DIM_X] = nextPosition[DIM_X] - incomingDirection[DIM_Y];
0197     nextRightPosition[DIM_Y] = nextPosition[DIM_Y] - incomingDirection[DIM_X];
0198 
0199     bool deviation = false;
0200     if (positionInTheBox(nextPosition) && contains((nextPosition[DIM_X] - 2) + (nextPosition[DIM_Y] - 2) * m_columns)) {
0201         // HIT
0202         position[DIM_X] = KBBGameDoc::HIT_POSITION;
0203         position[DIM_Y] = KBBGameDoc::HIT_POSITION;
0204         points.append(absolutePositionToBoxPosition(nextPosition));
0205     } else if (positionInTheBox(nextLeftPosition) && contains((nextLeftPosition[DIM_X] - 2) + (nextLeftPosition[DIM_Y] - 2) * m_columns)) {
0206         // DEVIATION 1
0207         outgoingDirection[DIM_X] = -incomingDirection[DIM_Y];
0208         outgoingDirection[DIM_Y] = -incomingDirection[DIM_X];
0209         deviation = true;
0210     } else if (positionInTheBox(nextRightPosition) && contains((nextRightPosition[DIM_X] - 2) + (nextRightPosition[DIM_Y] - 2) * m_columns)) {
0211         // DEVIATION 2
0212         outgoingDirection[DIM_X] = incomingDirection[DIM_Y];
0213         outgoingDirection[DIM_Y] = incomingDirection[DIM_X];
0214         deviation = true;
0215     } else {
0216         //NORMAL
0217         position[DIM_X] = nextPosition[DIM_X];
0218         position[DIM_Y] = nextPosition[DIM_Y];
0219         outgoingDirection[DIM_X] = incomingDirection[DIM_X];
0220         outgoingDirection[DIM_Y] = incomingDirection[DIM_Y];
0221     }
0222     
0223     // Out of the Black box? (loop exit condition)
0224     if (positionInTheBox(position)) {
0225         points.append(absolutePositionToBoxPosition(position));
0226         getOutgoingPosition( position, outgoingDirection, points );
0227     } else if (deviation)
0228         // special case: Deviation entering the black box. Player should see the laser ray entering, even if it's in fact deviated before entering...
0229         points.append(absolutePositionToBoxPosition(nextPosition));
0230     
0231     return;
0232 }
0233 
0234 
0235 bool KBBBallsOnBoard::positionInTheBox( int position[DIM_MAX] )
0236 {
0237     return !((position[DIM_X] < 2) || (position[DIM_X] > m_columns + 1) || (position[DIM_Y] < 2) || (position[DIM_Y] > m_rows + 1));
0238 }
0239 
0240