我有一个Farkle游戏,我试图创建一个"计算机"玩家和我正在努力让这个工作。
游戏玩法:1' s& 5,总是可以评分,直1-6,3种,4种,5种类型的& 6种是可以评分的。如果使用全部6个骰子,对只有可评价。例如:2,2,5,5,4,4。
所以这是我的问题。我让它选择所有骰子只是为了使它工作,但我想找到在棋盘上显示的骰子的价值和这些可评价的组合,并以1:1的方式以编程方式选择它们。屏幕截图显示人类玩家已经选择了5.我知道代码是一团糟(我已被告知几次)。仅供参考,我不得不删除大量代码以保持30000的限制。完整代码为here
以下是我认为需要的文件。你会看到一些Toasts,这是我试图弄清楚我需要做什么的逻辑
AiOhFarkActivity - Main Class
public class AiOhFarkActivity extends Activity implements AnimationEndListener {
private AiGameController controller;
private DieManager dm;
private ArrayList<MyImageView> imageViews = new ArrayList<MyImageView>();
// Added for AI to set the starting
// number of dice selected to 0
private int selectedDie = -1;
//public boolean performItemClick (View v, int position, long id);
private int[] letters = new int[6];
private boolean toFarkle = false;
private int animationCount = 0;
public Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Create, Initialize and then load the Sound manager and Volume Control
setVolumeControlStream(AudioManager.STREAM_MUSIC);
SoundManager. ....
r = getResources();
initializeArrays();
scoreBox = (TextView) ....
numFarkles = (TextView) ....
dieScore = (TextView) ....
scoreButton = (Button) ....
rollButton = (Button) ....
finalButton = (Button) ....
finalRoundLayout = (LinearLayout) ....
winnerButton = (Button) ....
winnerLayout = (LinearLayout) ....
winnerTextView = (TextView) ....
handler = new Handler();
// Restore GameController
if (getLastNonConfigurationInstance() != null) {
controller = (AiGameController) getLastNonConfigurationInstance();
controller.newUI(this);
updateImages(false, false);
} else {
controller = new AiGameController(this);
}
// Restore UI elements
if (savedInstanceState != null && savedInstanceState.getBoolean("hasState")) {
scoreBox.setText ....
numFarkles.setText ....
dieScore.setText ....
scoreButton.setText ....
scoreButton.setEnabled ....
rollButton.setEnabled ....
finalButton.setEnabled ....
finalRoundLayout.setEnabled ....
winnerButton.setEnabled ....
winnerButton.setText ....
winnerLayout.setEnabled ....
}
}
// These arrays allows the use of a for loop in updateImages()
private void initializeArrays() {
imageViews.add((MyImageView) findViewById(R.id.img_1));
imageViews.add((MyImageView) findViewById(R.id.img_2));
imageViews.add((MyImageView) findViewById(R.id.img_3));
imageViews.add((MyImageView) findViewById(R.id.img_4));
imageViews.add((MyImageView) findViewById(R.id.img_5));
imageViews.add((MyImageView) findViewById(R.id.img_6));
letters[0] = R.drawable.dief;
letters[1] = R.drawable.diea;
letters[2] = R.drawable.dier;
letters[3] = R.drawable.diek;
letters[4] = R.drawable.diel;
letters[5] = R.drawable.diee;
}
public void onRoll(View v) {
controller.onRoll();
}
// TODO AI
public void disableButtons(){
}
// TODO AI
public void enableButtons(){
rollButton.setClickable(true);
scoreButton.setClickable(true);
}
// TODO AI
public void disableDice(){
}
// TODO AI
public void enableDice(){
}
public void onScore(View v) {
// Calculate Score
controller.onScore();
//Play Sound
if (myPrefs.getBoolean("soundPrefCheck", true)) {
SoundManager. ....
}
// After Player Scores
// Check to see if the Current Player is now the Machine
// If machine player, roll the dice and lock
// the buttons so the human cannot cheat
// TODO AI
if (controller.isMachinePlayer() == true) {
controller.machineRoll();
disableButtons();
disableDice();
}else {
enableButtons();
enableDice();
}
}
public void updateImages(boolean toAnimate, boolean isFarkle) {
// This is used in onAnimationEnd() to determine when all animations
// have ended. Since all the animations are starting when this method is
// called the count is 0
animationCount = 0;
MyImageView i = null;
for (int j = 0; j < imageViews.size(); j++) {
Animation a = AnimationUtils.loadAnimation(this, R.anim.dice_animation);
i = imageViews.get(j);
// If were gonna animate we need to know when the animation ends.
// Hence were gonna attach this instance as a listener so
// onAnimationEnd() gets called when animations finish.
if (toAnimate) {
i.setAnimationEndListerner(this);
}
// Get the right image from the Resources. *See in DiceManager
// getImage()
i.setImageDrawable(r.getDrawable(controller.getImage(j)));
if (toAnimate && controller.shouldAnimate(j)) {
i.clearAnimation();
i.startAnimation(a);
}
}
// Used in onAnimatonEnds()
if (isFarkle)
toFarkle = true;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
}
@Override
public Object onRetainNonConfigurationInstance() {
return controller;
}
public void showFarkle() {
}
private void farkleAnimation() {
}
@Override
public void onAnimationEnd(View v) {
}
}
AiGameController
public class AiGameController extends PreferenceActivity {
private ArrayList<Player> players = new ArrayList<Player>();
public AiGameController(AiOhFarkActivity ui) {
setupPlayers(ui);
dM = new DieManager();
UI = ui;
updateUIScore();
currPlayer = players.get(round % players.size());
lastPlayer = null;
machinePlayer = players.get(round % players.size());
}
public void setupPlayers(Context c) {
int numOfPlayers = 1;
for (int i = 1; i <= numOfPlayers; i++) {
// TODO AI
String player = "Human ";
String machine = "Machine";
players.add(new Player(player));
players.add(new Player(machine));
}
}
// If the currPlayer is the Machine
// TODO AI
public void machineRoll() {
// Check for Machine Player, if found Roll the dice
// Check for Machine Player, if found Roll the dice
if (currPlayer.getName() == "Machine"){
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
onRoll();
handler.postDelayed(new Runnable() {
public void run() {
onClickDice(0, false);
onClickDice(1, false);
onClickDice(2, false);
onClickDice(3, false);
onClickDice(4, false);
onClickDice(5, false);
android.os.SystemClock.sleep(350);
if (ppossibleScore >= GOB_SCORE){
handler.postDelayed(new Runnable() {
public void run() {
//Play Sound
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(UI);
if (prefs.getBoolean("soundPrefCheck", true)) {
SoundManager.playSound(11, 1); // Flip Sound
}
onScore();
}
}, 750);
}else {
handler.postDelayed(new Runnable() {
public void run() {
// If the highest score possible on the table is 0 then its a farkle
if (Scorer.calculate(dM.diceOnTable(DieManager.ABS_VALUE_FLAG), true,
UI) == 0) {
currPlayer.setInRoundScore(0);
currPlayer.incrementNumOfFarkles();
// True because its a Farkle
endRound(true);
// Else just show what the player rolled
} else
repaetMachineRoll();
}
}, 750);
}
}
}, 1750);
// If all dice are selected (Hot Dice) onRoll again
// Not sure if this belongs here ..... But,
// If the numDiceRemaining <= 2 and the CurrScoreOnTable >= 300
// bank the points - call onScore
// if numDiceRemaining > 2 and CurrScoreOnTable <= 250 - call onRoll
}
}, 1750);
}
// If the currPlayer is the Machine
public boolean isMachinePlayer() {
// TODO Alert AI
// Check for Machine Player, if found Roll the dice
if (currPlayer.getName() == "Machine"){
return true;
}
return false;
}
// Always called from onRoll method
public void startRound() {
isRoundEnded = false;
currPlayer = players.get(round % players.size());
currPlayer.resetInRoundScore();
machinePlayer = players.get(round % players.size());
machinePlayer.resetInRoundScore();
updateUIScore();
// Show the Current Players Number of Farkles
String fmessage = "";
fmessage += UI.getString(R.string.stYouHave) + " " + currPlayer.getNumOfFarkles() + " " + UI.getString(R.string.stFarkles);
UI.updatenumOfFarkles(UTILS.setSpanBetweenTokens(fmessage, "$$", new StyleSpan(Typeface.NORMAL)));
}
// Can be called from onRoll or onScore
public void endRound(boolean isFarkle) {
if (!isFarkle)
UI.rollButtonState(true);
UI.scoreButtonState(false);
String pscore = UI.getString(R.string.stScore);
UI.updatepPoints(UTILS.setSpanBetweenTokens(pscore, "$$", new StyleSpan(Typeface.BOLD)));
// show penalty
SharedPreferences pref=PreferenceManager.getDefaultSharedPreferences(UI);
int farklePenaltyScore = Integer.valueOf(pref.getString("farklePenaltyPref", "-1000"));
// Checks to see if Farkle Penalty is on
if (pref.getBoolean("farklePenalty", true)) {
if (isFarkle && currPlayer.getNumOfFarkles() == 3) {
currPlayer.setInRoundScore(farklePenaltyScore);
// Show a -1000 next to his name
updateUIScore();
// There is a penalty *See animationsEnded()
negateFarklePenalty = true;
}
}
// Alert the UI a farkle is rolled
UI.updateImages(false, isFarkle);
// If its not a farkle then just clear the table and Update the images
if (!isFarkle) {
dM.clearTable();
UI.updateImages(false, false);
}
isRoundEnded = true;
round++;
lastPlayer = currPlayer;
currPlayer = players.get(round % players.size());
// Usually updateUIScore() is called to erase the "+Score" but it
// shouldn't be called if the last player farkled three times because it
// erases the -1000
if (lastPlayer.getNumOfFarkles() != 3)
updateUIScore();
if (!isFarkle && currPlayer.hasHighestScore()) {
alertOfWinner();
}
}
private void alertOfWinner() {
showGameOver();
}
// Finds the player with the Highest score
private int findHighestScore() {
for (Player p : players) {
if (p.hasHighestScore())
return players.indexOf(p);
}
return -1;
}
// Updates the ScoreBox
private void updateUIScore() {
String message = "";
for (Player p : players) {
if (p.equals(currPlayer)) {
int currInRoundScore = p.getInRoundScore();
String temp = "$$ ";
String sign = (currInRoundScore > 0) ? "+" : "";
if (currInRoundScore != 0 && !isRoundEnded)
temp = "$$ " + sign + currInRoundScore + " ";
message += "$$" + p.getName() + temp + p.getScore() + "\n";
} else {
message += p.getName() + " " + p.getScore() + "\n";
}
}
// The $$ tell setSpanBetweenTokens() what to make bold
UI.updateScoreBox(UTILS.setSpanBetweenTokens(message, "$$", new StyleSpan(Typeface.BOLD)));
}
// Number of Current Die remaining on the table
public int numOnTable() {
return dM.numOnTable();
}
// Called when the roll button is clicked or can be called from the AI
public void onRoll() {
UI.finalRoundLayout.setVisibility(View.GONE);
// Sounds
SharedPreferences mySoundPref=PreferenceManager.getDefaultSharedPreferences(UI);
if (mySoundPref.getBoolean("soundPrefCheck", true)) {
}
// Reset Score Button
String message = "";
//message += "Dice Score: 0";
// onRoll
if (isRoundEnded)
startRound();
UI.rollButtonState(false);
UI.scoreButtonState(false);
if (dM.getHighlighted(DieManager.INDEX_FLAG).length > 0) {
int scoreOnTable = Scorer.calculate(
dM.getHighlighted(DieManager.ABS_VALUE_FLAG), true, UI);
currPlayer.incrementInRoundScore(scoreOnTable);
// Show how much was picked up
updateUIScore();
dM.pickUp(dM.getHighlighted(DieManager.INDEX_FLAG));
}
dM.rollDice();
UI.updateImages(true, false);
// If the highest score possible on the table is 0 then its a farkle
if (Scorer.calculate(dM.diceOnTable(DieManager.ABS_VALUE_FLAG), true,
UI) == 0) {
currPlayer.setInRoundScore(0);
currPlayer.incrementNumOfFarkles();
// True because its a Farkle
endRound(true);
// Else just show what the player rolled
} else
UI.updateImages(true, false);
// Check for isMachinePlayer
}
// When a dice is clicked the GameController determines which dice to
// highlight and whether to enable the buttons
public void onClickDice(int index, boolean isFarkle) {
// Play Select Sound
SharedPreferences mySoundPref=PreferenceManager.getDefaultSharedPreferences(UI);
if (mySoundPref.getBoolean("soundPrefCheck", true)) {
SoundManager.playSound(10, 1); // Select Sound
}
String message = "";
String pscore = "";
if (isRoundEnded)
return;
int value = dM.getValue(index, DieManager.ABS_VALUE_FLAG);
// A letter was clicked
if (value == 0)
return;
// Always highlight 5's and 1's
if (value == 5 || value == 1) {
dM.toggleHighlight(index);
} else {
// This method determines if the dice should be highlighted
if (shouldHighlight(index)) {
// if true then get the pairs of this dice
int[] pairs = dM.findPairs(index, DieManager.INDEX_FLAG);
// Highlight them
for (int i : pairs)
dM.toggleHighlight(i);
// And highlight the original dice
dM.toggleHighlight(index);
}
}
// The score of the highlighted dice
int highlightedScore = Scorer.calculate(dM.getHighlighted(DieManager.ABS_VALUE_FLAG), false, UI);
// Second parameter is false to not ignore any extra dice
// The score the player picked up
int possibleScore = currPlayer.getInRoundScore() + highlightedScore + currPlayer.getScore();
// Display the Current Score of the selected Dice
//message += "Dice Score: " + highlightedScore;
message += (UI.getString(R.string.stDiceScore)) + ": " + highlightedScore;
UI.updateCurrentScore(UTILS.setSpanBetweenTokens(message, "$$", new StyleSpan(Typeface.BOLD)));
// Display the Potential Points in the Score Button
int ppossibleScore = currPlayer.getInRoundScore() + highlightedScore;
pscore = "+ " + ppossibleScore;
UI.updatepPoints(UTILS.setSpanBetweenTokens(pscore, "$$", new StyleSpan(Typeface.BOLD)));
if (highlightedScore != 0) {
UI.rollButtonState(true);
// Play Hot Dice sound
if (mySoundPref.getBoolean("soundPrefCheck", true)) {
if (dM.numDiceRemain() == 0){
SoundManager.playSound(8, 1); // HotDice Sound
}
}
// Tells it when to enable the Score Button
// based on the Get-On-Board Value
if (possibleScore >= GOB_SCORE) {
UI.scoreButtonState(true);
showToast("GOB Score met");
}
// If a player is past the winning score
if (isPlayerPastWinScore) {
// Disable the score button
UI.scoreButtonState(false);
// The highest score so far
int scoreOfWinnerToBe = players.get(findHighestScore())
.getScore();
// If the player can get a higher score then enable the score
// button
if (possibleScore > scoreOfWinnerToBe) {
UI.scoreButtonState(true);
}
}
} else {
UI.rollButtonState(false);
UI.scoreButtonState(false);
}
UI.updateImages(false, false);
}
// Calculate the current Score that is possible if banked.
public int CurrScoreOnTable() {
int highlightedScore = Scorer.calculate(dM.getHighlighted(DieManager.ABS_VALUE_FLAG), false, UI);
int possibleScore = lastPlayer.getInRoundScore() + highlightedScore;
return possibleScore;
}
// Determines whether to highlight the dice clicked
private boolean shouldHighlight(int index) {
// Gets the pairs (if any)
int[] pairs = dM.findPairs(index, DieManager.INDEX_FLAG);
int[] valuesOfPairs = new int[pairs.length + 1];
// Takes the value of the pairs and puts them into the valueOfPairs
// array
System.arraycopy(dM.findPairs(index, DieManager.ABS_VALUE_FLAG), 0, valuesOfPairs, 0, pairs.length);
// Adds the dice that was clicked to the array
valuesOfPairs[pairs.length] = dM.getValue(index, DieManager.ABS_VALUE_FLAG);
// True if the value of the pairs and the dice clicked is 0
boolean isZero = Scorer.calculate(valuesOfPairs, false, UI) == 0;
int[] diceOnTable = dM.diceOnTable(DieManager.ABS_VALUE_FLAG);
// True is there are three pairs on the table
boolean isThreePair = Scorer.isThreePair(diceOnTable, UI, true) != 0;
// True if there is a straight on the table
boolean isStraight = Scorer.isStraight(diceOnTable, UI, true) != 0;
return (!isZero || isThreePair || isStraight);
}
// Score button is clicked.
public void onScore() {
// Reset the Current Dice Score and Make Roll Button Active
String message = "";
// message += "Dice Score: 0";
message += (UI.getString(R.string.stDiceScore)) + ": 0";
UI.updateCurrentScore(UTILS.setSpanBetweenTokens(message, "$$", new StyleSpan(Typeface.BOLD)));
String pscore = UI.getString(R.string.stScore);
UI.updatepPoints(UTILS.setSpanBetweenTokens(pscore, "$$", new StyleSpan(Typeface.BOLD)));
// Values of highlighted dice on table
int[] highlighted = dM.getHighlighted(DieManager.ABS_VALUE_FLAG);
// Score of the highlighted dice
int onTable = Scorer.calculate(highlighted, false, UI);
// The players new Score
int newScore = currPlayer.getScore() + onTable + currPlayer.getInRoundScore();
currPlayer.setScore(newScore);
if (newScore >= WINNING_SCORE) {
//SharedPreferences myPrefs=PreferenceManager.getDefaultSharedPreferences(this);
isPlayerPastWinScore = true;
// If no one is over the WINNING_SCORE findWinnerToBe() returns -1
if (findHighestScore() == -1) {
// Player is the first one to pass the score
currPlayer.setOriginalWinner(true);
currPlayer.setHasHighestScore(true);
} else {
currPlayer.setHasHighestScore(true);
}
}
currPlayer.resetInRoundScore();
// False because its not a Farkle
endRound(false);
// Show the Current PLayers Number of Farkles
}
public int getImage(int index) {
return dM.getImage(index);
}
public void newUI(AiOhFarkActivity newUI) {
UI = newUI;
}
// Should not animate if value of dice is 0 ie its a letter
public boolean shouldAnimate(int index) {
return (dM.getValue(index, DieManager.VALUE_FLAG) > 0);
}
public void clearTable() {
dM.clearTable();
}
public void animationsEnded(boolean isFarkle) {
}
}
DieManager
public class DieManager {
// Will return the Indexes of the dice when this is used
public static final int INDEX_FLAG = 1;
// Will return the values of the dice when this is used
public static final int VALUE_FLAG = 2;
// Will return the absolute values of the dice when this is used
public static final int ABS_VALUE_FLAG = 3;
// The array that holds the dice
private int[] diceValues = { 0, 0, 0, 0, 0, 0 };
private HashMap<Integer, Integer> diceImages = new HashMap<Integer, Integer>();
private HashMap<Integer, Integer> deadImages = new HashMap<Integer, Integer>();
private HashMap<Integer, Integer> letterImages = new HashMap<Integer, Integer>();
// Sets @newValue to dieValues[@index]
public void setValue(int index, int newValue) {
Log.w(getClass().getName(), "Index = " + index + " Value = " + newValue);
diceValues[index] = newValue;
}
public DieManager() {
super();
initializeMaps();
}
private void initializeMaps() {
// Shows Selected
diceImages.put(-6, R.drawable.die6_select);
diceImages.put(-5, R.drawable.die5_select);
diceImages.put(-4, R.drawable.die4_select);
diceImages.put(-3, R.drawable.die3_select);
diceImages.put(-2, R.drawable.die2_select);
diceImages.put(-1, R.drawable.die1_select);
// Shows Rolled
diceImages.put(1, R.drawable.die1_roll);
diceImages.put(2, R.drawable.die2_roll);
diceImages.put(3, R.drawable.die3_roll);
diceImages.put(4, R.drawable.die4_roll);
diceImages.put(5, R.drawable.die5_roll);
diceImages.put(6, R.drawable.die6_roll);
// dice are dead
deadImages.put(0, R.drawable.die1_dead);
deadImages.put(1, R.drawable.die2_dead);
deadImages.put(2, R.drawable.die3_dead);
deadImages.put(3, R.drawable.die4_dead);
deadImages.put(4, R.drawable.die5_dead);
deadImages.put(5, R.drawable.die6_dead);
// Shows blank
letterImages.put(0, R.drawable.die_no);
letterImages.put(1, R.drawable.die_no);
letterImages.put(2, R.drawable.die_no);
letterImages.put(3, R.drawable.die_no);
letterImages.put(4, R.drawable.die_no);
letterImages.put(5, R.drawable.die_no);
}
public void rollDice() {
showToast("Rolling Dice");
boolean isNewRound = (numOnTable() == 0);
for (int j = 0; j < 6; j++) {
if (isNewRound || diceValues[j] != 0)
diceValues[j] = (int) ((Math.random() * 6) + 1);
}
}
// Returns the value or absolute value
public int getValue(int index, int flag) {
if (flag == ABS_VALUE_FLAG)
return Math.abs(diceValues[index]);
return diceValues[index];
}
// If a dice value is 0 then its a letter
public int numOnTable() {
int count = 6;
for (int i : diceValues) {
if (i == 0)
count--;
}
return count;
}
// Picking up makes the dice value 0
public void pickUp(int[] highlighted) {
for (int i = 0; i < highlighted.length; i++)
diceValues[highlighted[i]] = 0;
}
// A negative value means a die is highlighted
public void toggleHighlight(int index) {
diceValues[index] *= -1;
}
public void clearTable() {
diceValues[0] = 0;
diceValues[1] = 0;
diceValues[2] = 0;
diceValues[3] = 0;
diceValues[4] = 0;
diceValues[5] = 0;
}
// Return the dice that aren't 0
public int[] diceOnTable(int flag) {
showToast("Getting Dice Values");
if (flag == ABS_VALUE_FLAG) {
int[] array = new int[diceValues.length];
for (int i = 0; i < diceValues.length; i++)
array[i] = Math.abs(diceValues[i]);
return array;
}
return diceValues;
}
//Returns dice that are negative
public int[] getHighlighted(int flag) {
int[] dirtyArray = { 0, 0, 0, 0, 0, 0 };
int count = 0;
for (int j = 0; j < 6; j++) {
if (diceValues[j] < 0) {
if (flag == INDEX_FLAG)
dirtyArray[count++] = j;
if (flag == VALUE_FLAG)
dirtyArray[count++] = diceValues[j];
if (flag == ABS_VALUE_FLAG)
dirtyArray[count++] = Math.abs(diceValues[j]);
}
}
int[] cleanArray = new int[count];
//Returns an array of length 0
if (count == 0)
return cleanArray;
System.arraycopy(dirtyArray, 0, cleanArray, 0, count);
return cleanArray;
}
// Finds in dieValues same @value and excludes @index
public int[] findPairs(int index, int flag) {
int[] dirtyArray = { 0, 0, 0, 0, 0, 0 };
int count = 0;
for (int j = 0; j < 6; j++) {
if (j != index
&& Math.abs(diceValues[j]) == Math.abs(diceValues[index])) {
if (flag == INDEX_FLAG)
dirtyArray[count++] = j;
if (flag == VALUE_FLAG)
dirtyArray[count++] = diceValues[j];
if (flag == ABS_VALUE_FLAG)
dirtyArray[count++] = Math.abs(diceValues[j]);
}
}
int[] cleanArray = new int[count];
if (count == 0)
return cleanArray;
System.arraycopy(dirtyArray, 0, cleanArray, 0, count);
return cleanArray;
}
//Get the Dice Images
public Integer getImage(int index) {
if (diceValues[index] == 0) {
return letterImages.get(index);
} else {
return diceImages.get((diceValues[index]));
}
}
//Get the Number of dice remaining that are not 0
public int numDiceRemain() {
int counter = 0;
for (int j = 0; j < diceValues.length; j++) {
if (diceValues[j] > 0)
counter++;
}
return counter;
}
public void selectDice() {
// TODO Alert AI
}
public void selectAllDice() {
// TODO Alert AI
}
}