|
|
1b8111 |
package com.icystar.findnumber;
|
|
|
1b8111 |
|
|
|
1b8111 |
import java.io.FileInputStream;
|
|
|
1b8111 |
import java.io.FileOutputStream;
|
|
|
1b8111 |
import java.io.IOException;
|
|
|
1b8111 |
import java.util.ArrayList;
|
|
|
1b8111 |
import java.util.List;
|
|
|
1b8111 |
import java.util.Random;
|
|
|
1b8111 |
import java.util.Timer;
|
|
|
1b8111 |
import java.util.TimerTask;
|
|
|
1b8111 |
|
|
|
1b8111 |
import android.content.Context;
|
|
|
1b8111 |
import android.graphics.Canvas;
|
|
|
1b8111 |
import android.graphics.Paint;
|
|
|
1b8111 |
import android.graphics.Point;
|
|
|
1b8111 |
import android.graphics.Rect;
|
|
|
1b8111 |
import android.graphics.Typeface;
|
|
|
1b8111 |
import android.text.TextPaint;
|
|
|
1b8111 |
import android.util.FloatMath;
|
|
|
1b8111 |
import android.view.View;
|
|
|
1b8111 |
import android.widget.TextView;
|
|
|
1b8111 |
|
|
|
1b8111 |
public class Game {
|
|
|
1b8111 |
public static Game[] games = new Game[] { new Game(), new Game() };
|
|
|
1b8111 |
|
|
|
1b8111 |
public static class Number {
|
|
|
1b8111 |
public int number;
|
|
|
1b8111 |
public String text;
|
|
|
1b8111 |
public int digits;
|
|
|
1b8111 |
public int sizeIndex;
|
|
|
1b8111 |
public float size;
|
|
|
1b8111 |
public float scaleX;
|
|
|
1b8111 |
public int fontIndex;
|
|
|
1b8111 |
Typeface font;
|
|
|
1b8111 |
public Rect rect = new Rect();
|
|
|
1b8111 |
public Point position = new Point();
|
|
|
1b8111 |
|
|
|
1b8111 |
public void save(FileOutputStream fos) throws IOException {
|
|
|
1b8111 |
Serializer.writeInt(fos, number);
|
|
|
1b8111 |
Serializer.writeFloat(fos, size);
|
|
|
1b8111 |
Serializer.writeFloat(fos, scaleX);
|
|
|
1b8111 |
Serializer.writeInt(fos, fontIndex);
|
|
|
1b8111 |
Serializer.writeInt(fos, rect.left);
|
|
|
1b8111 |
Serializer.writeInt(fos, rect.right);
|
|
|
1b8111 |
Serializer.writeInt(fos, rect.top);
|
|
|
1b8111 |
Serializer.writeInt(fos, rect.bottom);
|
|
|
1b8111 |
Serializer.writeInt(fos, position.x);
|
|
|
1b8111 |
Serializer.writeInt(fos, position.y);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void load(FileInputStream fis) throws IOException {
|
|
|
1b8111 |
number = Serializer.readInt(fis);
|
|
|
1b8111 |
size = Serializer.readFloat(fis);
|
|
|
1b8111 |
scaleX = Serializer.readFloat(fis);
|
|
|
1b8111 |
fontIndex = Serializer.readInt(fis);
|
|
|
1b8111 |
rect.left = Serializer.readInt(fis);
|
|
|
1b8111 |
rect.right = Serializer.readInt(fis);
|
|
|
1b8111 |
rect.top = Serializer.readInt(fis);
|
|
|
1b8111 |
rect.bottom = Serializer.readInt(fis);
|
|
|
1b8111 |
position.x = Serializer.readInt(fis);
|
|
|
1b8111 |
position.y = Serializer.readInt(fis);
|
|
|
1b8111 |
|
|
|
1b8111 |
text = Integer.toString(number);
|
|
|
1b8111 |
digits = text.length();
|
|
|
1b8111 |
sizeIndex = 0;
|
|
|
1b8111 |
font = fonts[fontIndex];
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public interface Listener {
|
|
|
1b8111 |
public void onLock(Game game);
|
|
|
1b8111 |
public void onWin(Game game, float time);
|
|
|
1b8111 |
public void onTouchNumber(Game game, int touchedNumber, int maxNumber, boolean win);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private static final String filename = "game.sav";
|
|
|
1b8111 |
private static final int sizesCount = 100;
|
|
|
1b8111 |
private static final int generationTrials = 100;
|
|
|
1b8111 |
private static final int fontTrials = 100;
|
|
|
1b8111 |
private static final int positionTrials = 100;
|
|
|
1b8111 |
public static final Typeface[] fonts = new Typeface[] {
|
|
|
1b8111 |
Typeface.create(Typeface.SERIF, Typeface.NORMAL),
|
|
|
1b8111 |
Typeface.create(Typeface.SERIF, Typeface.BOLD),
|
|
|
1b8111 |
Typeface.create(Typeface.SERIF, Typeface.ITALIC),
|
|
|
1b8111 |
Typeface.create(Typeface.SERIF, Typeface.BOLD_ITALIC),
|
|
|
1b8111 |
Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL),
|
|
|
1b8111 |
Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD),
|
|
|
1b8111 |
Typeface.create(Typeface.SANS_SERIF, Typeface.ITALIC),
|
|
|
1b8111 |
Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD_ITALIC)
|
|
|
1b8111 |
};
|
|
|
1b8111 |
|
|
|
1b8111 |
private static Object staticHandle = new Object();
|
|
|
1b8111 |
private static boolean stateLoaded = false;
|
|
|
1b8111 |
private static String[] playerNames;
|
|
|
1b8111 |
|
|
|
1b8111 |
private int width = 0;
|
|
|
1b8111 |
private int height = 0;
|
|
|
1b8111 |
private float minSize;
|
|
|
1b8111 |
private float maxSize;
|
|
|
1b8111 |
private int initialMaxSizeIndex;
|
|
|
1b8111 |
private int maxDigits;
|
|
|
1b8111 |
private Rect[][][] sizes;
|
|
|
1b8111 |
|
|
|
1b8111 |
private TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
|
|
1b8111 |
private TextView numberTextView;
|
|
|
1b8111 |
private TextView timeTextView;
|
|
|
1b8111 |
private TextView playerNameTextView;
|
|
|
1b8111 |
private NumbersView numbersView;
|
|
|
1b8111 |
private View lockView;
|
|
|
1b8111 |
private Listener listener;
|
|
|
1b8111 |
|
|
|
1b8111 |
private Timer timer;
|
|
|
1b8111 |
private Object handle = new Object();
|
|
|
1b8111 |
private int waitToGenerate = 0;
|
|
|
1b8111 |
|
|
|
1b8111 |
private List<point> invalidTouches = new ArrayList<point>();
</point></point>
|
|
|
1b8111 |
|
|
|
1b8111 |
// serialization data
|
|
|
1b8111 |
private Number[] numbers = new Number[0];
|
|
|
1b8111 |
private int currentNumberIndex = -1;
|
|
|
1b8111 |
private int currentNumber = 0;
|
|
|
1b8111 |
private float time = 0;
|
|
|
1b8111 |
private float lockTime = 0;
|
|
|
1b8111 |
private boolean paused = true;
|
|
|
1b8111 |
private boolean playing = false;
|
|
|
1b8111 |
private boolean isWin = false;
|
|
|
1b8111 |
private boolean isLose = false;
|
|
|
1b8111 |
|
|
|
1b8111 |
public void save(FileOutputStream fos) throws IOException {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
Serializer.writeInt(fos, currentNumberIndex);
|
|
|
1b8111 |
Serializer.writeInt(fos, Math.round(time));
|
|
|
1b8111 |
Serializer.writeInt(fos, Math.round(lockTime));
|
|
|
1b8111 |
Serializer.writeInt(fos, paused ? 1 : 0);
|
|
|
1b8111 |
Serializer.writeInt(fos, playing ? 1 : 0);
|
|
|
1b8111 |
Serializer.writeInt(fos, numbers.length);
|
|
|
1b8111 |
for(Number number : numbers)
|
|
|
1b8111 |
number.save(fos);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void load(FileInputStream fis) throws IOException {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
currentNumberIndex = Serializer.readInt(fis);
|
|
|
1b8111 |
time = Serializer.readInt(fis);
|
|
|
1b8111 |
lockTime = Serializer.readInt(fis);
|
|
|
1b8111 |
paused = Serializer.readInt(fis) != 0;
|
|
|
1b8111 |
playing = Serializer.readInt(fis) != 0;
|
|
|
1b8111 |
numbers = new Number[Serializer.readInt(fis)];
|
|
|
1b8111 |
for(int i = 0; i < numbers.length; i++) {
|
|
|
1b8111 |
numbers[i] = new Number();
|
|
|
1b8111 |
numbers[i].load(fis);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
currentNumber = currentNumberIndex >= 0 && currentNumberIndex < numbers.length
|
|
|
1b8111 |
? numbers[currentNumberIndex].number : 0;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
|
|
|
1b8111 |
Game() {
|
|
|
1b8111 |
timer = new Timer();
|
|
|
1b8111 |
timer.schedule(new TimerTask() {
|
|
|
1b8111 |
@Override
|
|
|
1b8111 |
public void run() { onTime(1); }
|
|
|
1b8111 |
}, 1000, 1000);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private float internalCalcSize(int index) {
|
|
|
1b8111 |
return minSize + (maxSize - minSize)*(float)index/(float)(sizesCount-1);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalCalcSizes(int count) {
|
|
|
1b8111 |
maxSize = Math.min(width, height)/2f;
|
|
|
1b8111 |
minSize = count < 50 ? maxSize/5f : maxSize/10f;
|
|
|
1b8111 |
initialMaxSizeIndex = sizesCount/2;
|
|
|
1b8111 |
if (count > 25) initialMaxSizeIndex = sizesCount/4;
|
|
|
1b8111 |
if (count > 50) initialMaxSizeIndex = sizesCount/6;
|
|
|
1b8111 |
if (initialMaxSizeIndex < 1) initialMaxSizeIndex = 1;
|
|
|
1b8111 |
|
|
|
1b8111 |
String template = "MMMMMMMMMMMMMMMMMMMMMMMMMMMMM";
|
|
|
1b8111 |
sizes = new Rect[fonts.length][sizesCount][maxDigits + 1];
|
|
|
1b8111 |
paint.setTextScaleX(1f);
|
|
|
1b8111 |
for(int fontIndex = 0; fontIndex < fonts.length; fontIndex++) {
|
|
|
1b8111 |
paint.setTypeface(fonts[fontIndex]);
|
|
|
1b8111 |
for(int sizeIndex = 0; sizeIndex < sizesCount; sizeIndex++) {
|
|
|
1b8111 |
paint.setTextSize(internalCalcSize(sizeIndex));
|
|
|
1b8111 |
for(int digits = 0; digits <= maxDigits; digits++) {
|
|
|
1b8111 |
sizes[fontIndex][sizeIndex][digits] = new Rect();
|
|
|
1b8111 |
paint.getTextBounds(template, 0, digits, sizes[fontIndex][sizeIndex][digits]);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private boolean internalCheckRect(Rect rect, int count, int exclude) {
|
|
|
1b8111 |
if (rect.left < 0 || rect.top < 0 || rect.right > width || rect.bottom > height)
|
|
|
1b8111 |
return false;
|
|
|
1b8111 |
for(int i = 0; i < count; i++)
|
|
|
1b8111 |
if (Rect.intersects(rect, numbers[i].rect))
|
|
|
1b8111 |
return false;
|
|
|
1b8111 |
return true;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalGenerate(int count) {
|
|
|
1b8111 |
waitToGenerate = 0;
|
|
|
1b8111 |
time = 0;
|
|
|
1b8111 |
lockTime = 0;
|
|
|
1b8111 |
playing = false;
|
|
|
1b8111 |
isWin = false;
|
|
|
1b8111 |
isLose = false;
|
|
|
1b8111 |
if (timer != null) timer.cancel();
|
|
|
1b8111 |
timer = null;
|
|
|
1b8111 |
|
|
|
1b8111 |
maxDigits = count < 10 ? 1 : (count < 100 ? 2 : (count < 1000 ? 3 : 4));
|
|
|
1b8111 |
internalCalcSizes(count);
|
|
|
1b8111 |
|
|
|
1b8111 |
numbers = new Number[count];
|
|
|
1b8111 |
Random random = new Random();
|
|
|
1b8111 |
|
|
|
1b8111 |
// fill digits
|
|
|
1b8111 |
int[] remainingNumbers = new int[count];
|
|
|
1b8111 |
for(int i = 0; i < count; i++) remainingNumbers[i] = i+1;
|
|
|
1b8111 |
for(int i = 0; i < count; i++) {
|
|
|
1b8111 |
int j = random.nextInt(count - i);
|
|
|
1b8111 |
numbers[i] = new Number();
|
|
|
1b8111 |
numbers[i].number = remainingNumbers[j];
|
|
|
1b8111 |
numbers[i].text = Integer.toString(numbers[i].number);
|
|
|
1b8111 |
numbers[i].digits = numbers[i].text.length();
|
|
|
1b8111 |
for(int k = j+1; k < count-i; k++) remainingNumbers[k-1] = remainingNumbers[k];
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
// generate numbers
|
|
|
1b8111 |
boolean success = false;
|
|
|
1b8111 |
for(int generationTry = 0; !success && generationTry < generationTrials; generationTry++) {
|
|
|
1b8111 |
for(int i = 0; i < count; i++) {
|
|
|
1b8111 |
success = false;
|
|
|
1b8111 |
Number number = numbers[i];
|
|
|
1b8111 |
for(int fontTry = 0; !success && fontTry < fontTrials && fontTry < initialMaxSizeIndex; fontTry++) {
|
|
|
1b8111 |
number.fontIndex = random.nextInt(fonts.length);
|
|
|
1b8111 |
number.sizeIndex = random.nextInt(initialMaxSizeIndex - fontTry);
|
|
|
1b8111 |
number.font = fonts[number.fontIndex];
|
|
|
1b8111 |
number.size = internalCalcSize(number.sizeIndex);
|
|
|
1b8111 |
number.scaleX = 1f; //random.nextFloat()*1.5f + 0.5f;
|
|
|
1b8111 |
Rect r = sizes[number.fontIndex][number.sizeIndex][number.digits];
|
|
|
1b8111 |
int w = Math.round((r.right - r.left)*number.scaleX);
|
|
|
1b8111 |
int h = r.bottom - r.top;
|
|
|
1b8111 |
if (w < width && h < height) {
|
|
|
1b8111 |
for(int positionTry = 0; !success && positionTry < positionTrials; positionTry++) {
|
|
|
1b8111 |
int x = random.nextInt(width - w);
|
|
|
1b8111 |
int y = random.nextInt(height - h);
|
|
|
1b8111 |
number.rect.set(x, y, x+w, y+h);
|
|
|
1b8111 |
number.position.set(number.rect.left - r.left, number.rect.top - r.top);
|
|
|
1b8111 |
if (internalCheckRect(number.rect, i, -1))
|
|
|
1b8111 |
success = true;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
if (!success) break;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
if (success) {
|
|
|
1b8111 |
// enlarge numbers
|
|
|
1b8111 |
boolean enlarged = false;
|
|
|
1b8111 |
Rect[] rects = new Rect[] { new Rect(), new Rect(), new Rect(), new Rect() };
|
|
|
1b8111 |
while (enlarged) {
|
|
|
1b8111 |
enlarged = true;
|
|
|
1b8111 |
for(int i = 0; i < count; i++) {
|
|
|
1b8111 |
Number number = numbers[i];
|
|
|
1b8111 |
if (number.sizeIndex < sizesCount) {
|
|
|
1b8111 |
Rect r = sizes[number.fontIndex][number.sizeIndex+1][number.digits];
|
|
|
1b8111 |
int w = Math.round((r.right - r.left)*number.scaleX);
|
|
|
1b8111 |
int h = r.bottom - r.top;
|
|
|
1b8111 |
int validCount = 0;
|
|
|
1b8111 |
for(int j = 0; j < 3; j++) {
|
|
|
1b8111 |
int x = j % 2 == 0 ? number.rect.left : number.rect.right - w;
|
|
|
1b8111 |
int y = j / 2 == 0 ? number.rect.top : number.rect.bottom - h;
|
|
|
1b8111 |
rects[validCount].set(x, y, x+w, y+h);
|
|
|
1b8111 |
if (internalCheckRect(rects[validCount], count, i)) validCount++;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
if (validCount > 0) {
|
|
|
1b8111 |
number.sizeIndex++;
|
|
|
1b8111 |
number.size = internalCalcSize(number.sizeIndex);
|
|
|
1b8111 |
number.rect.set(rects[random.nextInt(validCount)]);
|
|
|
1b8111 |
number.position.set(number.rect.left - r.left, number.rect.top - r.top);
|
|
|
1b8111 |
enlarged = true;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
} else {
|
|
|
1b8111 |
numbers = new Number[0];
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
time = 0;
|
|
|
1b8111 |
lockTime = 0;
|
|
|
1b8111 |
playing = true;
|
|
|
1b8111 |
internalSetCurrentNumber(1);
|
|
|
1b8111 |
internalUpdateViews();
|
|
|
1b8111 |
timer = new Timer();
|
|
|
1b8111 |
timer.schedule(new TimerTask() {
|
|
|
1b8111 |
@Override
|
|
|
1b8111 |
public void run() { onTime(1); }
|
|
|
1b8111 |
}, 1000, 1000);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private static boolean checkDistance(int x0, int y0, int x1, int y1, int distSqr)
|
|
|
1b8111 |
{ return (x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) < distSqr; }
|
|
|
1b8111 |
|
|
|
1b8111 |
private boolean internalCheckTouch(int x, int y) {
|
|
|
1b8111 |
Number number = null;
|
|
|
1b8111 |
try { number = numbers[currentNumberIndex]; } catch (Exception e) { }
|
|
|
1b8111 |
if (number != null) {
|
|
|
1b8111 |
int radius = Math.min(width, height)/20;
|
|
|
1b8111 |
int radiusSqr = radius*radius;
|
|
|
1b8111 |
Rect rect = number.rect;
|
|
|
1b8111 |
|
|
|
1b8111 |
if (new Rect(rect.left - radius, rect.top, rect.right + 2*radius, rect.bottom ).contains(x, y)
|
|
|
1b8111 |
|| new Rect(rect.left, rect.top - radius, rect.right, rect.bottom + 2*radius ).contains(x, y)
|
|
|
1b8111 |
|| checkDistance(x, y, rect.left, rect.top, radiusSqr)
|
|
|
1b8111 |
|| checkDistance(x, y, rect.right, rect.top, radiusSqr)
|
|
|
1b8111 |
|| checkDistance(x, y, rect.left, rect.bottom, radiusSqr)
|
|
|
1b8111 |
|| checkDistance(x, y, rect.right, rect.bottom, radiusSqr)
|
|
|
1b8111 |
) {
|
|
|
1b8111 |
return true;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
return false;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalSetCurrentNumber(int value) {
|
|
|
1b8111 |
currentNumberIndex = -1;
|
|
|
1b8111 |
currentNumber = 0;
|
|
|
1b8111 |
for(int i = 0; i < numbers.length; i++)
|
|
|
1b8111 |
if (numbers[i].number == value)
|
|
|
1b8111 |
{ currentNumberIndex = i; currentNumber = value; break; }
|
|
|
1b8111 |
internalUpdateNumberTextView();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalUpdateNumberTextView() {
|
|
|
1b8111 |
if (numberTextView != null) {
|
|
|
1b8111 |
int numbersCount = numbers.length;
|
|
|
1b8111 |
int numbersFound = isWin ? numbersCount : currentNumber - 1;
|
|
|
1b8111 |
int id = R.string.currentNumber;
|
|
|
1b8111 |
if (isLose) id = R.string.currentNumberLose;
|
|
|
1b8111 |
if (isWin) { id = R.string.currentNumberWin; numbersFound = numbersCount; }
|
|
|
1b8111 |
|
|
|
1b8111 |
final TextView textView = numberTextView;
|
|
|
1b8111 |
final String text = textView.getContext().getString(id, currentNumber, numbersFound, numbersCount);
|
|
|
1b8111 |
textView.post(new Runnable() { @Override public void run() { textView.setText(text); } });
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalUpdateTimeTextView() {
|
|
|
1b8111 |
if (timeTextView != null) {
|
|
|
1b8111 |
int min = (int)FloatMath.floor(time/60);
|
|
|
1b8111 |
int sec = (int)FloatMath.floor(time - min*60);
|
|
|
1b8111 |
String minStr = Integer.toString(min);
|
|
|
1b8111 |
String secStr = Integer.toString(sec);
|
|
|
1b8111 |
while (minStr.length() < 2) minStr = "0" + minStr;
|
|
|
1b8111 |
while (secStr.length() < 2) secStr = "0" + secStr;
|
|
|
1b8111 |
|
|
|
1b8111 |
final TextView textView = timeTextView;
|
|
|
1b8111 |
final String text = minStr + ":" + secStr;
|
|
|
1b8111 |
textView.post(new Runnable() { @Override public void run() { textView.setText(text); } });
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalUpdatePlayerNameTextView() {
|
|
|
1b8111 |
if (playerNameTextView != null) {
|
|
|
1b8111 |
final TextView textView = playerNameTextView;
|
|
|
1b8111 |
final int visibility = playing ? View.VISIBLE : View.GONE;
|
|
|
1b8111 |
textView.post(new Runnable() { @Override public void run() { textView.setVisibility(visibility); } });
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalUpdateNumbersView() {
|
|
|
1b8111 |
if (numbersView != null) {
|
|
|
1b8111 |
final NumbersView view = numbersView;
|
|
|
1b8111 |
view.post(new Runnable() { @Override public void run() { view.invalidate(); } });
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalUpdateLockView() {
|
|
|
1b8111 |
if (lockView != null) {
|
|
|
1b8111 |
final View view = lockView;
|
|
|
1b8111 |
final int visibility = lockTime <= 0 ? View.GONE : View.VISIBLE;
|
|
|
1b8111 |
view.post(new Runnable() { @Override public void run() {
|
|
|
1b8111 |
if (view.getVisibility() != visibility) view.setVisibility(visibility);
|
|
|
1b8111 |
if (visibility == View.VISIBLE) view.invalidate();
|
|
|
1b8111 |
} });
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private void internalUpdateViews() {
|
|
|
1b8111 |
internalUpdateNumberTextView();
|
|
|
1b8111 |
internalUpdateTimeTextView();
|
|
|
1b8111 |
internalUpdatePlayerNameTextView();
|
|
|
1b8111 |
internalUpdateNumbersView();
|
|
|
1b8111 |
internalUpdateLockView();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
|
|
|
1b8111 |
|
|
|
1b8111 |
public void start(int count) {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
if (width > 0 && height > 0)
|
|
|
1b8111 |
internalGenerate(count);
|
|
|
1b8111 |
else
|
|
|
1b8111 |
waitToGenerate = count;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void stop() {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
playing = false;
|
|
|
1b8111 |
isWin = false;
|
|
|
1b8111 |
isLose = false;
|
|
|
1b8111 |
numbers = new Number[0];
|
|
|
1b8111 |
internalUpdateNumberTextView();
|
|
|
1b8111 |
internalUpdatePlayerNameTextView();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void lose() {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
playing = false;
|
|
|
1b8111 |
isWin = false;
|
|
|
1b8111 |
isLose = true;
|
|
|
1b8111 |
internalUpdateNumberTextView();
|
|
|
1b8111 |
internalUpdatePlayerNameTextView();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void win() {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
playing = false;
|
|
|
1b8111 |
isWin = true;
|
|
|
1b8111 |
isLose = false;
|
|
|
1b8111 |
internalUpdateNumberTextView();
|
|
|
1b8111 |
internalUpdatePlayerNameTextView();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static void lock() {
|
|
|
1b8111 |
for(Game game : games) {
|
|
|
1b8111 |
synchronized (game.handle) {
|
|
|
1b8111 |
game.lockTime = 5;
|
|
|
1b8111 |
game.internalUpdateLockView();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
if (game.listener != null) game.listener.onLock(game);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public boolean getPlaying()
|
|
|
1b8111 |
{ synchronized (handle) { return playing; } }
|
|
|
1b8111 |
public boolean getPaused()
|
|
|
1b8111 |
{ synchronized (handle) { return paused; } }
|
|
|
1b8111 |
public void setPaused(boolean value)
|
|
|
1b8111 |
{ synchronized (handle) { paused = value; } }
|
|
|
1b8111 |
public int getCount()
|
|
|
1b8111 |
{ synchronized (handle) { return numbers.length; } }
|
|
|
1b8111 |
|
|
|
1b8111 |
public int getCurrentNumber() {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
try { return numbers[currentNumberIndex].number; } catch (Exception e) { }
|
|
|
1b8111 |
return 0;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void onLayout(int width, int height) {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
this.width = width;
|
|
|
1b8111 |
this.height = height;
|
|
|
1b8111 |
if (width > 0 && height > 0 && waitToGenerate > 0)
|
|
|
1b8111 |
internalGenerate(waitToGenerate);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void onTouch(int x, int y) {
|
|
|
1b8111 |
boolean touch = false;
|
|
|
1b8111 |
int touchedNumber = 0;
|
|
|
1b8111 |
int maxNumber = 0;
|
|
|
1b8111 |
|
|
|
1b8111 |
boolean win = false;
|
|
|
1b8111 |
float winTime = 0;
|
|
|
1b8111 |
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
if (playing && !paused && lockTime <= 0) {
|
|
|
1b8111 |
if (internalCheckTouch(x, y)) {
|
|
|
1b8111 |
touch = true;
|
|
|
1b8111 |
touchedNumber = currentNumber;
|
|
|
1b8111 |
maxNumber = numbers.length;
|
|
|
1b8111 |
if (currentNumber < numbers.length) {
|
|
|
1b8111 |
internalSetCurrentNumber(currentNumber + 1);
|
|
|
1b8111 |
} else {
|
|
|
1b8111 |
this.win();
|
|
|
1b8111 |
win = true;
|
|
|
1b8111 |
winTime = time;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
invalidTouches.clear();
|
|
|
1b8111 |
} else {
|
|
|
1b8111 |
invalidTouches.add(new Point(x, y));
|
|
|
1b8111 |
if (invalidTouches.size() > 1) {
|
|
|
1b8111 |
int maxDist = Math.min(width, height)/4;
|
|
|
1b8111 |
int places = 1;
|
|
|
1b8111 |
Point min = new Point(width, height);
|
|
|
1b8111 |
Point max = new Point(0, 0);
|
|
|
1b8111 |
for(Point p : invalidTouches) {
|
|
|
1b8111 |
min.x = Math.min(min.x, p.x);
|
|
|
1b8111 |
min.y = Math.min(min.y, p.y);
|
|
|
1b8111 |
max.x = Math.max(max.x, p.x);
|
|
|
1b8111 |
max.y = Math.max(max.y, p.y);
|
|
|
1b8111 |
if (max.x - min.x > maxDist || max.y - min.y > maxDist) {
|
|
|
1b8111 |
places++;
|
|
|
1b8111 |
min.set(p.x, p.y);
|
|
|
1b8111 |
max.set(p.x, p.y);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
if (places > 3) {
|
|
|
1b8111 |
lock();
|
|
|
1b8111 |
invalidTouches.clear();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
if (touch && listener != null) listener.onTouchNumber(this, touchedNumber, maxNumber, win);
|
|
|
1b8111 |
if (win && listener != null) listener.onWin(this, winTime);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void onTime(float time) {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
if (playing && !paused) {
|
|
|
1b8111 |
this.time += time;
|
|
|
1b8111 |
lockTime -= time;
|
|
|
1b8111 |
if (lockTime <= 0) lockTime = 0;
|
|
|
1b8111 |
internalUpdateTimeTextView();
|
|
|
1b8111 |
internalUpdateLockView();
|
|
|
1b8111 |
if (Math.round(this.time) % 3 == 0 && invalidTouches.size() > 0)
|
|
|
1b8111 |
invalidTouches.remove(0);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void draw(Canvas canvas) {
|
|
|
1b8111 |
synchronized (handle) {
|
|
|
1b8111 |
for(int i = 0; i < numbers.length; i++) {
|
|
|
1b8111 |
Number number = numbers[i];
|
|
|
1b8111 |
paint.setTypeface(number.font);
|
|
|
1b8111 |
paint.setTextSize(number.size);
|
|
|
1b8111 |
paint.setTextScaleX(number.scaleX);
|
|
|
1b8111 |
canvas.drawText(number.text, number.position.x, number.position.y, paint);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public void setListener(Listener value)
|
|
|
1b8111 |
{ synchronized (handle) { listener = value; } }
|
|
|
1b8111 |
public void setNumberTextView(TextView value)
|
|
|
1b8111 |
{ synchronized (handle) { numberTextView = value; internalUpdateNumberTextView(); } }
|
|
|
1b8111 |
public void setTimeTextView(TextView value)
|
|
|
1b8111 |
{ synchronized (handle) { timeTextView = value; internalUpdateTimeTextView(); } }
|
|
|
1b8111 |
public void setPlayerNameTextView(TextView value)
|
|
|
1b8111 |
{ synchronized (handle) { playerNameTextView = value; internalUpdatePlayerNameTextView(); } }
|
|
|
1b8111 |
public void setNumbersView(NumbersView value)
|
|
|
1b8111 |
{ synchronized (handle) { numbersView = value; internalUpdateNumbersView(); } }
|
|
|
1b8111 |
public void setLockView(View value)
|
|
|
1b8111 |
{ synchronized (handle) { lockView = value; internalUpdateLockView(); } }
|
|
|
1b8111 |
|
|
|
1b8111 |
private static void save(Context context) {
|
|
|
1b8111 |
try {
|
|
|
1b8111 |
FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
|
|
|
1b8111 |
for(Game game : games) game.save(fos);
|
|
|
1b8111 |
Serializer.writeInt(fos, playerNames.length);
|
|
|
1b8111 |
if (playerNames == null) playerNames = new String[0];
|
|
|
1b8111 |
for(String name : playerNames)
|
|
|
1b8111 |
Serializer.writeString(fos, name);
|
|
|
1b8111 |
ScoreboardActivity.save(fos);
|
|
|
1b8111 |
Serializer.writeInt(fos, SoundPlayer.getEnabled() ? 1 : 0);
|
|
|
1b8111 |
} catch (Exception e) { }
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
private static void load(Context context) {
|
|
|
1b8111 |
for(Game game : games) game.stop();
|
|
|
1b8111 |
|
|
|
1b8111 |
try {
|
|
|
1b8111 |
FileInputStream fis = context.openFileInput(filename);
|
|
|
1b8111 |
for(Game game : games) game.load(fis);
|
|
|
1b8111 |
playerNames = new String[Serializer.readInt(fis)];
|
|
|
1b8111 |
for(int i = 0; i < playerNames.length; i++)
|
|
|
1b8111 |
playerNames[i] = Serializer.readString(fis);
|
|
|
1b8111 |
ScoreboardActivity.load(fis);
|
|
|
1b8111 |
SoundPlayer.setEnabled(Serializer.readInt(fis) != 0);
|
|
|
1b8111 |
} catch (Exception e) {
|
|
|
1b8111 |
for(Game game : games) game.stop();
|
|
|
1b8111 |
//e.printStackTrace();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
if (playerNames == null) playerNames = new String[0];
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static void saveState(Context context) {
|
|
|
1b8111 |
synchronized (staticHandle) {
|
|
|
1b8111 |
save(context);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static void loadState(Context context) {
|
|
|
1b8111 |
synchronized (staticHandle) {
|
|
|
1b8111 |
if (!stateLoaded) {
|
|
|
1b8111 |
stateLoaded = true;
|
|
|
1b8111 |
load(context);
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static int getMode() {
|
|
|
1b8111 |
boolean g0 = games[0].getCount() > 0;
|
|
|
1b8111 |
boolean g1 = games[1].getCount() > 0;
|
|
|
1b8111 |
if (g0 && g1) return 2;
|
|
|
1b8111 |
if (g0 && !g1) return 1;
|
|
|
1b8111 |
return 0;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static boolean getAnyPlaying() {
|
|
|
1b8111 |
switch (getMode()) {
|
|
|
1b8111 |
case 1:
|
|
|
1b8111 |
return games[0].getPlaying();
|
|
|
1b8111 |
case 2:
|
|
|
1b8111 |
return games[0].getPlaying() || games[1].getPlaying();
|
|
|
1b8111 |
}
|
|
|
1b8111 |
return false;
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static String getPlayerName(int index) {
|
|
|
1b8111 |
synchronized (staticHandle) {
|
|
|
1b8111 |
try { return playerNames[index] == null ? "" : playerNames[index]; } catch (Exception e) { }
|
|
|
1b8111 |
return "";
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
|
|
|
1b8111 |
public static void setPlayerName(int index, String name) {
|
|
|
1b8111 |
synchronized (staticHandle) {
|
|
|
1b8111 |
if (name != null && name.length() > 0) {
|
|
|
1b8111 |
try {
|
|
|
1b8111 |
playerNames = Serializer.enlargeArrayIfNeed(String.class, playerNames, index+1);
|
|
|
1b8111 |
playerNames[index] = name;
|
|
|
1b8111 |
} catch (Exception e) { }
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|
|
|
1b8111 |
}
|