⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sudokume.java

📁 sudoku j2me手机游戏主要有游戏主类和闪屏类菜单类和模型类等
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
package sudoku;

import java.util.*;
import java.io.IOException;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
/*
 *  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
 */

// Stuff to do:
// X) Check if records can be saved to store (enough space).
// X) Scrolling on record selection page
// X) Downloadable puzzles
// X) CatEntry should only load when tab selected
// X) Puzzle solver
// -) Puzzle generator
//    -) make solver select a random solution if multiple are possible
//    -) to generate, add locked cells until there is only a single solution.
// -) Improved puzzle generator
//    -) make solver able to rate a game 
//    -) use the rating to filter the found games.
// X) Optmised load/save
// X) Replace startGrid with lock booleans
// X) Better list support - with download waiting
// X) Credits/copyright
// X) Timer
// X) Titles in save game
// X) Compression on online content
// -) Better error reporting
// X) Completion check
// X) Sub menus in cat.txt
// X) Undo feature
// -) Improve undo - undo working and save undo. 
// X) Rename save title
// X) Improve UI - Allow user to identify if working list is complete or not - press * when editing working - changes ? to .
// X) Improve UI - If user has separate left/right/up/down/working sel then allow movement in grid when working is selected
// *) Allow saved games to be loaded from elsewhere (file browser) - useful if peoples telco doesnt
//    allow external access
// X) make keys user programmable (and savable) - allows for user friendly keys on telephones that support it
//    Keys needed: menu, Shift, left, right, up, down, have<1-9>, undo, working, timer, lock_working, lock_cell, increment
//    UI as follows: list of keys.  soft keys to clear or program. last option: done.  When starting
//    a game, check that enough keys are available - menu accessible, increment or 1-9 (resp 0-9,*,#) available.
// -) allow different keys for a 12x12 game and a 9x9 game
// X) Work out UI for 12x12 grid (using *,0,#)
// X) on forced exit, save the game.
// X) can we make it full screen?
// X) If screen is wider than it is tall, then put working on the side
// X) Allow user to select full screen mode, if MIDP2 is supported
// -) Zoomed working mode? - View working for all cells in a row/column/group?
// -) Improve performance by using GameUI?
// X) To identify the phone, use System.getProperty("microedition.platform")
// -) Improve start up menus - use normal hierarchical system. main menu - (Continue) / New game(9x9,12x12,test,load from file, load from online) / load saved game / Options (set keys, set fullscreen, set online catalog) / exit
//    Main Menu:        List: [Continue],[End],New Game,Instructions,Options
//    New Game:         List: 9x9, 12x12,Test Grid, Load from File, Load from online
//    Load from file:   To be implemented
//    Load from online: Investigate how to link to current code
//    Instructions:     List: Rules, Key Definitions, Programming Keys, About
//    Options:          Load ProgKeys list/display.
//
// 


// *********************************************************************
// Main class.
// *********************************************************************
public class SudokuME extends MIDlet implements MenuListener,GameSelectionListener
{	// -----State data
	private GameData game;					// Game data object
    public static ProgKeys programmedKeyCodes;
	private long timeStarted;				// Timer working values
	private long timeAway,timeAwayStart;	// Ditto
	private int mode=MENU;					// Current display mode

	private final static int MENU=0;		// Mode 0 : load/new menu
	private final static int GRID=1;		// Mode 1 : game
	private final static int TOPLEFT = Graphics.TOP|Graphics.LEFT;
	private final static int CENTERED = Graphics.TOP|Graphics.HCENTER;

	final static byte FORMAT_VERSION = 4;
	final static byte SAVE_GAME_RECORD = 1;
	final static byte KEYCODE_RECORD = 2;
	final static String REC_STORE_NAME = "SudokuME";

	// -----Transient data.  Can be deleted when paused.
	public static Display display;				// Our display (handy!)
	static boolean debug=false;				// Switch on dumping of exceptions
	static String catalogueAddr=null;		// Location of on-line catalogue (from JAD)
	static OnlineDirectory onlineCatalogue;	// Online oatalogue root
	static OnlineEntry selectedBundle;		// Download bundle selection
	static OnlineDirectory selectedOnlineCatalogueDir; // Current catalogue directory
    static boolean hasMIDP2 = false;


