📄 gamedata.java
字号:
/*
* Copyright, 2005, S.E.Morris, C.Speirs
*
* This file is part of SudokuME.
*
* SudokuME is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* SudokuME is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SudokuME; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package sudoku;
import java.io.*;
import java.util.Date;
import javax.microedition.rms.*;
// *********************************************************************
// This class encapsulates a single game, including its ability to
// store and recover its own state using a device's record store.
//
// One constructor is used to create a new game (based upon the grid
// size) while the other is used to recreate a list of saved games from
// a record store, via the static load() method.
//
// FIX: Load/save code needs refactoring and optimsing wrt. footprint.
// *********************************************************************
class GameData
{ int recordId; // Record store key
byte formatVersion; // File format version
Date creationDate,savedDate; // Date
int timer; // Seconds so far
String title; // Game title
int gridSz; // Grid size
byte[][] grid; // Game data
boolean[][] locked; // Locked cells
short[][] working; // Working out
int setW,setH; // Set width and height
final int DEFAULT_MAX_SOLUTIONS=20; // if not otherwise defined, is the maximum number of solutions that will be searched for
boolean[][] collisions; // Collisions with current cell
static String lastErrorMessage=null; // Last error message accessing record store
// -----Record store and file format constants
private final static int TITLE_SZ = 20;
// CONSTRUCTOR: FIX - needed to get class in static context
// see 'load(String rName)' below
private GameData() {}
// -----------------------------------------------------------------
// CONSTRUCTOR: new game - just pass the grid size.
// -----------------------------------------------------------------
GameData(int sz)
{
this(sz,new byte[sz][sz],null);
}
// -----------------------------------------------------------------
// CONSTRUCTOR: from online - grid size and initial grid data.
// -----------------------------------------------------------------
GameData(int sz,byte[][] g,String t)
{ recordId=-1; title=t;
creationDate = new Date();
gridSz=sz;
grid = g;
locked = new boolean[gridSz][gridSz];
working = new short[gridSz][gridSz];
for(int y=0;y<gridSz;y++)
for(int x=0;x<gridSz;x++)
locked[x][y]=(grid[x][y]>0);
_init();
}
// -----------------------------------------------------------------
// CONSTRUCTOR: from record store - record id and record bytes
// -----------------------------------------------------------------
private GameData(int id,byte[] buff) throws IOException
{ this( new DataInputStream(new ByteArrayInputStream(buff)) );
recordId=id;
}
// -----------------------------------------------------------------
// PRIVATE CONSTRUCTOR: from data stream
// -----------------------------------------------------------------
private GameData(DataInputStream dis) throws IOException
{ recordId=-1;
formatVersion = dis.readByte(); // (2+) Format version number
if (formatVersion >= 4) {
// check this is a save game
if (dis.readByte() != SudokuME.SAVE_GAME_RECORD) {
throw new IOException("Stream does not represent a Save Game");
}
}
creationDate = new Date(dis.readLong()); // (2+) Date first started
savedDate = new Date(dis.readLong()); // (2+) Date last saved
if(formatVersion>=3)
{ timer = dis.readInt(); // (3+) Timer
title = _readASCIIString(TITLE_SZ,dis); // (3+) String title
}
gridSz = dis.readByte(); // (2+) Grid size
grid = new byte[gridSz][gridSz];
locked = new boolean[gridSz][gridSz];
working = new short[gridSz][gridSz];
_readRLE_8(grid,dis); // (2+) Grid data
_readBools(locked,dis); // (2+) Locked data
_readRLE_16(working,dis); // (2+) Working data
dis.close();
_init();
}
private void _init()
{ if(title==null) title=gridSz+"x"+gridSz;
switch(gridSz)
{ case 9 : setW=3; setH=3; break;
case 12 : setW=4; setH=3; break;
}
collisions = new boolean[gridSz][gridSz];
updateCollisions(0,0);
}
static void _readRLE_8(byte[][] arr,DataInputStream dis) throws IOException
{ int gridSz=arr.length;
//System.out.println("--");
for(int i=0;i<gridSz*gridSz;i++)
{ int val=dis.readByte();
if((val&0x80)!=0)
{ int rpt=val&0x7f;
val=dis.readByte();
//System.out.println("C:"+rpt+":"+val);
for(int j=i;j<i+rpt;j++) arr[j%gridSz][j/gridSz]=(byte)val;
i+=(rpt-1);
}
else
{ //System.out.println("B:"+val);
arr[i%gridSz][i/gridSz]=(byte)val;
}
}
}
private static void _readRLE_16(short[][] arr,DataInputStream dis) throws IOException
{ int gridSz=arr.length;
//System.out.println("--");
for(int i=0;i<gridSz*gridSz;i++)
{ int val=dis.readShort();
if((val&0x8000)!=0)
{ int rpt=val&0x7fff;
val=dis.readShort();
//System.out.println("C:"+rpt+":"+val);
for(int j=i;j<i+rpt;j++) arr[j%gridSz][j/gridSz]=(short)val;
i+=(rpt-1);
}
else
{ //System.out.println("B:"+val);
arr[i%gridSz][i/gridSz]=(short)val;
}
}
}
private static void _readBools(boolean[][] arr,DataInputStream dis) throws IOException
{ int gridSz=arr.length;
int l=gridSz*gridSz;
short[] buff = new short[((l%8)==0) ? l/8 : l/8+1];
// -----Read in byte array
for(int i=0;i<buff.length;i++)
buff[i]=(short)(dis.readByte()&0xff);
// -----Extract booleans from bits
for(int i=0;i<l;i++)
{ int bit=(1 << (7-i%8));
int byt=i/8;
arr[i%gridSz][i/gridSz] = ( (buff[byt] & bit) > 0 );
}
}
private static String _readASCIIString(int sz,DataInputStream dis) throws IOException
{ StringBuffer sb = new StringBuffer();
int i=0;
do
{ int b=dis.readByte(); // Next byte
if(b>0) sb.append((char)b); // Zero? No: append
else i=sz; // Yes: exit loop
i++;
}while(i<sz);
return sb.toString();
}
// -----------------------------------------------------------------
// Save this game. If new game, append, else update.
// -----------------------------------------------------------------
boolean save()
{ RecordStore rs=null;
try
{ ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeByte(SudokuME.FORMAT_VERSION);
dos.writeByte(SudokuME.SAVE_GAME_RECORD);
dos.writeLong(creationDate.getTime()); // (2+) Date first started
dos.writeLong(new Date().getTime()); // (2+) Date last saved
dos.writeInt(timer); // (3+) Timer
_writeASCIIString(title,TITLE_SZ,dos); // (3+) String title
dos.writeByte((byte)(gridSz&0x7f)); // (2+) Grid size
_writeRLE_8(grid,dos); // (2+) Grid data
_writeBools(locked,dos); // (2+) Locked data
_writeRLE_16(working,dos); // (2+) Working data
dos.close();
byte[] buff = baos.toByteArray();
rs = RecordStore.openRecordStore(SudokuME.REC_STORE_NAME,true);
if(recordId==-1)
{ // -----New game, so append record
if(buff.length<=rs.getSizeAvailable())
{ recordId=rs.addRecord(buff,0,buff.length);
return true;
}
else
{ lastErrorMessage="Not enough space in record store.";
return false;
}
// FIX else show warning
}
else
{ // -----Existing game, so update record
rs.setRecord(recordId,buff,0,buff.length);
return true;
}
}
catch(Exception e)
{ if(SudokuME.debug) e.printStackTrace();
lastErrorMessage="Exception: "+e.toString();
return false;
}
finally
{ try { rs.closeRecordStore(); }catch(Exception e) {}
}
}
private static void _writeRLE_8(byte[][] arr,DataOutputStream dos) throws IOException
{ int gridSz=arr.length;
//System.out.println("--");
for(int i=0;i<gridSz*gridSz;i++)
{ int val=arr[i%gridSz][i/gridSz];
int end=_findRepeat_8(arr,i);
if((end-i)>3)
{ int a=(end-i)&0x7f;
//System.out.println("C:"+a+":"+val);
dos.writeByte(0x80+a); // frrrrrrr
dos.writeByte(val);
i=end-1;
}
else
{ //System.out.println("B:"+val);
dos.writeByte(val);
}
//System.out.println( val+" "+(start%gridSz)+","+(start/gridSz)+" "+(i%gridSz)+","+(i/gridSz) );
}
}
private static int _findRepeat_8(byte[][] arr,int start)
{ int gridSz=arr.length;
int end=start;
byte val=arr[start%gridSz][start/gridSz];
while
( end<gridSz*gridSz && // Smaller than grid?
end<=0x7f && // Smaller than max repeat token size
arr[end%gridSz][end/gridSz]==val // Same value?
) end++;
return end;
}
private static void _writeRLE_16(short[][] arr,DataOutputStream dos) throws IOException
{ int gridSz=arr.length;
//System.out.println("--");
for(int i=0;i<gridSz*gridSz;i++)
{ int val=arr[i%gridSz][i/gridSz];
int end=_findRepeat_16(arr,i);
if((end-i)>3)
{ int a=(end-i)&0x7fff;
//System.out.println("C:"+a+":"+val);
dos.writeShort((short)0x8000+a); // frrrrrrr.rrrrrrrr
dos.writeShort((short)val);
i=end-1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -