Android——手機彩票搖晃選號(雙色球) 實現原理
阿新 • • 發佈:2019-02-16
實現思路:因為手機感測器每隔一段時間會發送採集到的資料包, 首先獲取第一個資料包所在的三個軸的加速度值,記錄, 當過一段時間之後再次獲取三個軸的加速度值,計算增量,將相鄰兩個點的增量進行彙總,當達到預先設定的閥值,說明手機搖晃了。
實現步驟:
1、記錄第一個點的資料: 三個軸的加速度,為了遮蔽不同手機取樣的時間間隔差異,將第一個點的時間也記錄下 來。
2、選取第二個點的資料:當有新的感測器資料傳遞進來後,用當前的時間與第一個點的時間進行比對,判斷時間間 隔,如果滿足了時間間隔(經驗值:100)的要求,認為是合格的第二個點,否則捨棄改資料包。
3、 進行增量的計算:獲取到的新的加速度值與第一個點上的加速度值進行差值運算,獲取到一點和二點之間的增量,將三個增量值進行彙總。
4、以此類推,獲取到相鄰兩個點的增量,進行彙總。
5、通過彙總的值與之前設定好的閥值(經驗值:200)進行比對,如果>=閥值,使用者搖晃手機。否則記錄當前點的資料(加速度的值 和 該點的時間)。
一、核心感測器監聽程式碼:
package com.huang.mylottery.view.sensor;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.Vibrator;
/**
* 處理感測器監聽
*
* @author wuseyukui
*
*/
public abstract class ShakeListener implements SensorEventListener {
// 判斷手機搖晃的閾值
private final static float SWITH_VALUE = 200f;
private final static long DURATION = 100;
private Vibrator vibrator;
private float lastX;
private float lastY;
private float lastZ;
private long lastTime;
private float total;
public ShakeListener(Context context) {
super();
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE );
}
private void initParam() {
lastX = 0;
lastY = 0;
lastZ = 0;
lastTime = 0;
total = 0;
}
@Override
public void onSensorChanged(SensorEvent event) {
// 判斷 是否第一個點
if ( lastX == 0 && lastY == 0 && lastZ == 0 && lastTime == 0) {
// 記錄三個軸的加速度值
float[] values = event. values;
lastX = values[0];
lastY = values[1];
lastZ = values[2];
lastTime = System. currentTimeMillis();
total = lastX + lastY + lastZ;
} else {
// 儘可能遮蔽掉不同手機感測器的差異
if (System. currentTimeMillis() - lastTime > DURATION) {
float[] values = event. values;
// 第二個點及以後
float x = values[0];
float y = values[1];
float z = values[2];
// 計算增量
float dx = Math. abs(x-lastX);
float dy = Math. abs(y-lastY);
float dz = Math. abs(z-lastZ);
// 儘量遮蔽掉微小的增量值
if (dx < 1) {
dx = 0;
}
if (dy < 1) {
dy = 0;
}
if (dz < 1) {
dz = 0;
}
// 極個別手機,靜止狀態 某個軸的增量會大於1,10以上,甚至100以上
if (dx == 0 && dy == 0 && dz == 0) {
initParam();
return;
}
// 彙總(一點和二點總得增量)
float shake = dx + dy + dz;
if(shake == 0) {
initParam();
return;
}
total += shake;
if ( total >= SWITH_VALUE) {
// 手機搖晃了
// 機選一注彩票
RandomCure();
// 提示使用者
vibrator.vibrate(100);
// 所有的資料都要初始化
initParam();
} else {
lastX = x;
lastY = y;
lastZ = z;
lastTime = System. currentTimeMillis();
}
}
}
}
public abstract void RandomCure();
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
二、註冊監聽
listener = new ShakeListener(context){
@Override
public void RandomCure() {
//機選一注
randomSSQ();
}
};
// 註冊感測器監聽
sensor.registerListener( listener,
sensor.getDefaultSensor(Sensor. TYPE_ACCELEROMETER),
SensorManager. SENSOR_DELAY_FASTEST);
二、各種彩票的演算法
package cn.com.soarmobile.lottery;
import android.content.res.TypedArray;
import cn.com.soarmobile.SoarEngine;
import cn.com.soarmobile.bean.LotteryCartItem;
import cn.com.soarmobile.util.CalculatorUtils;
/**
* Type代表彩種玩法(如:任選一、任選二); Mode代表選號型別(如:直選)
*
* @author Administrator
*
*/
public abstract class LotteryBase {
/**
* 彩種LOGO
*/
public int icon;
/**
* 彩種名字 例如排列三
*/
public String name;
/**
* 彩種名字編號 例如排列三:p3 雙色球:ssq
*/
public String gameName;
/**
* 彩種代號 例如雙色球:001 福彩3D:002
*/
public String code;
/**
* 官方規則
*/
public int officialrule;
/**
* 獎金說明
*/
public int prizeexplain;
/**
* 彩票期數 例如20110115
*/
public String issue;
/**
* 彩種簡介,例如:天天排列3,不愁吃喝穿
*/
public String summary;
/**
* 購買一注的價格
*/
public int price;
/**
* 購買截止時間
*/
public String deadLine;
/**
* 紅色選號區標籤 如只有紅色球 則顯示選號 藍球選號區域不顯示
*/
public String redTag;
/**
* 藍色選號區標籤 如果木有藍球 該區域不顯示
*/
public String buleTag;
/**
* 最少要選擇的紅球數 例如雙色球至少選6個紅球
*/
public int redMin;
/**
* 最少要選擇的藍球數 例如雙色球至少選1個藍球 值可以為0
*/
public int blueMin;
/**
* 選號規則介紹 例如 請選擇至少六個紅球和一個藍球
*/
public String[] rules;
/**
* 當前模式選號規則
*/
public String currentRule;
/**
* 彩種玩法,例如:任選一、任選二
*/
public String[] playType;
/**
* 當前彩種玩法 <br>
* 參照{@link #playType playType}
*/
protected String currentType;
/**
* 機選玩法,例如:二星、三星、五星 <br>
* 該玩法目前為{@link #playType playType}的子集
*/
public String[] autoPlayType = null;
/**
* 選號型別,例如:直選、組選、通選
*/
public String[] playMode;
/**
* 當前選號型別 <br>
* 參照{@link #playMode playMode}
*/
protected String currentMode;
/**
* 不同玩法 模式的注意事項提醒
*/
public String[] notices;
/**
* 當前模式注意事項
*/
public String currentNotice;
/**
* 是否允許追加
*/
public boolean allowAddTo = false;
/**
* 是否格式化顯示號碼 例如 雙色球01,02,03
*/
public boolean format = false;
/**
* 獲取紅球選號池 例如 :排列三{0,1,2,3,4,5,6,7,8,9} 選號型別和選號模式影響改返回值
*
* @return
*/
/**
* 根據playtype和playmode計算出來當前索引
*/
public int currentIndex;
public abstract int[] getRedPool();
protected int[] getRedPool(int resId) {
String[] redrules = getStringArray(resId);
String temp = redrules[currentIndex];
String[] string = temp.split("-");
int count = Integer.parseInt(string[1]);
int start = Integer.parseInt(string[2]);
int end = Integer.parseInt(string[3]);
return CalculatorUtils.createBalls(count, start, end);
}
/**
* 紅球選擇區的顯示時候的列數
*
* @return
*/
public abstract int getRedColumnCount();
protected int getRedColumnCount(int resId) {
String[] redrules = getStringArray(resId);
String temp = redrules[currentIndex];
String[] string = temp.split("-");
return Integer.parseInt(string[0]);
}
/**
* 獲取藍球選號池 例如排列三{0,1,2,3,4,5,6,7,8,9} 選號型別和選號模式影響改返回值
*
* @return
*/
public abstract int[] getBluePool();
protected int[] getBluePool(int resId) {
String[] redrules = getStringArray(resId);
String temp = redrules[currentIndex];
String[] string = temp.split("-");
int count = Integer.parseInt(string[1]);
int start = Integer.parseInt(string[2]);
int end = Integer.parseInt(string[3]);
return CalculatorUtils.createBalls(count, start, end);
}
/**
* 藍球選擇區的顯示時候的列數
*
* @return
*/
public abstract int getBlueColumnCount();
protected int getBlueColumnCount(int resId) {
String[] redrules = getStringArray(resId);
String temp = redrules[currentIndex];
String[] string = temp.split("-");
return Integer.parseInt(string[0]);
}
/**
* 機選紅球
*/
public abstract int[] getRandomRed();
/**
* 機選藍球
*/
public abstract int[] getRandomBlue();
/**
* 機選n注號碼
* 返回int[][]
*/
public abstract int[][] getRandom(int n);
/**
* 機選n注號碼
* 返回String[]
* 這樣就不用根據redMin blueMin判斷填充那種顏色了,
* 減少彩種切換時對redMin和blueMin的管理
*/
public abstract String[] getRandomString(int n);
/**
* 判斷當前選擇是否合法
*
* @param red
* @param bule
* @return
*/
public abstract boolean isValid(int[] red, int[] bule);
/**
* 計算當前選了多少注 數學公式C(red,bule)或A(red,bule)
*
* @param red
* 當前選擇的紅球
* @param bule
* 當前選擇的藍球
* @return 計算出注數
*/
public abstract long calculatorBoxes(int[] red, int[] bule);
/**
* 重新為預設設定
*/
public abstract void reset(boolean isAutoToManual);
/**
* 根據plaype和playMode獲取索引 例如 福彩3d {直選 複式}對應索引0 {直選 單式}對應索引1 {組三 複式}對應索引2
*/
public int getIndex(int resId) {
int n = 0;
for (int i = 0; i < playType.length; i++) {
String[] strings = CountModeByType(resId, i);
for (int j = 0; j < strings.length; j++) {
if (currentType.equals(playType[i])
&& currentMode.equals(strings[j])) {
return n;
}
n++;
}
}
for (int i = 0; i < playMode.length; i++) {
if (currentMode.equals(playMode[i])) {
return n;
}
n++;
}
return n;
}
/**
*
* @return 獲取當前選擇playType的索引 例如 福彩3d {直選,組三,組六}對應的索引分別為{0,1,2}
*/
public int getPlayTypeIndex() {
for (int i = 0; i < playType.length; i++) {
if (currentType.equals(playType[i])) {
return i;
}
}
return 0;
}
/**
*
* @param resId
* R.array.xx_playmodes
* @param index
* 當前選擇playType的索引 例如 福彩3d {直選,組三,組六}對應的索引分別為{0,1,2}
* @return 對應plaype下的playmodes 例如 福彩3d直選 {複式 單式}
*/
public String[] CountModeByType(int resId, int index) {
TypedArray typedArray = SoarEngine.getInstance().getResources()
.obtainTypedArray(resId);
resId = typedArray.getResourceId(index, -1);
return getStringArray(resId);
}
/**
* 彩種playype發生變化 例如 福彩3d{直選 組三}
*/
public abstract void notifyPlayTypeChanged();
/**
* 當有的彩種的玩法型別改變時,其redMin或buleMin的值會相應的被改變, 這種情況下,在具體的彩種類中要重寫該方法,使玩法型別與redMin
* 和buleMin相對應。例如,11選5的玩法,任選二 任選三等的最小 紅球數不同,切換玩法型別時就要對redMin做相應的改變,否則在自選
* 和機選間切換時會出問題,因為機選顯示號碼個數時會用到以上量值。 {@link #setCurrentMode(String)
* setCurrentMode()}類似。
*
* @param currentType
*/
public void setCurrentType(String currentType) {
this.currentType = currentType;
notifyPlayTypeChanged();
}
public String getCurrentType() {
return currentType;
}
/**
* 彩種playMode發生變化 例如 福彩3d{單式 複式}
*/
public abstract void notifyPlayModeChanged();
/**
* 使用說明參考{@link #setCurrentType(String) setCurrentType}
*
* @return
*/
public void setCurrentMode(String currentMode) {
this.currentMode = currentMode;
notifyPlayModeChanged();
}
public String getCurrentMode() {
return currentMode;
}
/**
*
* @param resId
* R.arrat.xx_playmodes
* @return 當前PlayType對應的PlayMode 例如 福彩3d直選{複式,單式}
*/
public String[] getPlayModes(int resId) {
TypedArray typedArray = SoarEngine.getInstance().getResources()
.obtainTypedArray(resId);
resId = typedArray.getResourceId(getPlayTypeIndex(), -1);
return getStringArray(resId);
}
protected String getString(int resId) {
return SoarEngine.getInstance().getResources().getString(resId);
}
protected String[] getStringArray(int resId) {
return SoarEngine.getInstance().getResources().getStringArray(resId);
}
protected int getInteger(int resId) {
return SoarEngine.getInstance().getResources().getInteger(resId);
}
protected boolean getBoolean(int resId) {
return SoarEngine.getInstance().getResources().getBoolean(resId);
}
/**
* 判斷當前想要選擇的紅球是否能被選選擇
*
* @param selected
* 當前已經選中的紅球
* @param index
* 想要選擇的紅球
* @return
*/
public abstract String canSelecteRed(int[] selected, int index);
/**
* 判斷當前想要選擇的藍球是否能被選選擇
*
* @param selected
* 當前已經選中的藍球
* @param index
* 想要選擇的藍球
* @return
*/
public abstract String canSelecteBlue(int[] selected, int index);
/**
* 根據當前已選紅球和想要選擇的紅球計算出新的選中狀態
*
* @param selected
* 當前已經選中的紅球
* @param index
* @return
*/
public abstract int[][] newRedBalls(int[] selected, int index,
boolean isCancel);
/**
* 根據當前已選紅球和想要選擇的藍球計算出新的選中狀態
*
* @param selected
* 當前已經選中的紅球
* @param index
* @return
*/
public abstract int[][] newblueBalls(int[] selected, int index,
boolean isCancel);
/**
* 將當前已經選擇的紅球格式化為字串 例如 已經選擇3 6 7格式化為3,6,7
*
* @param text
* @param index
* @return
*/
public abstract String formatSelectedRed(String[] texts, int[] indexs);
/**
* 將當前已經選擇的藍球格式化為字串 例如 已經選擇3 6 7格式化為3,6,7
*
* @param text
* @param index
* @return
*/
public abstract String formatSelectedBlue(String[] texts, int[] indexs);
//根據當前選號情況建立代表當前選好的彩票訂單專案
/**
* @param redpool 紅球
* @param bluepool 藍球
* @param result 方案資訊(X注X元)
* @param zhuijia 是否追加
*/
public abstract LotteryCartItem createLotteryCartItem(String redpool,String bluepool,String result,boolean zhuijia);
public abstract int getTypeCodeByMode(String mode);
}
package cn.com.soarmobile.lottery;
import cn.com.soarmobile.R;
import cn.com.soarmobile.bean.LotteryCartItem;
import cn.com.soarmobile.util.CalculatorUtils;
import cn.com.soarmobile.util.StringUtil;
public class Lottery11x5 extends LotteryRed {
public Lottery11x5() {
icon = R.string.llx5_icon;
name = getString(R.string.llx5_name);
gameName = getString(R.string.llx5_game_name);
code = getString(R.string.llx5_code);
issue = getString(R.string.llx5_issue);
summary = getString(R.string.llx5_summary);
price = getInteger(R.integer.llx5_price);
deadLine = getString(R.string.llx5_deadline);
redTag = getString(R.string.llx5_redtag);
buleTag = getString(R.string.llx5_bluetag);
redMin = getInteger(R.integer.llx5_redmin);
blueMin = getInteger(R.integer.llx5_bluemin);
rules = getStringArray(R.array.llx5_rules);
notices = getStringArray(R.array.llx5_notices);
playType = getStringArray(R.array.llx5_playtypes);
currentType = getString(R.string.llx5_defaulttype);
playMode = getStringArray(R.array.llx5_playmodes);
currentMode = getString(R.string.llx5_defaultmode);
allowAddTo = getBoolean(R.integer.llx5_allowAdd);
format = getBoolean(R.integer.llx5_format);
officialrule = R.string.llx5_officialrule;
prizeexplain = R.string.llx5_prizeexplain;
autoPlayType = getStringArray(R.array.llx5_auto_playtypes);
notifyPlayTypeChanged();
}
@Override
public int[] getRedPool() {
return super.getRedPool(R.array.llx5_redpools);
}
@Override
public int getRedColumnCount() {
return super.getRedColumnCount(R.array.llx5_redpools);
}
@Override
public int[] getRandomRed() {
int n = getIndex(R.array.llx5_playmodes);
int column = getRedColumnCount();
switch (n) {
case 0:// 任一-直選
return CalculatorUtils.getRandomArrayNumber(1, 0, 10);
case 1:// 任二-直選
return CalculatorUtils.getRandomArrayNumber(2, 0, 10);
case 2:// 任三-直選
return CalculatorUtils.getRandomArrayNumber(3, 0, 10);
case 3:// 任四-直選
return CalculatorUtils.getRandomArrayNumber(4, 0, 10);
case 4:// 任五-直選
return CalculatorUtils.getRandomArrayNumber(5, 0, 10);
case 5:// 任六-直選
return CalculatorUtils.getRandomArrayNumber(6, 0, 10);
case 6:// 任七-直選
return CalculatorUtils.getRandomArrayNumber(7, 0, 10);
case 7:// 任八-直選
return CalculatorUtils.getRandomArrayNumber(8, 0, 10);
case 8:// 前二-直選
int[] reds = CalculatorUtils.getRandomArrayNumber(2, 0, 10);
for (int i = 0; i < reds.length; i++) {
reds[i] = reds[i] + column * i;
}
return reds;
case 9:// 前二-組選
return CalculatorUtils.getRandomArrayNumber(2, 0, 10);
case 10:// 前三-直選
reds = CalculatorUtils.getRandomArrayNumber(3, 0, 10);
for (int i = 0; i < reds.length; i++) {
reds[i] = reds[i] + column * i;
}
return reds;
case 11:// 前三-組選
return CalculatorUtils.getRandomArrayNumber(3, 0, 10);
}
return null;
}
@Override
public int[][] getRandom(int n) {
if (n < 1) {
n = 1;
}
int[][] result = new int[n][redMin];
for (int i = 0; i < n; i++) {
for (int j = 0; j < redMin; j++) {
result[i][j] = CalculatorUtils.getRandomNumber(1, 11);
}
}
return result;
}
@Override
public String[] getRandomString(int n) {
if (n < 1) {
n = 1;
}
String[] result = new String[n];
StringBuffer sBuffer = new StringBuffer();
for (int i = 0; i < n; i++) {
sBuffer.delete(0, sBuffer.length());
int[] nums = CalculatorUtils.getRandomArrayNumber(redMin, 1, 11);
for (int j = 0; j < redMin; j++) {
sBuffer.append(StringUtil.format(nums[j]) + ",");
}
result[i] = sBuffer.toString().substring(0, sBuffer.length() - 1);
}
return result;
}
@Override
public boolean isValid(int[] red, int[] bule) {
if (red.length == 0)
return false;
switch (currentIndex) {
case 0:// 任一-直選
break;
case 1:// 任二-直選
break;
case 2:// 任三-直選
break;
case 3:// 任四-直選
break;
case 4:// 任五-直選
break;
case 5:// 任六-直選
break;
case 6:// 任七-直選
break;
case 7:// 任八-直選
break;
case 8:// 前二-直選
if (red[red.length - 1] / getRedColumnCount() != 1)
return false;
case 9:// 前二-組選
break;
case 10:// 前三-直選
if (red[red.length - 1] / getRedColumnCount() != 2)
return false;
case 11:// 前三-組選
break;
}
if (red.length < redMin)
return false;
return true;
}
@Override
public long calculatorBoxes(int[] red, int[] blue) {
if (!isValid(red, blue)) {
return -1;
}
int column = getRedColumnCount();
switch (currentIndex) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:// 任一-直選 到 任八-直選
return CalculatorUtils.calculatorCombination(red.length, redMin);
case 8:// 前二-直選
return CalculatorUtils.calculatorBoxs(red, column);
case 9:// 前二-組選
return CalculatorUtils.calculatorCombination(red.length, redMin);
case 10:// 前三-直選
return CalculatorUtils.calculatorBoxs(red, column);
case 11:// 前三-組選
return CalculatorUtils.calculatorCombination(red.length, redMin);
}
return 0;
}
@Override
public void reset(boolean isAutoToManual) {
currentType = getString(R.string.llx5_defaulttype);
if (isAutoToManual) {
notifyPlayTypeChanged();
}
}
@Override
public void notifyPlayTypeChanged() {
playMode = getPlayModes(R.array.llx5_playmodes);
currentMode = playMode[0];
notifyPlayModeChanged();
}
@Override
public void notifyPlayModeChanged() {
currentIndex = getIndex(R.array.llx5_playmodes);
if (!StringUtil.isEmpty(rules))
currentRule = rules[getIndex(R.array.llx5_playmodes)];
if (!StringUtil.isEmpty(notices))
currentNotice = notices[getIndex(R.array.llx5_playmodes)];
switch (currentIndex) {
case 0:// 任一-直選
redMin = 1;
break;
case 1:// 任二-直選
redMin = 2;
break;
case 2:// 任三-直選
redMin = 3;
break;
case 3:// 任四-直選
redMin = 4;
break;
case 4:// 任五-直選
redMin = 5;
break;
case 5:// 任六-直選
redMin = 6;
break;
case 6:// 任七-直選
redMin = 7;
break;
case 7:// 任八-直選
redMin = 8;
break;
case 8:// 前二-直選
redMin = 2;
break;
case 9:// 前二-組選
redMin = 2;
break;
case 10:// 前三-直選
redMin = 3;
break;
case 11:// 前三-組選
redMin = 3;
break;
}
}
@Override
public String canSelecteRed(int[] selected, int index) {
int column = getRedColumnCount();
switch (currentIndex) {
case 0:// 任一-直選
break;
case 1:// 任二-直選
break;
case 2:// 任三-直選
break;
case 3:// 任四-直選
break;
case 4:// 任五-直選
break;
case 5:// 任六-直選
break;
case 6:// 任七-直選
break;
case 7:// 任八-直選
if(selected.length>=8){
return "最多隻能選8個號碼!";
}
break;
case 8:// 前二-直選
if (index / column == 0) {
for (int i = 0; i < selected.length; i++) {
if (selected[i] == index + column) {
return "前二選號:各位不能重複";
}
}
} else if (index / column == 1) {
for (int i = 0; i < selected.length; i++) {
if (selected[i] == index - column) {
return "前二選號:各位不能重複";
}
}
}
break;
case 9:// 前二-組選
break;
case 10:// 前三-直選
if (index / column == 0) {
for (int i = 0; i < selected.length; i++) {
if (selected[i] == index + column
|| selected[i] == index + 2 * column) {
return "前三選號:各位不能重複";
}
}
} else if (index / column == 1) {
for (int i = 0; i < selected.length; i++) {
if (selected[i] == index - column
|| selected[i] == index + column) {
return "前三選號:各位不能重複";
}
}
} else if (index / column == 2) {
for (int i = 0; i < selected.length; i++) {
if (selected[i] == index - column
|| selected[i] == index - 2 * column) {
return "前三選號:各位不能重複";
}
}
}
break;
case 11:// 前三-組選
break;
}
return "yes";
}
public int[][] zhixuanrenyi(int[] selected, int index) {
int[][] state = new int[2][];
int[] remove = selected;
int[] add = new int[] { index };
state[0] = add;
state[1] = remove;
return state;
}
public int[][] zhixuan(int[] selected, int index) {
int[][] state = new int[2][];
int[] remove = null;
int[] add = new int[] { index };
state[0] = add;
state[1] = remove;
return state;
}
public int[][] zuxuan(int[] selected, int index) {
int[][] state = new int[2][];
int[] remove = null;
int[] add = new int[] { index };
state[0] = add;
state[1] = remove;
return state;
}
@Override
public int[][] newRedBalls(int[] selected, int index, boolean isCancel) {
if (isCancel) {
int[][] state = new int[2][];
int[] remove = new int[] { index };
int[] add = null;
state[0] = add;
state[1] = remove;
return state;
}
int n = getIndex(R.array.llx5_playmodes);
switch (n) {
case 0:
return zhixuanrenyi(selected, index);