	// -----------------------------------------------------------------
	// MIDlet lifecycle.
	// -----------------------------------------------------------------
	public void startApp() throws MIDletStateChangeException
	{	// -----Create display
		display = Display.getDisplay(this);
        programmedKeyCodes = new ProgKeys();
        if (System.getProperty("microedition.profiles").indexOf("MIDP-2") != -1) {
            hasMIDP2 = true;
        } else {
            hasMIDP2 = false;
        }

		// -----Location of Catalogue file
		catalogueAddr = getAppProperty("SudokuME-Catalogue-Addr");
		debug = getAppProperty("SudokuME-Debug").equals("true");

		// -----Set display based upon current mode
		Displayable displayable=null;
		switch(mode)
		{	case MENU :
				displayable = new GameSelection(display,this);
				break;
			case GRID :
				displayable = new GridDisplay();
				break;
		}
		display.setCurrent(displayable);
	}
	public void pauseApp()
	{	// -----Release all non-essensial resources here (anything we can
		// -----recreate later on).
		if(mode==GRID)  pauseTimer();
		// -----See footnote 1 at the bottom  of this file.
		if(mode==MENU)  ((GameSelection)display.getCurrent()).destroy();

		display=null;  catalogueAddr=null;
		onlineCatalogue=null;  selectedBundle=null;
		selectedOnlineCatalogueDir=null;
		OnlineEntry.reset();
	}
	public void destroyApp(boolean unconditional)
	{	pauseApp();

		if(!unconditional) {	// -----Ask if we want to save first
			final String[][] optStr = { { "Discard game","Save before exiting" } };
			final int[][] optInt = { { 100,0 } };
			new Menu(display,this,optStr,optInt,-1,-1);
			// 'game' gets set to null by menu handler
		} else {	// -----Just get the hell out of here, pronto
			game.save();
            game=null;
		}
	}

	public void menuSelection(int code)
	{	if(code==100)  game.save();
		game=null;
	}

	// -----------------------------------------------------------------
	// These three methods allow us to time how long a player takes to
	// play a grid.  This is much more problematic than it would seem, as
	// we have to take account of pauses in the action - for example when
	// menus are accessed, the "About screen" is shown, or the game is
	// interrupted (startApp/pauseApp).
	//
	// We do this my maintaining two variables: one which is the time play
	// started (timeStarted) and the other the total amount of time away
	// from the action (timeAway), excluding the current period if currently
	// paused.  A third (timeAwayStarted) is used to time each period of
	// inaction, which is added to the total once the period ends.
	//
	//   resetTimer() should be used when entering a game.
	//   pauseTimer() should be used when entering an untimed period.
	//   startTimer() should be used to start/restart the timer.
	// -----------------------------------------------------------------
	private synchronized void resetTimer()
	{	//System.out.println("r");
		// -----Set start time *BUT* make allowances for time already
		// -----played and saved in save game record (stored as seconds).
		timeStarted=System.currentTimeMillis()-game.timer*1000;
		timeAwayStart=0;  timeAway=0;
	}
	private synchronized void startTimer()
	{	//System.out.println("s");
		// -----Are we paused?  Unpause and add on current inaction period to
		// -----total time away, then reset current period.
		if(timeAwayStart>0)
		{	timeAway += System.currentTimeMillis()-timeAwayStart;
		}
		timeAwayStart=0;
	}
	private synchronized void pauseTimer()
	{	//System.out.println("p");
		// -----Are we unpaused?  (Don't pause if already paused!)
		// -----Create new period of inaction.
		if(timeAwayStart==0)
			timeAwayStart=System.currentTimeMillis();
	}
	private synchronized long getTimer()
	{	// -----Current time
		long curr=System.currentTimeMillis();
		// -----Current period of inaction (if paused)
		long away = (timeAwayStart>0) ? curr-timeAwayStart : 0;
		// -----Current time minus time started minus inaction total
		// -----minus current period of inaction.
		return curr-timeStarted-timeAway-away;
	}
	private String getTimerString()
	{	int sec = (int)(getTimer()/1000);
		StringBuffer sb = new StringBuffer("Timer: ");
		sb.append(sec/60).append(":").append((sec%60<10)?"0":"").append(sec%60);
		return sb.toString();
	}

