1//
2// KBlackBox
3//
4// A simple game inspired by an emacs module
5//
6/***************************************************************************
7 * Copyright (c) 1999-2000, Robert Cimrman *
8 * cimrman3@students.zcu.cz *
9 * *
10 * Copyright (c) 2007, Nicolas Roffet *
11 * nicolas-kde@roffet.com *
12 * *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA *
28 ***************************************************************************/
29
30
31#include "kbbballsonboard.h"
32
33#include <QObject>
34
35
36#include "kbbgamedoc.h"
37
38
39
40//
41// Constructor / Destructor
42//
43
44KBBBallsOnBoard::KBBBallsOnBoard(KBBGameDoc* parent, const int columns, const int rows) : QObject(parent)
45{
46 m_columns = columns;
47 m_rows = rows;
48}
49
50
51
52//
53// Public
54//
55
56int KBBBallsOnBoard::absolutePositionToBorderPosition(int position[DIM_MAX])
57{
58 int borderPosition = KBBGameDoc::HIT_POSITION;
59 if (position[DIM_Y] == 1)
60 borderPosition = position[DIM_X] - 2;
61 else if (position[DIM_X] == m_columns + 2)
62 borderPosition = position[DIM_Y] - 2 + m_columns;
63 else if (position[DIM_Y] == m_rows + 2)
64 borderPosition = 1 - position[DIM_X] + 2 * m_columns + m_rows;
65 else if (position[DIM_X] == 1)
66 borderPosition = 1 - position[DIM_Y] + 2*(m_rows + m_columns);
67
68 return borderPosition;
69}
70
71
72int KBBBallsOnBoard::absolutePositionToBoxPosition(int position[DIM_MAX])
73{
74 return (position[DIM_X]-2)+(position[DIM_Y]-2)*(m_columns);
75}
76
77
78void KBBBallsOnBoard::add(int boxPosition)
79{
80 m_balls.append(boxPosition);
81 emit changes();
82}
83
84
85void KBBBallsOnBoard::borderPositionToAbsolutePosition(int borderPosition, int position[DIM_MAX])
86{
87 if (borderPosition < m_columns) {
88 position[DIM_X] = borderPosition + 2;
89 position[DIM_Y] = 1;
90 } else if ((borderPosition >= m_columns) && (borderPosition < m_columns + m_rows)) {
91 position[DIM_X] = m_columns + 2;
92 position[DIM_Y] = (borderPosition - m_columns) + 2;
93 } else if ((borderPosition >= m_columns + m_rows) && (borderPosition < 2*m_columns + m_rows)) {
94 position[DIM_X] = (m_columns - (borderPosition - m_columns - m_rows)) + 1;
95 position[DIM_Y] = m_rows + 2;
96 } else if (borderPosition >= 2*m_columns + m_rows) {
97 position[DIM_X] = 1;
98 position[DIM_Y] = (m_rows - (borderPosition - 2*m_columns - m_rows)) + 1;
99 } else {
100 position[DIM_X] = KBBGameDoc::HIT_POSITION;
101 position[DIM_Y] = KBBGameDoc::HIT_POSITION;
102 }
103}
104
105
106int KBBBallsOnBoard::columns()
107{
108 return m_columns;
109}
110
111
112bool KBBBallsOnBoard::contains(int boxPosition)
113{
114 return m_balls.contains(boxPosition);
115}
116
117
118int KBBBallsOnBoard::count()
119{
120 return m_balls.count();
121}
122
123
124void KBBBallsOnBoard::newBoard(const int columns, const int rows)
125{
126 m_balls.clear();
127 m_columns = columns;
128 m_rows = rows;
129 emit changes();
130}
131
132
133int KBBBallsOnBoard::numberOfBallsNotIn(KBBBallsOnBoard* otherBoard)
134{
135 int diff = 0;
136
137 for (int i=0; i<m_balls.count(); i++)
138 if (!otherBoard->contains(m_balls[i]))
139 diff++;
140
141 return diff;
142}
143
144
145int KBBBallsOnBoard::oppositeBorderPosition(int borderPosition) {
146 QList<int> points;
147 return oppositeBorderPositionWithPoints(borderPosition, points);
148}
149
150
151int KBBBallsOnBoard::oppositeBorderPositionWithPoints(const int borderPosition, QList<int> &points) {
152 // 1. Conversion "border position -> (Absolute) position"
153 int position[DIM_MAX];
154 borderPositionToAbsolutePosition(borderPosition, position);
155
156 // 2. Get start direction
157 int direction[DIM_MAX];
158 if (borderPosition < m_columns) {
159 direction[DIM_X] = 0;
160 direction[DIM_Y] = 1;
161 } else if ((borderPosition >= m_columns) && (borderPosition < m_columns + m_rows)) {
162 direction[DIM_X] = -1;
163 direction[DIM_Y] = 0;
164 } else if ((borderPosition >= m_columns + m_rows) && (borderPosition < 2*m_columns + m_rows)) {
165 direction[DIM_X] = 0;
166 direction[DIM_Y] = -1;
167 } else if (borderPosition >= 2*m_columns + m_rows) {
168 direction[DIM_X] = 1;
169 direction[DIM_Y] = 0;
170 }
171
172 // 3. Get the outgoing (absolute) position
173 getOutgoingPosition(position, direction, points);
174
175 // 4. Conversion "(absolute) position -> border position"
176 return absolutePositionToBorderPosition(position);
177}
178
179
180void KBBBallsOnBoard::ray(const int borderPosition, QList<int> &points)
181{
182 oppositeBorderPositionWithPoints(borderPosition, points);
183}
184
185
186void KBBBallsOnBoard::remove(int boxPosition)
187{
188 m_balls.removeAll(boxPosition);
189 emit changes();
190}
191
192
193int KBBBallsOnBoard::rows()
194{
195 return m_rows;
196}
197
198
199
200//
201// Private
202//
203
204void KBBBallsOnBoard::getOutgoingPosition( int position[DIM_MAX], int incomingDirection[DIM_MAX], QList<int> &points)
205{
206 int outgoingDirection[DIM_MAX];
207
208 int nextPosition[DIM_MAX];
209 nextPosition[DIM_X] = position[DIM_X] + incomingDirection[DIM_X];
210 nextPosition[DIM_Y] = position[DIM_Y] + incomingDirection[DIM_Y];
211
212 int nextLeftPosition[DIM_MAX];
213 nextLeftPosition[DIM_X] = nextPosition[DIM_X] + incomingDirection[DIM_Y];
214 nextLeftPosition[DIM_Y] = nextPosition[DIM_Y] + incomingDirection[DIM_X];
215
216 int nextRightPosition[DIM_MAX];
217 nextRightPosition[DIM_X] = nextPosition[DIM_X] - incomingDirection[DIM_Y];
218 nextRightPosition[DIM_Y] = nextPosition[DIM_Y] - incomingDirection[DIM_X];
219
220 bool deviation = false;
221 if (positionInTheBox(nextPosition) && contains((nextPosition[DIM_X] - 2) + (nextPosition[DIM_Y] - 2) * m_columns)) {
222 // HIT
223 position[DIM_X] = KBBGameDoc::HIT_POSITION;
224 position[DIM_Y] = KBBGameDoc::HIT_POSITION;
225 points.append(absolutePositionToBoxPosition(nextPosition));
226 } else if (positionInTheBox(nextLeftPosition) && contains((nextLeftPosition[DIM_X] - 2) + (nextLeftPosition[DIM_Y] - 2) * m_columns)) {
227 // DEVIATION 1
228 outgoingDirection[DIM_X] = -incomingDirection[DIM_Y];
229 outgoingDirection[DIM_Y] = -incomingDirection[DIM_X];
230 deviation = true;
231 } else if (positionInTheBox(nextRightPosition) && contains((nextRightPosition[DIM_X] - 2) + (nextRightPosition[DIM_Y] - 2) * m_columns)) {
232 // DEVIATION 2
233 outgoingDirection[DIM_X] = incomingDirection[DIM_Y];
234 outgoingDirection[DIM_Y] = incomingDirection[DIM_X];
235 deviation = true;
236 } else {
237 //NORMAL
238 position[DIM_X] = nextPosition[DIM_X];
239 position[DIM_Y] = nextPosition[DIM_Y];
240 outgoingDirection[DIM_X] = incomingDirection[DIM_X];
241 outgoingDirection[DIM_Y] = incomingDirection[DIM_Y];
242 }
243
244 // Out of the Black box? (loop exit condition)
245 if (positionInTheBox(position)) {
246 points.append(absolutePositionToBoxPosition(position));
247 getOutgoingPosition( position, outgoingDirection, points );
248 } else if (deviation)
249 // special case: Deviation entering the black box. Player should see the laser ray entering, even if it's in fact deviated before entering...
250 points.append(absolutePositionToBoxPosition(nextPosition));
251
252 return;
253}
254
255
256bool KBBBallsOnBoard::positionInTheBox( int position[DIM_MAX] )
257{
258 return !((position[DIM_X] < 2) || (position[DIM_X] > m_columns + 1) || (position[DIM_Y] < 2) || (position[DIM_Y] > m_rows + 1));
259}
260
261#include "kbbballsonboard.moc"
262