I'm trying to do an application which set a game plan for a tournament.
I have a method:
public List<Match> creerMatchsTousContreTous(List<Equipe> lEquipe) {
List<Match> lMatch = new ArrayList<>();
for (int i = 0; i < lEquipe.size(); i++) {
for (int j = i + 1; j < lEquipe.size(); j++) {
Match match = new Match();
match.setEquA(lEquipe.get(i));
match.setEquB(lEquipe.get(j));
lMatch.add(match);
}
}
return lMatch;
}
This method receid a list of Teams. Each one must to play which each others. This return a list of plays (Match).
I want now to random the plays. I need that a Team A who plays the first Play not play the next one. And so more.
I use:
Collections.shuffle(lMatch);
But that ramdom the list of plays and it is possible that a tema play two successive plays.
How can I achieve that?
Thanks
Best Regards
EDIT:
EXAMPLE:
The method return a list of games:
TEAM 1 : TEAM 2
TEAM 2 : TEAM 3
TEAM 1 : TEAM 3
TEAM 4 : TEAM 3
TEAM 2 : TEAM 4
TEAM 4 : TEAM 3
creerMatchsTousContreTous() return in this example a list with 6 values. But here for example, in the first game, TEAM 2 is playing, in the second game he is also playing, and this mustn't be.
I would suggest adding a boolean variable, such as justPlayed or hasPlayed, to the Team class. This variable would track if a particular team has just played in a game.
Collections.shuffle(lMatch); // get two random teams using shuffle
while(Match.Team1.getHasPlayed() == True or Match.Team2.getHasPlayed() == True){
Collections.shuffle(lMatch); // try to find different teams
}
lMatch.play(); // you've found two teams, so now you can call your play method
for(Team t:lEquipe){ // go through the list of teams and
t.setHasPlayed(false); // reset the rest each team's boolean
}
Match.Team1.setHasPlayed(true);
Match.Team2.setHasPlayed(true); // set the boolean to true at the end of the turn
//
This is obviously pseudocode, since I don't know your implementation of Match and Team. Still, consider using the boolean instance field and checking if it has been modified in the previous turn.
The one below is a recursive approach. I think it can provide solution in a faster way than one suggested by #Sonedring, as constraint is applied after every randomization.
It is also safer for a corner case where you have less than 4 teams. In the corner case you will not find a solution and you don't to run an endless loop.
Hope this helps.
public static void randomize(List<Match> matches) {
List<Match> randomizedList = new ArrayList<>();
int numberOfAttempts = 256;
// tmpSubList is a temporary list that contains all matches
// (excluding unwanted) after n-th iteration (randomization).
List<Match> tmpSubList = new ArrayList<Match>(matches);
while (matches.size() > 0) {
// if tmpSubList contains - it means there is no match that can be added.
// Need to restart randomization algorithm.
if (tmpSubList.size() == 0) {
System.out.println("Restarting algorithm.");
if (--numberOfAttempts == 0) {
throw new ArithmeticException("Could not find solution.");
}
// Need to restart:
matches.addAll(randomizedList);
tmpSubList.addAll(randomizedList);
randomizedList.clear();
}
int randomIndex = (int) (tmpSubList.size() * Math.random());
Match match = tmpSubList.remove(randomIndex);
matches.remove(match); // remove also from the main list;
randomizedList.add(match);
Equipe lastTeam1 = match.getEquA();
Equipe lastTeam2 = match.getEquB();
tmpSubList.clear();
matches.stream()
.filter( x -> !x.getEquA().equals(lastTeam1) && !x.getEquB().equals(lastTeam1) )
.filter( x -> !x.getEquA().equals(lastTeam2) && !x.getEquB().equals(lastTeam2) )
.forEach( x -> tmpSubList.add(x));
}
matches.addAll(randomizedList);
}
Related
Following a question here OP is interested in listing all unique 2x2 games. Games here are game theory games in which there with two players and two strategies each. Hence, there are four possible outcomes (see diagram). These outcomes comes with 'payoffs' for each players. Payoff 'pairs' are two payoffs for each player from some combinations of strategies. Payoffs are given in integers and cannot exceed 4.
For instance, consider the following example of a 2x2 game (with a payoff pair is written in the brackets, and P1 and P2 denote player 1 and 2 respectively):
P2
Right Left
Up (2,2) (3,4)
P1
Down (1,1) (4,3)
The payoffs here take the values [ (2,2),(3,4) | (1,1),(4,3) ].
Now, clearly many other games (i.e. unique payoff matrices) are possible. If payoffs for each players is given by 1,2,3,4 (which we can permute in 4!=24 ways) then 24*24 games are possible. OP was interested with listing all these games.
Here comes the subtle part: two unique payoff matrices may nevertheless represent games if one can be obtained from the other by
i) exchanging columns (i.e. relabel Player A's strategies)
ii) exchanging rows (i.e. relabel Player B's strategies)
iii) Exchange the players (i.e. exchanging the payoff pairs and
mirroring the matrix along the first diagonal)
OP posted the following code that correctly lists all 78 possible games in which the payoffs for each can be (1,2,3,4).
I am interested in changing the code so that the program lists all unique games where the possible payoffs are different: i.e. (1,2,3,3) for player 1 and (1,2,3,4) for player 2. Here, there would be 4!/2! ways of permuting (1,2,3,3) and therefore fewer games.
#!/usr/bin/groovy
// Payoff Tuple (a,b) found in game matrix position.
// The Tuple is immutable, if we need to change it, we create a new one.
// "equals()" checks for equality against another Tuple instance.
// "hashCode()" is needed for insertion/retrievel of a Tuple instance into/from
// a "Map" (in this case, the hashCode() actually a one-to-one mapping to the integers.)
class Tuple {
final int a,b
Tuple(int a,int b) {
assert 1 <= a && a <= 4
assert 1 <= b && b <= 4
this.a = a
this.b = b
}
#!/usr/bin/groovy
// Payoff Tuple (a,b) found in game matrix position.
// The Tuple is immutable, if we need to change it, we create a new one.
// "equals()" checks for equality against another Tuple instance.
// "hashCode()" is needed for insertion/retrievel of a Tuple instance into/from
// a "Map" (in this case, the hashCode() actually a one-to-one mapping to the integers.)
class Tuple {
final int a,b
Tuple(int a,int b) {
assert 1 <= a && a <= 4
assert 1 <= b && b <= 4
this.a = a
this.b = b
}
boolean equals(def o) {
if (!(o && o instanceof Tuple)) {
return false
}
return a == o.a && b == o.b
}
int hashCode() {
return (a-1) * 4 + (b-1)
}
String toString() {
return "($a,$b)"
}
Tuple flip() {
return new Tuple(b,a)
}
}
// "GameMatrix" is an immutable structure of 2 x 2 Tuples:
// top left, top right, bottom left, bottom right
// "equals()" checks for equality against another GameMatrix instance.
// "hashCode()" is needed for insertion/retrievel of a GameMatrix instance into/from
// a "Map" (in this case, the hashCode() actually a one-to-one mapping to the integers)
class GameMatrix {
final Tuple tl, tr, bl, br
GameMatrix(Tuple tl,tr,bl,br) {
assert tl && tr && bl && br
this.tl = tl; this.tr = tr
this.bl = bl; this.br = br
}
GameMatrix colExchange() {
return new GameMatrix(tr,tl,br,bl)
}
GameMatrix rowExchange() {
return new GameMatrix(bl,br,tl,tr)
}
GameMatrix playerExchange() {
return new GameMatrix(tl.flip(),bl.flip(),tr.flip(),br.flip())
}
GameMatrix mirror() {
// columnEchange followed by rowExchange
return new GameMatrix(br,bl,tr,tl)
}
String toString() {
return "[ ${tl},${tr} | ${bl},${br} ]"
}
boolean equals(def o) {
if (!(o && o instanceof GameMatrix)) {
return false
}
return tl == o.tl && tr == o.tr && bl == o.bl && br == o.br
}
int hashCode() {
return (( tl.hashCode() * 16 + tr.hashCode() ) * 16 + bl.hashCode() ) * 16 + br.hashCode()
}
}
// Check whether a GameMatrix can be mapped to a member of the "canonicals", the set of
// equivalence class representatives, using a reduced set of transformations. Technically,
// "canonicals" is a "Map" because we want to not only ask the membership question, but
// also obtain the canonical member, which is easily done using a Map.
// The method returns the array [ canonical member, string describing the operation chain ]
// if found, [ null, null ] otherwise.
static dupCheck(GameMatrix gm, Map canonicals) {
// Applying only one of rowExchange, colExchange, mirror will
// never generate a member of "canonicals" as all of these have player A payoff 4
// at topleft, and so does gm
def q = gm.playerExchange()
def chain = "player"
if (q.tl.a == 4) {
}
else if (q.tr.a == 4) {
q = q.colExchange(); chain = "column ∘ ${chain}"
}
else if (q.bl.a == 4) {
q = q.rowExchange(); chain = "row ∘ ${chain}"
}
else if (q.br.a == 4) {
q = q.mirror(); chain = "mirror ∘ ${chain}"
}
else {
assert false : "Can't happen"
}
assert q.tl.a == 4
return (canonicals[q]) ? [ canonicals[q], chain ] : [ null, null ]
}
// Main enumerates all the possible Game Matrixes and builds the
// set of equivalence class representatives, "canonicals".
// We only bother to generate Game Matrixes of the form
// [ (4,_) , (_,_) | (_,_) , (_,_) ]
// as any other Game Matrix can be trivially transformed into the
// above form using row, column and player exchange.
static main(String[] argv) {
def canonicals = [:]
def i = 1
[3,2,1].permutations { payoffs_playerA ->
[4,3,2,1].permutations { payoffs_playerB ->
def gm = new GameMatrix(
new Tuple(4, payoffs_playerB[0]),
new Tuple(payoffs_playerA[0], payoffs_playerB[1]),
new Tuple(payoffs_playerA[1], payoffs_playerB[2]),
new Tuple(payoffs_playerA[2], payoffs_playerB[3])
)
def ( c, chain ) = dupCheck(gm,canonicals)
if (c) {
System.out << "${gm} equivalent to ${c} via ${chain}\n"
}
else {
System.out << "${gm} accepted as canonical entry ${i}\n"
canonicals[gm] = gm
i++
}
}
}
}
I have attempted changing the "assert 1 <= a && a <= 4" to "assert 1 <= a && a <= 3" and then changing the 4's to a 3 further down in the code. This does not seem to work.
I am not sure however what the "int hashCode() {return (a-1) * 4 + (b-1)" or if "(q.tl.a == 4) {
}
else if (q.tr.a == 4) {" does and therefore not sure how to change this.
Apart from this, I suspect that the flips and exchanges can remain the way they are, since this should produce a procedure for identifying unique games no matter what the specific payoff set is (i.e. whether it's 1,2,3,4 or 1,2,3,3).
I have calculated the number of unique games for different payoff sets by hand which may be useful for reference.
I had a similar situation making an AI for Othello/Reversi, and wanting the state-space to be as small as possible to remove redundant processing.
The technique I used was to represent the game as a set of meta-states, or in your case, meta-outcomes, where each meta consists of all the permutations which are equivalent. Listing and identifying equivalent permutations involved coming up with a normalization scheme which determines which orientation or reflection is the key for the meta instance. Then all new permutations are transformed to normalize them before comparing to see if they represented a new instance.
In your case, if swapping rows and columns are both considered equivalent, you might consider the case where the orientation of sorted order puts the smallest value in the top-left corner and the next smallest adjacent value in the top-right corner. This normalizes all 4 flip positions (identity, h-flip, v-vlip, hv-flip) into a single representation.
I'm developing a game in Java, and part of it requires that objects spawn at the top of the screen and proceed to fall down. I have three objects that can possibly spawn, and three possible x coordinates for them to spawn at, all stored in an array called xCoordinate[].
One of the objects is of a class called Enemy, which inherits a class I have called FallingThings. In the FallingThings class, I have methods to generate new objects, my enemy method is below:
public static void generateNewEnemy() {
xIndexEnemyOld = xIndexEnemy;
xIndexEnemy = new Random().nextInt(3);
if (delayTimer == 0) {
while (xIndexEnemy == xIndexEnemyOld) {
xIndexEnemy = new Random().nextInt(3);
}
}
if (xIndexEnemy != xIndexMoney && xIndexEnemy != xIndexFriend) {
Enemy enemy = new Enemy(xCoordinates[xIndexEnemy]);
enemies.add((Enemy) enemy);
} else {
generateNewEnemy();
}
}
xIndexEnemy represents the index of the xCoordinates array.
xIndexMoney and xIndexFriend are the indexes of the xCoordinates array for the two other objects (the comparisons with these values ensures that one object does not spawn directly on top of another).
The delayTimer variable represents the random delay between when new objects spawn, which was set earlier in my main class.
I store each instance of an Enemy object in an ArrayList.
Everything works except for the fact that sometimes, an object will spawn over itself (for example, the delay is 0, so two enemy objects spawn directly on top of each other, and proceed to fall down at the same speed at the same time).
I've been trying to crack this for the past two days, but I understand exactly why my code right now isn't working properly. I even tried implementing collision detection to check if another object already exists in the space, but that didn't work either.
I would be extremely grateful for any suggestions and ideas.
EDIT2
It seems that you still don't understand the problem with your function. It was addressed in the other answer but I'll try to make it more clear.
public static void generateNewEnemy() {
xIndexEnemyOld = xIndexEnemy;
This is just wrong. You can't set the Old index without having actually used a new index yet.
xIndexEnemy = new Random().nextInt(3);
if (delayTimer == 0) {
while (xIndexEnemy == xIndexEnemyOld) {
xIndexEnemy = new Random().nextInt(3);
}
}
This is actually ok. You're generating an index until you get one that is different. It may not be the most elegant of solutions but it does the job.
if (xIndexEnemy != xIndexMoney && xIndexEnemy != xIndexFriend) {
Enemy enemy = new Enemy(xCoordinates[xIndexEnemy]);
enemies.add((Enemy) enemy);
} else {
generateNewEnemy();
}
}
This is your problem (along with setting the Old index back there). Not only do you have to generate an index thats different from the Old index, it must also be different from IndexMoney and IndexFriend.
Now, what happens if, for example, IndexOld = 0, IndexMoney = 1 and IndexFriend = 2? You have to generate an index that's different from 0, so you get (again, for instance) 1. IndexMoney is 1 too, so the condition will fail and you do a recursive call. (Why do you even have a recursive call?)
OldIndex was 0, and now in the next call you're setting it to 1. So IndexOld = 1, IndexMoney = 1 and IndexFriend = 2. Do you see the problem now? The overlapped index is now wrong. And the new index can only be 0 no matter how many recursive calls it takes.
You're shooting yourself in the foot more than once. The recursive call does not result in an infinite loop (stack overflow actually) because you're changing the Old index. (Which, again is in the wrong place)
That if condition is making it so the newly generated index cannot overlap ANY of the previous indexes. From what you said before it's not what you want.
You can simplify your function like this,
public static void generateNewEnemy() {
xIndexEnemy = new Random().nextInt(3);
if (delayTimer == 0) {
while (xIndexEnemy == xIndexEnemyOld) {
xIndexEnemy = new Random().nextInt(3);
}
}
Enemy enemy = new Enemy(xCoordinates[xIndexEnemy]);
enemies.add((Enemy) enemy);
xIndexEnemyOld = xIndexEnemy;
// Now that you used the new index you can store it as the Old one
}
Will it work? It will certainly avoid overlapping when the delayTimer is 0 but I don't know the rest of your code (nor do I want to) and what do you do. It's you who should know.
About my suggestions, they were alternatives for how to generate the index you wanted. I was assuming you would know how to fit them in your code, but you're still free to try them after you've fixed the actual problem.
Original Answer
Here's one suggestion.
One thing you could do is to have these enemies "borrow" elements from the array. Say you have an array,
ArrayList< Float > coordinates = new ArrayList< Float >();
// Add the coordinates you want ...
You can select one of the indexes as you're doing, but use the maximum size of the array instead and then remove the element that you choose. By doing that you are removing one of the index options.
int nextIndex = new Random().nextInt( coordinates.size() );
float xCoordinate = coordinates.get( nextIndex );
coordinates.remove( nextIndex ); // Remove the coordinate
Later, when you're done with the value (say, when enough time has passed, or the enemy dies) you can put it back into the array.
coordinates.add( xCoordinate );
Now the value is available again and you don't have to bother with checking indexes.
Well, this is the general idea for my suggestion. You will have to adapt it to make it work the way you need, specifically when you place the value back into the array as I don't know where in your code you can do that.
EDIT:
Another alternative is, you keep the array that you previously had. No need to remove values from it or anything.
When you want to get a new coordinate create an extra array with only the values that are available, that is the values that won't overlap other objects.
...
if (delayTimer == 0) {
ArrayList< Integer > availableIndexes = new ArrayList< Integer >();
for ( int i = 0; i < 3; ++i ) {
if ( i != xIndexEnemyOld ) {
availableIndexes.add( i );
}
}
int selectedIndex = new Random().nextInt( availableIndexes.size() );
xIndexEnemy = availableIndexes.get( selectedIndex );
}
// Else no need to use the array
else {
xIndexEnemy = new Random().nextInt( 3 );
}
...
And now you're sure that the index you're getting should be different, so no need to check if it overlaps.
The downside is that you have to create this extra array, but it makes your conditions simpler.
(I'm keeping the "new Random()" from your code but other answers/comments refer that you should use a single instance, remember that)
As I see, if delay == 0 all is good, but if not, you have a chance to generate new enemy with the same index. Maybe you want to call return; if delayTimer != 0?
UPDATED
Look what you have in such case:
OldEnemyIndex = 1
NewEnemyIndex = random(3) -> 1
DelayTimer = 2
Then you do not pass to your if statement, then in the next if all is ok, if your enemy has no the same index with money or something else, so you create new enemy with the same index as previous
In my Undead class I have a method written which allows an undead character to sacrifice itself and split its remaining health between the two remaining team mates (the total number of players in the array of chars is always 3).
My function for this is
public void sacrifice(Character other1, Character other2){
int healthgiven = health/2;
health -= health;
other1.health += healthgiven;
other2.health += healthgiven;
System.out.println(name + " has sacrified himself for the team.
His health has been distributed among the two remaining allies. ");
}
This works as far as I know, but it becomes a problem when I have to use it in the main. I somehow have to figure out which elements of the list are the two other characters (who can be Undead as well). Basically when I end up calling undeadchar.sacrifice(other1, other2), I need to find the two characters that are not undeadchar. Sorry if it's confusing I will rewrite this if necessary.
I think you should place a check before calling the method sacrifice.
Assuming that you have getHealth() function in your Player and once the player sacrifices health the health of player is 0 then,
List<Player> PlayersList = new ArrayList<Player>();
Player sacrificingPlayer = ... //Your logic to find sacrificing player
List<Player> healthyPlayers = GetHealthyPlayer(PlayersList );
sacrificingPlayer.sacrifice(healthyPlayers.get(0), healthyPlayers.get(1));
and function GetHealthyPlayer();
public List<Player> GetHealthyPlayer(List<Player> PlayersList )
{
List<Player> Players = new ArrayList<Player>();
int PlayerCount = 0;
for (Player pl: PlayersList )
{
if(pl.getHealth() > 0)
{
Players.add(pl);
PlayerCount++;
if(PlayerCount == 2) //Since we need only two healthy player
break;
}
}
if(PlayerCount != 2)
throw Exception("Two healthy players not found "); //Or you Can return null and check
return Players;
}
Assuming you have something like:
ArrayList<Character> chars = ...; // all of them
Character sacrificingChar = ...; // the one that will sacrifice himself
Then you can do:
List<Character> others = new ArrayList<>(chars);
others.remove(sacrificingChar);
sacrificingChar.sacrifice(others.get(0), others.get(1));
Using Java 8:
List<Character> charList = ...
Character sacrificeChar = ...
List<Character> notSacrificeList = charList.stream()
.filter(x -> !x.equals(sacrificeChar))
.map(Character::new)
.collect(Collectors.toList());
I wrote a little program that tries to find a connection between two equal length English words. Word A will transform into Word B by changing one letter at a time, each newly created word has to be an English word.
For example:
Word A = BANG
Word B = DUST
Result:
BANG -> BUNG ->BUNT -> DUNT -> DUST
My process:
Load an English wordlist(consist of 109582 words) into a Map<Integer, List<String>> _wordMap = new HashMap();, key will be the word length.
User put in 2 words.
createGraph creates a graph.
calculate the shortest path between those 2 nodes
prints out the result.
Everything works perfectly fine, but I am not satisfied with the time it took in step 3.
See:
Completely loaded 109582 words!
CreateMap took: 30 milsecs
CreateGraph took: 17417 milsecs
(HOISE : HORSE)
(HOISE : POISE)
(POISE : PRISE)
(ARISE : PRISE)
(ANISE : ARISE)
(ANILE : ANISE)
(ANILE : ANKLE)
The wholething took: 17866 milsecs
I am not satisfied with the time it takes create the graph in step 3, here's my code for it(I am using JgraphT for the graph):
private List<String> _wordList = new ArrayList(); // list of all 109582 English words
private Map<Integer, List<String>> _wordMap = new HashMap(); // Map grouping all the words by their length()
private UndirectedGraph<String, DefaultEdge> _wordGraph =
new SimpleGraph<String, DefaultEdge>(DefaultEdge.class); // Graph used to calculate the shortest path from one node to the other.
private void createGraph(int wordLength){
long before = System.currentTimeMillis();
List<String> words = _wordMap.get(wordLength);
for(String word:words){
_wordGraph.addVertex(word); // adds a node
for(String wordToTest : _wordList){
if (isSimilar(word, wordToTest)) {
_wordGraph.addVertex(wordToTest); // adds another node
_wordGraph.addEdge(word, wordToTest); // connecting 2 nodes if they are one letter off from eachother
}
}
}
System.out.println("CreateGraph took: " + (System.currentTimeMillis() - before)+ " milsecs");
}
private boolean isSimilar(String wordA, String wordB) {
if(wordA.length() != wordB.length()){
return false;
}
int matchingLetters = 0;
if (wordA.equalsIgnoreCase(wordB)) {
return false;
}
for (int i = 0; i < wordA.length(); i++) {
if (wordA.charAt(i) == wordB.charAt(i)) {
matchingLetters++;
}
}
if (matchingLetters == wordA.length() - 1) {
return true;
}
return false;
}
My question:
How can I improve my algorithm inorder to speed up the process?
For any redditors that are reading this, yes I created this after seeing the thread from /r/askreddit yesterday.
Here's a starting thought:
Create a Map<String, List<String>> (or a Multimap<String, String> if you've using Guava), and for each word, "blank out" one letter at a time, and add the original word to the list for that blanked out word. So you'd end up with:
.ORSE => NORSE, HORSE, GORSE (etc)
H.RSE => HORSE
HO.SE => HORSE, HOUSE (etc)
At that point, given a word, you can very easily find all the words it's similar to - just go through the same process again, but instead of adding to the map, just fetch all the values for each "blanked out" version.
You probably need to run it through a profiler to see where most of the time is taken, especially since you are using library classes - otherwise you might put in a lot of effort but see no significant improvement.
You could lowercase all the words before you start, to avoid the equalsIgnoreCase() on every comparison. In fact, this is an inconsistency in your code - you use equalsIgnoreCase() initially, but then compare chars in a case-sensitive way: if (wordA.charAt(i) == wordB.charAt(i)). It might be worth eliminating the equalsIgnoreCase() check entirely, since this is doing essentially the same thing as the following charAt loop.
You could change the comparison loop so it finishes early when it finds more than one different letter, rather than comparing all the letters and only then checking how many are matching or different.
(Update: this answer is about optimizing your current code. I realize, reading your question again, that you may be asking about alternative algorithms!)
You can have the list of words of same length sorted, and then have a loop nesting of the kind for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) { }.
And in isSimilar count the differences and on 2 return false.
I'm doing my homework, and am stuck on some logic (I think I used that term correctly?). I'm writing an application that shows 12 buttons numbered 1-12, 2 pictures of dice, and a Roll button.
The player rolls the dice (2, 6 sided die) and whatever number(s) he gets, he can use to "cover" some of the twelve numbers. For example, let's say he rolls the dice and gets a 3 and a 5. He gets to choose whether to cover the 3 and the 5, or the total of the two numbers - 8 (Did I mention I'm a math wiz?).
The goal of the game is to cover all the numbers using the least amount of rolls.
The problem I'm having is with, what I believe to be, the if statements:
if (die1 == 3 && die2 == 5) {
player can cover 3 and 5, or 8, but not both
}
Now, I think this works, but if I wrote all this out it would be 36 if statements (give or take zero). Is there an easier way?
By your description I think the player can select die1, die2 or die1 + die2, so to see if the user selected a valid value you need just one if.
if (cover == die1 or cover == die2 or cover == ( die1 + die2)) {
//valid..
}
no if statement needed. player can cover die1 and die2 or die1+die2
This is a good example to use a switch case, IMO.
That'd be 2 switchs which have 6 cases each.
Don't check until the player tries to cover something. By only validating the input you simplify everything down to one if statement.
If you do need to know all possibilities (maybe to show the player possible moves), then ... you still don't need all those if statements. Simply highlight the buttons that match the dice roll and only accept those as input; you'll want to index them in an array or map by their value (e.g. "1") as a way to retrieve them.
You know with two dice you always have three covering options. Presumably elsewhere in code you're going to compare your covered options with numbers. Something like
int[] covered = { die1, die2, die1+die2 };
// ... other stuff
if (comparisonValue > 6) {
// maybe do special stuff since this uses both dice
if (comparisonValue == covered[2]) {
// covered/coverable behavior
} else {
// not
}
} else {
// maybe do special stuff since this only uses one die
if (comparisonValue == covered[0] || comparisonValue == covered[1]) {
// covered/coverable behavior
} else {
// not
}
}
gives you first what's covered, then simple use of it. You could also foreach over the array to do stuff for the covered numbers, ala
for (int c : covered) {
// do stuff with c because it's covered
}
That's fairly fragile, but the flexible answer (e.g., dumping the outcomes into Collection) is way overkill for 6-sided, integer face dice, and the really flexible answer (e.g., accommodating a variable number of dice, specialized combination of faces into outcomes) is like nuclear armageddon for this particular problem.
EDIT for your particular problem, I'd do something like
// start new turn, disable all buttons
// get rolls
int[] coverable = { die1, die2, die1+die2 };
for (int covered : coverable ) {
// enabled covered button
}
If the player can change which of the 1-12 are covered by previous rolls based on a new outcome, well, then you could be in for some fun depending on how much help you want to give them.
I would probably create 2 new objects and use them with a lookup table, like so:
class TossResult{
int firstDie;
int secondDie;
}
Class Coverage{
TossResult tossResult;
int getThirdNumber(){
return tossResult.firstDie + tossResult.secondDie;
}
}
Then on application start-up, populate your map:
HashMap<TossResult, Coverage> lookup = new HashMap<>();
for (int i = 0, i < SIDES_ON_DIE; i++){
for (int j = 0, j < SIDES_ON_DIE; j++){
TossResult tempResult = new TossResult(i,j);
Coverage tempCoverage = new Coverage(tempResult);
lookup.put(tempResult, tempCoverage);
}
}
After a user rolls the dice, create a new TossResult and do a lookup.get(tossResult)
You could also create an array of 12 ints or bools. Initialize all 12 elements (say to 0 or false). Then for each role you can do something lik:
if (false == myArray[die1Value] && false == myArray[die2Value]) {
myArray[die1Value] = true;
myArray[die2Value] = true;
} else if (false == myArray[die1Value + die2Value]) {
myArray[die1Value + die2Value]
} else if (false == myArray[die1Value] || false == myArray[die2Value]) {
if (false == myArray[die1Value]) {
myArray[die1Value] = true;
}
if (false == myArray[die2Value]) {
myArray[die2Value] = true;
}
} else {
// all 12 covered
}
And certainly you can refactor this code some more.
The stated goal "The goal of the game is to cover all the numbers using the least amount of rolls." is not doable, really. The best you can do is to use probabilities to know if, for instance, you should cover on a roll of 1 and 2, a 1 and 2, or 3 first:-)