	// -----------------------------------------------------------------
	// GameSelection listener: called once a game has been selected
	// -----------------------------------------------------------------
	public void gameSelected(GameData gd)
	{	game=gd;  mode=GRID;  resetTimer();
		display.setCurrent(new GridDisplay());
	}


	// *****************************************************************
	// The game grid.  This component uses optimised drawing to attempt
	// to speed up the display of the grid, which can have 81 or 144
	// cells depending upon size, and therefore will draw slowly on low
	// spec phones.  To do this an array is used which holds a int
	// representation of what is currently drawn to a cell, in the format...
	//     0001 0000 0000 :  (1 bit) 1=cursor at cell, 0=no cursor at cell
	//     0000 1111 1100 :  (6 bits) tile x in 'digits' image
	//     0000 0000 0011 :  (2 bits) tile y in 'digits' image
	// For each cell the cursor flag, x and y digits' offset are calculated
	// and compared to the current contents.  Only if different will the
	// cell be actually plotted.  Note: a master switch, optPaintAll, is
	// used to draw the entire grid initially, eg: when first displayed or
	// when removing an on-screen menu.
	// *****************************************************************
	private class GridDisplay extends Canvas implements MenuListener, CommandListener
	{	private int xOff,yOff;				// Position of grid, centred
		private int workingH,workingY;		// Position of working out workingH/W is the height/width added to the grid
		private int workingW,workingX;		// Position of working out workingX/Y is the position of the first cell
        private boolean horizWorking=true;  // Is the working grid plotted horizontally or vertically (to side of grid if display is wider than it is tall)
		private int cellW,cellH;			// Height/width of a single cell
		private int cursorX,cursorY;		// Current x/y of cursor on grid
		private int workCursorX;			// Working out cursor
		private Image digits;				// Digits image
		private boolean editGrid=true;		// True=grid, false=working
		
		private boolean shiftFlag=false;	// Holding down Game B key?
		private boolean showTimer=false;	// Show timer on main display

		private int[][] optPaintPrevious;	// Optimised painting of cells
		private int[] optPaintPrevious2;	// Optimised painting of working
		private boolean optPaintAll=true;	// Master switch - paint all, inc. background
		private int optPaintDebug=0;		// Count cells painted

		private byte undoCurrent;			// Value of current cell
		private short[] undoBuffer;			// Undo buffer value:8,x:4,y:4
		private int undoPosition;			// Undo buffer position

        private KeyHelper keyHelper;
        private byte workingDotX[],workingDotY[],workingDotW[],workingDotH[];

		private final String[][] menuStr =
		{	{ "Save","About","Options","Game","Exit","Cancel" },
			{ "Yes","No" },
			{ "Yes","No" },
			{ "","Save","","Don't save","","Cancel" },
			{ "Lock all","Unlock all","Cancel" },
			{ "Recreate","Tidy locked","Tidy numbers","Tidy all","Cancel" },
			{ "Undo","Locks","Working","Solver","Cancel" },
            { "Solved?","Solvable?","Solve","Hint","Fix Errors", "Cancel"},
            { "AutoWork","InCellWork","BlankWork","Cancel" }
		};
		private final int[][] menuInt =
		{	{ 100,500,-8,-6,-3,0 },
			{ 200,0 },
			{ 300,0 },
			{ 0 , 401 , 0 , 402 , 0,0 },
			{ -1,-2,0 },
			{ 600,601,602,603,0 },
			{ 800,-4,-5,-7,0 },
            { 700, 701, 702, 703, 704, 0},
            { 900, 901, 902,0}
		};


        
		// -------------------------------------------------------------
		// CONSTRUCTOR
		// -------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -