1/*
2 Copyright (C) 1997 Mathias Mueller <in5y158@public.uni-hamburg.de>
3 Copyright (C) 2006 Mauricio Piacentini <mauricio@tabuleiro.com>
4
5 Kmahjongg is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include "BoardLayout.h"
21#include <QFile>
22#include <qtextstream.h>
23#include <qtextcodec.h>
24
25BoardLayout::BoardLayout()
26{
27 filename="";
28 m_width = 32;
29 m_height = 16;
30 m_depth = 5;
31 board = QByteArray(m_width*m_height*m_depth, 0);
32 clearBoardLayout();
33}
34
35BoardLayout::BoardLayout(const BoardLayout &boardLayout)
36{
37 m_width = boardLayout.m_width;
38 m_height = boardLayout.m_height;
39 m_depth = boardLayout.m_depth;
40 m_maxTiles = boardLayout.m_maxTiles;
41 maxTileNum = boardLayout.getMaxTileNum();
42 filename = boardLayout.getFilename();
43 board = boardLayout.getBoard();
44 loadedBoard = boardLayout.getLoadedBoard();
45}
46
47BoardLayout::~BoardLayout()
48{
49}
50
51QString BoardLayout::getFilename() const
52{
53 return filename;
54}
55
56QByteArray BoardLayout::getLoadedBoard() const
57{
58 return loadedBoard;
59}
60
61QByteArray BoardLayout::getBoard() const
62{
63 return board;
64}
65
66unsigned short BoardLayout::getMaxTileNum() const
67{
68 return maxTileNum;
69}
70
71void BoardLayout::clearBoardLayout() {
72 loadedBoard="";
73 initialiseBoard();
74}
75
76bool BoardLayout::saveBoardLayout(const QString &where) {
77 QFile f(where);
78 if (!f.open(QIODevice::ReadWrite)) {
79 return false;
80 }
81
82 QByteArray tmp = layoutMagic1_1.toUtf8();
83 if (f.write(tmp, tmp.length()) == -1) {
84 return(false);
85 }
86
87 tmp = QString("\nw%1").arg(m_width).toUtf8();
88 if (f.write(tmp, tmp.length()) == -1) {
89 return(false);
90 }
91
92 tmp = QString("\nh%1").arg(m_height).toUtf8();
93 if (f.write(tmp, tmp.length()) == -1) {
94 return(false);
95 }
96
97 tmp = QString("\nd%1").arg(m_depth).toUtf8();
98 if (f.write(tmp, tmp.length()) == -1) {
99 return(false);
100 }
101
102 for (int z=0; z<m_depth; z++) {
103 for(int y=0; y<m_height; y++) {
104 if(!f.putChar('\n'))
105 return(false);
106 for (int x=0; x<m_width; x++) {
107 if (getBoardData(z,y,x)) {
108 if(!f.putChar(getBoardData(z,y,x)))
109 return false;
110 } else {
111 if(!f.putChar('.'))
112 return false;
113 }
114 }
115 }
116 }
117 return f.putChar('\n');
118}
119
120bool BoardLayout::loadBoardLayout_10(const QString &from)
121{
122 if (from == filename) {
123 return true;
124 }
125
126 QFile f(from);
127 QString all = "";
128
129 if ( f.open(QIODevice::ReadOnly) ) {
130 QTextStream t( &f );
131 t.setCodec(QTextCodec::codecForName("UTF-8"));
132 QString s;
133 s = t.readLine();
134 if (s != layoutMagic1_0) {
135 f.close();
136 return(false);
137 }
138 //version 1.0 layouts used hardcoded board dimensions
139 m_width = 32;
140 m_height = 16;
141 m_depth = 5;
142 int lines = 0;
143 while ( !t.atEnd() ) {
144 s = t.readLine();
145 if (s[0] == '#')
146 continue;
147 all += s;
148 lines++;
149 }
150 f.close();
151 if (lines == m_height*m_depth) {
152 loadedBoard = all.toLatin1();
153 initialiseBoard();
154 filename = from;
155 return(true);
156 } else {
157 return(false);
158 }
159 return(true);
160 } else {
161 return(false);
162 }
163}
164
165bool BoardLayout::loadBoardLayout(const QString &from)
166{
167 if (from == filename) {
168 return true;
169 }
170
171 QFile f(from);
172 QString all = "";
173 if ( f.open(QIODevice::ReadOnly) ) {
174 QTextStream t( &f );
175 t.setCodec(QTextCodec::codecForName("UTF-8"));
176 QString s;
177 s = t.readLine();
178 if (s != layoutMagic1_1) {
179 f.close();
180 //maybe a version 1_0 layout?
181 return(loadBoardLayout_10(from));
182 }
183 int lines = 0;
184 m_width = m_height = m_depth = 0;
185 while ( !t.atEnd() ) {
186 s = t.readLine();
187 if (s[0] == '#')
188 continue;
189 if (s[0] == 'w') {
190 m_width = s.mid(1).toInt();
191 continue;
192 }
193 if (s[0] == 'h') {
194 m_height = s.mid(1).toInt();
195 continue;
196 }
197 if (s[0] == 'd') {
198 m_depth = s.mid(1).toInt();
199 continue;
200 }
201 all += s;
202 lines++;
203 }
204 f.close();
205 if ((lines == m_height*m_depth)&&(m_width>0)&&(m_height>0)&&(m_depth>0)) {
206 loadedBoard = all.toLatin1();
207 initialiseBoard();
208 filename = from;
209 return(true);
210 } else {
211 return(false);
212 }
213 return(true);
214 } else {
215 return(false);
216 }
217}
218
219void BoardLayout::initialiseBoard() {
220 short z=0;
221 short x=0;
222 short y=0;
223 maxTileNum = 0;
224
225 m_maxTiles = (m_width*m_height*m_depth)/4;
226 board.resize(m_width*m_height*m_depth);
227 board.fill(0);
228
229 if (loadedBoard.isEmpty()) {
230 return;
231 }
232
233 int idx = 0;
234 // loop will be left by break or return
235 while( true )
236 {
237 BYTE c = loadedBoard.at(idx++);
238 switch( c )
239 {
240 case (UCHAR)'1': maxTileNum++;
241 case (UCHAR)'3':
242 case (UCHAR)'2':
243 case (UCHAR)'4': setBoardData(z,y,x,c);
244 break;
245
246 default: setBoardData(z,y,x,0);
247 break;
248 }
249 if( ++x == m_width)
250 {
251 x=0;
252 if( ++y == m_height)
253 {
254 y=0;
255 if( ++z == m_depth)
256 {
257 // number of tiles have to be even
258 if( maxTileNum & 1 ) break;
259 return;
260 }
261 }
262 }
263 }
264}
265
266void BoardLayout::copyBoardLayout(UCHAR *to , unsigned short &n){
267 memcpy(to, board.data(), m_width*m_height*m_depth);
268 n = maxTileNum;
269}
270
271void BoardLayout::shiftLeft() {
272 for (int z=0; z<m_depth; z++) {
273 for (int y=0; y<m_height; y++) {
274 UCHAR keep=getBoardData(z,y,0);
275 if (keep == '1') {
276 // tile going off board, delete it
277 setBoardData(z,y,0,0);
278 setBoardData(z,y,1,0);
279 if (y<m_height-1) {
280 setBoardData(z,y+1,0,0);
281 setBoardData(z,y+1,1,0);
282 }
283 }
284 for (int x=0; x<m_width-1; x++) {
285 setBoardData(z,y,x,getBoardData(z,y,x+1));
286 }
287 setBoardData(z,y,m_width-1,0);
288 }
289 }
290}
291
292
293void BoardLayout::shiftRight() {
294 for (int z=0; z<m_depth; z++) {
295 for (int y=0; y<m_height; y++) {
296 UCHAR keep=getBoardData(z,y,m_width-2);
297 if (keep == '1') {
298 // tile going off board, delete it
299 setBoardData(z,y,m_width-2,0);
300 setBoardData(z,y,m_width-1,0);
301 if (y < m_height-1) {
302 setBoardData(z,y+1,m_width-2,0);
303 setBoardData(z,y+1,m_width-1,0);
304 }
305 }
306 for (int x=m_width-1; x>0; x--) {
307 setBoardData(z,y,x,getBoardData(z,y,x-1));
308 }
309 setBoardData(z,y,0,0);
310 }
311 }
312}
313void BoardLayout::shiftUp() {
314 for (int z=0; z<m_depth; z++) {
315 // remove tiles going off the top
316 for (int x=0; x<m_width; x++) {
317 if (getBoardData(z,0,x) == '1') {
318 setBoardData(z,0,x,0);
319 if (x<m_width-1) {
320 setBoardData(z,0,x+1,0);
321 setBoardData(z,1,x+1,0);
322 }
323 setBoardData(z,1,x,0);
324 }
325 }
326 }
327 for (int z=0; z<m_depth;z++) {
328 for (int y=0; y<m_height-1; y++) {
329 for (int x=0; x<m_width; x++) {
330 setBoardData(z,y,x,getBoardData(z,y+1,x));
331 if (y == m_height-2)
332 setBoardData(z,y+1,x,0);
333 }
334 }
335 }
336}
337
338
339void BoardLayout::shiftDown() {
340 for (int z=0; z<m_depth; z++) {
341 // remove tiles going off the top
342 for (int x=0; x<m_width; x++) {
343 if (getBoardData(z,m_height-2,x) == '1') {
344 setBoardData(z,m_height-2,x,0);
345 if (x<m_width-1) {
346 setBoardData(z,m_height-2,x+1,0);
347 setBoardData(z,m_height-1,x+1,0);
348 }
349 setBoardData(z,m_height-1,x,0);
350 }
351 }
352 }
353 for (int z=0; z<m_depth;z++) {
354 for (int y=m_height-1; y>0; y--) {
355 for (int x=0; x<m_width; x++) {
356 setBoardData(z,y,x,getBoardData(z,y-1,x));
357 if (y == 1)
358 setBoardData(z,y-1,x,0);
359 }
360 }
361 }
362}
363
364
365// is there a tile anywhere above here (top left to bot right quarter)
366bool BoardLayout::tileAbove(short z, short y, short x) {
367 if (z >= m_depth -1)
368 return false;
369 if( getBoardData(z+1,y,x) || getBoardData(z+1,y+1,x) || getBoardData(z+1,y,x+1) || getBoardData(z+1,y+1,x+1) ) {
370 return true;
371 }
372 return false;
373}
374
375
376bool BoardLayout::blockedLeftOrRight(short z, short y, short x) {
377 return( (getBoardData(z,y,x-1) || getBoardData(z,y+1,x-1)) &&
378 (getBoardData(z,y,x+2) || getBoardData(z,y+1,x+2)) );
379}
380
381void BoardLayout::deleteTile(POSITION &p) {
382 if ( p.e <m_depth && getBoardData(p.e,p.y,p.x) == '1') {
383 setBoardData(p.e,p.y,p.x,0);
384 setBoardData(p.e,p.y,p.x+1,0);
385 setBoardData(p.e,p.y+1,p.x,0);
386 setBoardData(p.e,p.y+1,p.x+1,0);
387 maxTileNum--;
388 }
389}
390
391bool BoardLayout::anyFilled(POSITION &p) {
392 return(getBoardData(p.e, p.y, p.x) != 0 ||
393 getBoardData(p.e, p.y, p.x+1) != 0 ||
394 getBoardData(p.e, p.y+1, p.x) != 0 ||
395 getBoardData(p.e, p.y+1, p.x+1) != 0);
396}
397bool BoardLayout::allFilled(POSITION &p) {
398 return(getBoardData(p.e, p.y, p.x) != 0 &&
399 getBoardData(p.e, p.y, p.x+1) != 0 &&
400 getBoardData(p.e, p.y+1, p.x) != 0 &&
401 getBoardData(p.e, p.y+1, p.x+1) != 0);
402}
403void BoardLayout::insertTile(POSITION &p) {
404 setBoardData(p.e,p.y,p.x,'1');
405 setBoardData(p.e,p.y,p.x+1,'2');
406 setBoardData(p.e,p.y+1,p.x+1,'3');
407 setBoardData(p.e,p.y+1,p.x,'4');
408}
409
410UCHAR BoardLayout::getBoardData(short z, short y, short x) {
411 return board.at((z*m_width*m_height)+(y*m_width)+x);
412}
413
414void BoardLayout::setBoardData(short z, short y, short x, UCHAR value) {
415 board[(z*m_width*m_height)+(y*m_width)+x] = value;
416}
417
418
419
420
421
422
423
424
425