4
* Copyright (C) Federico Vera 2010-2011 <dktcoding [at] gmail>
6
* PictoGame is free software: you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the
8
* Free Software Foundation, either version 3 of the License, or any later
11
* PictoGame is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
* See the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program. If not, see <http://www.gnu.org/licenses/>.
22
import java.io.BufferedReader;
24
import java.io.FileNotFoundException;
25
import java.io.FileReader;
26
import java.io.IOException;
27
import java.io.InputStream;
28
import java.io.InputStreamReader;
29
import java.io.Serializable;
30
import java.util.ArrayList;
31
import java.util.Arrays;
32
import java.util.logging.Level;
33
import java.util.logging.Logger;
34
import picto.app.interfaces.Flushable;
37
* This class represents the pattern file.<br>
38
* The pattern files contain the following information:<br><ol>
39
* <li><b>Title</b> -- The name of the pattern
40
* <li><b>Author</b> -- Who created the pattern
41
* <li><b>Date</b> -- The date the pattern was added to the game
42
* <li><b>X size</b> -- Number of columns of the pattern
43
* <li><b>y size</b> -- Number of rows of the pattern
44
* <li><i>blank line</i>
45
* <li><b>Data row 1</b>
46
* <li><b>Data row 2</b>
47
* <li><b>Data row ...</b>
48
* <li><b>Data row n</b></ol>
49
* The data is represented row by row with <tt>64-bit</tt> numbers in hex
50
* (without the <tt>'0x'</tt> identifier), as you know each number is
51
* represented by bits in this case each <tt>1</tt> means that the cell should
52
* be painted and as you might gather each <tt>0</tt> means that the cell should
55
* @author Fido <dktcoding [at] gmail>
57
public final class Picto implements Serializable, Flushable {
58
private static final long serialVersionUID = -535901729081793261L;
59
private transient byte [][] columnHeaders;
60
private transient byte [][] rowHeaders;
61
private transient boolean[][] board;
62
private transient long[] columns;
64
private String title = "";
65
private String author = "";
66
private String date = "";
67
private byte numberOfRows;
68
private byte numberOfColumns;
69
private int numberOfMarkedCells;
71
public Picto(int i, int j){
72
this((byte)i, (byte)j);
75
public Picto(byte i, byte j){
76
board = new boolean[i][j];
82
* Creates a new Picto board from a file
84
* @param input input file
85
* @param justInfo this flag tells the constructor if you are using
86
* the Picto to get information or to play.
88
public Picto(InputStream input, boolean justInfo){
89
loadBoardFromPatternFile(new BufferedReader(new InputStreamReader(input)));
95
public Picto(BufferedReader buff){
96
loadBoardFromPatternFile(buff);
99
public Picto(File file){
100
if (file.getName().toLowerCase().endsWith("sgriddler")){
101
loadBoardFromSGriddlerFile(file);
103
} else if (file.getName().toLowerCase().endsWith("pattern")){
105
loadBoardFromPatternFile(new BufferedReader(new FileReader(file)));
107
} catch (FileNotFoundException ex) {
108
Logger.getLogger(Picto.class.getName()).log(Level.SEVERE, null, ex);
114
* Generates the headers and the board
116
public void regenerate(){
121
* Remove all unnecessary things. This method is called when you finish
126
columnHeaders = null;
132
public long getRow(int i){
136
public long getColumn(int i){
137
if (columns == null){
143
public void setElement(int i, int j, boolean e){
147
public boolean getElement(int i, int j){
151
public byte getColumnHeaderNum(){
152
return (byte)columnHeaders[0].length;
155
public byte getRowHeaderNum(){
156
return (byte)rowHeaders[0].length;
159
public byte getColumnHeadersElement(int i, int j) {
160
return columnHeaders[i][j];
163
public byte getRowHeadersElement(int i, int j) {
164
return rowHeaders[i][j];
167
public byte getNumberOfColumns() {
168
return numberOfColumns;
171
public void setNumberOfColumns(byte numberOfColumns) {
172
this.numberOfColumns = numberOfColumns;
175
public byte getNumberOfRows() {
179
public void setNumberOfRows(byte numberOfRows) {
180
this.numberOfRows = numberOfRows;
183
public String getTitle() {
187
public void setTitle(String title) {
191
public String getAuthor() {
192
return author == null || author.isEmpty() ? "Unknown" : author;
195
public void setAuthor(String author) {
196
this.author = author;
199
public String getDate() {
203
public void setDate(String date) {
207
private static final int TITLE_LENGTH = "# Title: " .length();
208
private static final int AUTHOR_LENGTH = "# Author: " .length();
209
private static final int DATE_LENGTH = "# Date: " .length();
210
private static final int X_SIZE_LENGTH = "# X size: " .length();
211
private static final int Y_SIZE_LENGTH = "# Y size: " .length();
213
* Loads a pattern from a panel
215
* @param file the file to read
217
private void loadBoardFromPatternFile(BufferedReader file){
220
setTitle (file.readLine().substring(TITLE_LENGTH));
221
setAuthor(file.readLine().substring(AUTHOR_LENGTH));
222
setDate (file.readLine().substring(DATE_LENGTH));
223
line = file.readLine().substring(X_SIZE_LENGTH);
224
setNumberOfColumns(Byte.valueOf(line));
225
line = file.readLine().substring(Y_SIZE_LENGTH);
226
setNumberOfRows(Byte.valueOf(line));line = file.readLine();
227
data = new long[numberOfRows];
228
numberOfMarkedCells = 0;
230
for(byte i = 0; i < numberOfRows; i++){
231
data[i] = Long.valueOf(file.readLine(), 16);
232
numberOfMarkedCells += Long.bitCount(data[i]);
235
} catch (IndexOutOfBoundsException ex) {
236
Logger.getLogger(Picto.class.getName()).log(Level.SEVERE, null, ex);
237
} catch (IOException ex) {
238
Logger.getLogger(Picto.class.getName()).log(Level.SEVERE, null, ex);
242
public static Picto loadBoardFromSGriddlerFile(File file_name){
246
BufferedReader file = new BufferedReader(new FileReader(file_name));
249
line = file.readLine();
250
String[] spLine = line.split(" ");
251
temp = new Picto(Byte.valueOf(spLine[1]),
252
Byte.valueOf(spLine[0]));
254
temp.data = new long[temp.numberOfRows];
255
temp.numberOfMarkedCells = 0;
257
for(byte i = 0, n = (byte)temp.numberOfRows; i < n; i++){
258
line = file.readLine();
259
line = line.replace(" ", "" );
260
line = line.replace('#', '1');
261
line = line.replace('.', '0');
262
temp.data[i] = Long.valueOf(line, 2);
263
temp.numberOfMarkedCells += Long.bitCount(temp.data[i]);
267
temp.loadColumnHeaders();
268
temp.loadRowHeaders();
270
} catch (IndexOutOfBoundsException ex) {
271
Logger.getLogger(Picto.class.getName()).log(Level.SEVERE, null, ex);
272
} catch (IOException ex) {
273
Logger.getLogger(Picto.class.getName()).log(Level.SEVERE, null, ex);
279
* Load the headers and the binary panel
281
private void loadHeaders(){
293
* Loads the binary panel from the data
295
private void loadPanel(){
296
board = new boolean[numberOfRows][numberOfColumns];
297
for(int i = 0; i < numberOfRows; i++){
298
for (int j = numberOfColumns - 1, k = 0; j >= 0; j--){
299
board[i][k++] = (data[i] & (1L << j)) != 0;
305
* Load the row headers from the data
307
* @TODO clean up and optimize this a "little" bit
309
private void loadRowHeaders(){
310
ArrayList<ArrayList<Byte>> rows = new ArrayList<ArrayList<Byte>>(numberOfRows);
314
for (boolean[] row : board){
315
ArrayList<Byte> temp = new ArrayList<Byte>(5);
318
for (boolean cell : row){
321
} else if (counter != 0){
331
if (max_e < temp.size()){
338
rowHeaders = new byte[numberOfRows][max_e];
340
for (ArrayList<Byte> foo : rows){
341
for (int j = foo.size()-1, pos = max_e; j >= 0; j--){
342
rowHeaders[counter][--pos] = foo.get(j);
350
* Load the column headers from the data
352
* @TODO clean up and optimize this a "little" bit
354
private void loadColumnHeaders(){
355
ArrayList<ArrayList<Byte>> cols = new ArrayList<ArrayList<Byte>>(numberOfColumns);
359
for (int i = 0; i < numberOfColumns; i++){
360
ArrayList<Byte> temp = new ArrayList<Byte>(5);
363
for (int j = 0; j < numberOfRows; j++){
366
} else if (counter != 0){
376
if (max_e < temp.size()){
384
columnHeaders = new byte[numberOfColumns][max_e];
386
for (ArrayList<Byte> foo : cols){
387
for (int j = foo.size()-1, pos = max_e; j >= 0; j--){
388
columnHeaders[counter][--pos] = foo.get(j);
395
* Returns the sum of all the marked cells
397
* @return number of marked cells
399
public int getNumberOfMarkedCells() {
400
return numberOfMarkedCells;
404
* This method calculates the vertical data, is used by the solver
406
private void calculateColumns(){
411
columns = new long[numberOfRows];
414
for (i = 0; i < numberOfColumns; i++){
415
for (j = 0; j < numberOfRows; j++){
425
* Loads the data from the binary board, this method is called
426
* when you save a newly created pattern
428
private void loadData(){
429
numberOfMarkedCells = 0;
430
data = new long[numberOfRows];
433
for (i = 0; i < numberOfRows; i++){
434
for (j = 0; j < numberOfColumns; j++){
438
numberOfMarkedCells++;
445
public boolean equals(Object obj) {
446
if (obj == null || getClass() != obj.getClass()) {
450
for (int i = 0; i < numberOfRows; i++){
451
if (data[i] != ((Picto)obj).getRow(i)){
460
public int hashCode() {
461
return 41 * 7 + Arrays.hashCode(data);
465
* Generates the representation of a board to be saved as a playing board
466
* @return board to save
468
public String toSavingString(){
469
StringBuilder tmpStr = new StringBuilder(512);
471
tmpStr.append("# Title: ")
473
.append("\n# Author: ")
475
.append("\n# Date: ")
477
.append("\n# X size: ")
478
.append(numberOfColumns)
479
.append("\n# Y size: ")
480
.append(numberOfRows)
487
for (int i = 0; i < numberOfRows; i++) {
488
tmpStr.append(Long.toHexString(data[i]))
492
return tmpStr.toString();
496
public String toString(){
497
StringBuilder str = new StringBuilder(numberOfRows * (numberOfColumns + 1));
499
for (boolean[] row : board){
500
for (boolean marked_cell : row){
501
str.append(marked_cell ? '*' : '_');
506
return str.toString();