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.
Related
Given a class Ball (simplified for this question), where I can not change the equals and hashCode method
class Ball {
String color;
//some more fields, getters, setters, equals, hashcode ..
}
and a list of balls, I want to return true if the list contains at least one ball for each color value "RED", "YELLOW" and "GREEN". Example inputs:
List<Ball> first = List.of(
new Ball("RED"),
new Ball("BLUE"),
new Ball("GREEN"),
new Ball("RED"),
new Ball("YELLOW"),
new Ball("RED"));
List<Ball> second = List.of(
new Ball("RED"),
new Ball("BLUE"),
new Ball("GREEN"),
new Ball("RED"));
expected result for first list is true and for second false. For now I have a classic loop and three counter variables:
private static boolean isValidList(final List<Ball> balls) {
int r = 0;
int y = 0;
int g = 0;
for (Ball ball : balls) {
String color = ball.getColor();
if("RED".equals(color)){
r++;
}
else if("YELLOW".equals(color)){
y++;
}
else if("GREEN".equals(color)){
g++;
}
if(r > 0 && y > 0 && g > 0){
break;
}
}
return r > 0 && y > 0 && g > 0;
}
I have tried to refactor it to use streams like below
private static boolean isValidListStreams(final List<Ball> balls) {
long r = balls.stream().filter(ball -> "RED".equals(ball.getColor())).count();
long y = balls.stream().filter(ball -> "YELLOW".equals(ball.getColor())).count();
long g = balls.stream().filter(ball -> "GREEN".equals(ball.getColor())).count();
return r > 0 && y > 0 && g > 0;
}
but the above need to stream over the list 3 times. Is there a way I can do it in one go? I can't do it with filter using or
return balls.stream()
.filter(ball -> ball.getColor().equals("RED") ||
ball.getColor().equals("YELLOW") ||
ball.getColor().equals("GREEN")).count() >= 3;
since there may be multiple of the same color.
I can't do it with filter using or since there may be multiple of the same color.
You can just use distinct to remove the duplicate colours.
Since you cannot modify equals, you should first map everything to their color first, then distinct and filter.
return balls.stream()
.map(Ball::getColor)
.distinct()
.filter(color -> color.equals("RED") ||
color.equals("YELLOW") ||
color.equals("GREEN")).count() == 3;
Notice that your original for loop is short-circuiting - once you have found the three required colours, you stop looping. However, count will count everything. If that is undesirable, you can do a limit(3) before it.
Also, replacing the || chain with Set.of(...).contains could look better if there are many colours that you want to check:
return balls.stream()
.map(Ball::getColor)
.distinct()
.filter(Set.of("RED", "YELLOW", "GREEN")::contains)
.limit(3)
.count() == 3;
Lets make it a fair fight, your original snippet is much, much longer than it needs to be:
boolean r = false, y = false, g = false;
for (Ball ball : balls) {
String color = ball.getColor();
if ("RED".equals(color)) r = true;
if ("YELLOW".equals(color)) y = true;
if ("GREEN".equals(color)) g = true;
if (r && y && g) return true;
}
return false;
Streams don't 'like it' if you have to refer to results of other operations. That's because the stream API tries to cater to way too many scenarios, thus, you get the lowest common denominator. Which, in this case, is parallel processing: Imagine java runs your stream by handing each individual item to a separated out system - now there is no longer such a thing as 'any previous result' or 'have we seen at least 1 red, at least 1 green, and at least 1 yellow ball at this point' - there is no 'this point', there's just the stream itself.
Hence, it's going to either look ugly (because you're using the wrong tool for the job), or, it's fundamentally far more inefficient. It would look something like this:
return balls.stream()
.map(Ball::getColor)
.filter(x -> x.equals("RED") || x.equals("GREEN") || x.equals("YELLOW"))
.distinct()
.count() == 3;
Comparing code lengths its not significantly simpler. It is considerably worse in performance: It needs to do a distinct scan which requires another run through, and must iterate the whole thing, whereas the first snippet will stop the moment it sees the third color.
Trying to smash those back in, you're looking at a real ugly mess. Golfed to as small as I could make it:
boolean[] c = new boolean[4];
return balls.stream()
.map(Ball::getColor)
.peek(x -> c[x.equals("RED") ? 0 : x.equals("YELLOW") ? 1 : x.equals("BLUE") ? 2 : 3] = true)
.anyMatch(x -> c[0] && c[1] && c[2]);
It's not much code but it introduces all sorts of weirdness - it's weird enough that this probably needs commentary to explain what's going on. So not really a 'win'. It certainly isn't going to be any faster than the original.
In general when you are iterating over a collection with the intent to contrast between values and those operations cannot be described in terms of primitives of the list itself (such as .distinct() or .sorted() or .limit) and there is no pre-baked terminal operation (such as .max()) that does what you want, it's rather likely you do not want streams.
You can extract distinct colors (using Stream API), then simply search in the Set.
Set<String> colors = balls.stream().map(Ball::getColor)
.collect(Collectors.toSet());
if (colors.contains("RED") && colors.contains("GREEN") && colors.contains("YELLOW")) {
// test passes ...
}
If required colors are precomputed as a final Set<String>, code can be even more readable by using containsAll (checking if the retrieved set is a superset of the required set):
final Set<String> requiredColors = Set.of("RED", "GREEN", "YELLOW");
Set<String> colors = balls.stream().map(Ball::getColor)
.collect(Collectors.toSet());
if (colors.containsAll(requiredColors)) { /* test passes */ }
In sort my suggestions are:
Don't hard-code values to check against inside the method, provide them as a parameter.
Use enums, don't rely on strings.
Since you're describing the color of each Ball object with a string name (not for instance as a hex-code) implies that you expect only a moderate number of colors to be used in your application.
And you can improve the design of the Ball class by using a custom enum type Color instead of stream. It will guard you from making a typo and also provides a possibility to introduce a useful behavior withing the Color enum and also benefit from various language and JDK features related to enums.
public enum Color {RED, YELLOW, GREEN}
And even you don't consider utilizing enums it worth to change the method signature of the method you've listed by including an aditional parameter - a Set of colors instead of hard-coding them.
Note: there's also an inconsistency between the title and the code you've provided. The title says:
check if the list contains at list one object with one of three
given
However, your code aims checks whether all given values are present.
That's how you can check whether at least one color from the given set is present, as the question title says,:
private static boolean isValidListStreams(final List<Ball> balls, Set<Color> colors) {
return balls.stream()
.map(Ball::getColor)
.anyMatch(colors::contains);
}
But if you need to check if all the given colors are present, you can do it like that:
private static boolean isValidList(final List<Ball> balls, Set<Color> colors) {
return colors.equals(
balls.stream()
.map(Ball::getColor)
.filter(colors::contains)
.limit(colors.size())
.collect(Collectors.toSet())
);
}
main()
public static void main(String[] args) {
List<Ball> balls = // initializing the source list
isValidListStreams(balls, Set.of(Color.RED, Color.GREEN, Color.YELLOW)); // or simply EnumSet.allOf(Color.class) when you need all enum elements instead of enumerating them
}
Please note that before you flag my question as duplicate, I am referencing this question: What's the best way to check if a String represents an integer in Java?
I am attempting to check graph objects which come from a graph class representing adjacency matrices.
I am using an enhanced for loop to iterate over every node in a graph, and then using a nested enhanced for loop, to then iterate over every connecting edge from each node to each other node.
The thing is that I'm dealing with some graphs that have only integer value edges, and some graphs which have non-integer valued edges.
So, I need to write a method or series of methods that can check to see if every edge in a graph object contains strings that are parsable as integers or not.
My code is very simple and basic but when using graph examples that should return false, I am getting only a true return value.
My code is as follows:
//method to determine if a string can be parsed as an integer greater than zero
public boolean isInteger(String str)
{
try
{ //if the string can be parsed as an int that's greater than zero...
Integer.parseInt(str);
return true;
}
catch(Exception e)
{
return false;
}
}
//method to traverse all edges in a graph object to identify whether or not all
//edges can be parsed as positive integers representing distances
public void checkParsability()
{
//while positive int edges is true and therefore all edges can be parsed as positive integers
if (positive_int_edges)
{
for (Node n : this.nodeList)
{
for (Edge a : n.getOutgoingEdges())
this.setPositive_int_edges(isInteger(a.getLabel()));
//positive_int_edges = isInteger(a.getLabel());
for (Edge a : n.getIncomingEdges())
this.setPositive_int_edges(isInteger(a.getLabel()));
//positive_int_edges = isInteger(a.getLabel());
}
}
//return positive_int_edges;
}
public boolean isPositive_int_edges() {
return positive_int_edges;
}
public void setPositive_int_edges(boolean positive_int_edges) {
this.positive_int_edges = positive_int_edges;
}
The adjacency matrix graph looks something like this:
~ val AAA BB C DDD E
Alfa S ~ > ~ 99 fig
Bravo 67 999 -42 3 x ==
Charlie ~ ~ 4 ~ yz 9
Delta 4e 3 22 x ~ !=2
Echo yes ~ ~ ~ d>e 33
this should return false but for some reason it is always returning true.
Any help would be immensely appreciated. thanks
Edit: positive_int_edges is a boolean attribute of my graph objects which I set to true as default. My hope is to traverse a series of edges until the first instance is found in which a string cannot be parsed as an int, after the first instance is found I want to stop searching since I no longer need to worry about the status of the remaining edges that haven't yet been traversed.
Edit #2 This is how I'm attempting to invoke my methods in my driver class:
System.out.println("\nthe parsability of graph g after call to parsability method is: \n");
g.checkParsability();
System.out.println(g.isPositive_int_edges());
First of all: If you're not interested in the actual numeric value, it might be easier to use regular expressions:
final static Pattern IsIntegerPattern = Pattern.compile("^\\d+$");
public boolean isInteger(String str) {
return IsIntegerPattern.matcher(str).matches();
}
This avoids unecessary exceptions being raised and catched.
About the result being true all the time: That's not actually true. It will return false if the last incoming edge is not a number because you iterate over all edges and check if they are integers but don't break the loop if you reach an edge with a non-integer value. Subsequent edges with valid integer values will "overwrite" that information.
So your implementation should look like this:
public void checkParsability()
{
//while positive int edges is true and therefore all edges can be parsed as positive integers
if (positive_int_edges)
{
for (Node n : this.nodeList)
{
for (Edge a : n.getOutgoingEdges()) {
this.setPositive_int_edges(isInteger(a.getLabel()));
//positive_int_edges = isInteger(a.getLabel());
break;
]
for (Edge a : n.getIncomingEdges()) {
this.setPositive_int_edges(isInteger(a.getLabel()));
//positive_int_edges = isInteger(a.getLabel());
break;
}
}
}
//return positive_int_edges;
}
First of all, I'm aware that there is a similar questions like this. The answer to that question, however, did not help me.
I have the following code:
boolean result = fields[x][y + 1].getRing().getPlayer() == player || fields[x][y - 1].getRing().getPlayer() == player || fields[x + 1][y].getRing().getPlayer() == player || fields[x - 1][y].getRing().getPlayer() == player
The code is supposed to check if there are any rings of the current player above, under or next to the current field.
I'm trying to make this code more readable by using a lambda expression, but I can't get it right. I'm not sure whether this is even possible, though.
I tried to replace fields[x][y] by a variable field and then have field become fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]
boolean result = field.getRing().getPlayer() == player -> field = {fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]};
But this gives me a syntax error, which I expected, since field = {fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]}; sets field to an array, and does not iterate over that array.
Is there any way I can make this code shorter using lambda expression?
You keep repeating the same condition, on 4 different values. So what you want in fact is to avoid this repetition, and write the condition once. And you want to test if any of the 4 values match the condition. So start by storing the 4 values in a collection:
List<Field> neighbors = Arrays.asList(fields[x + 1][y],
fields[x - 1][y],
fields[x][y + 1],
fields[x][y - 1]);
Then test if any of those values match the condition:
boolean result = neighbors.stream().anyMatch(field -> field.getRing().getPlayer() == player);
This doesn't necessarily make the code faster or shorter, but it makes it more readable, and DRY.
I don't think lambdas will help here. What I think is better is just to introduce some methods so that the code is more readable.
For example, you could make four methods ringAbove, ringBelow, ringRight and ringLeft and that would make the code a little more readable.
boolean result = ringAbove(x,y) || ringBelow(x,y) || ringRight(x,y) || ringLeft(x,y);
Now just implement each method, with a bit of refactoring:
private boolean ringAbove( int x, int y ) {
return ringAt( x+1, y);
}
The other three methods can be implemented similarly.
I don't really understand this code, but lets just assume it works. player will need to be available as a global variable, or you'll need to also pass it as a parameter.
private boolean ringAt( int x, int y ) {
if( x < 0 || y < 0 || x >= fields.length || y >= fields[x].length )
return false;
return fields[x][y].getRing().getPlayer() == player;
}
Here is another "tiny embedded domain specific language" for
dealing with positions and fields. It makes use of Java8 Streams and lambdas.
The method neighborhood
abstracts the idea of the shape of a discrete geometric neighborhood, so
that is becomes very easy to deal with all kind of neighborhoods on the
grid, for example with something like this:
# ### # #
#x# #x# # #
# ### x
# #
# #
You wanted the first case, but in the code below, it would be very easy to
replace the concept of "neighborhood" by the 8-cell neighborhood (second case), or by something even weirder, like for example the allowed moves of a knight in chess (third case).
The method neighboringFields makes use of the stream of the purely geometric positions, performs some additional checks on it (to ensure that you don't leave the game universe), and then enumerates all the fields with their content.
You can then use these streams of fields to quickly check various predicates on them, for example using the allMatch and anyMatch methods, as is shown in the very last method checkRingsInNeighborhood,
so that the unwieldy if-expression collapses to just this:
return neighboringFields(pos).anyMatch(
field -> field.getRing().getPlayer() == player
);
Here is the full code snippet:
import java.util.function.*;
import java.util.stream.*;
class NeighborPositions {
// Mock up implementations of `Ring`, `Player`, and `Position`,
// whatever those things are
public static class Ring {
private Player player;
public Ring(Player player) {
this.player = player;
}
public Player getPlayer() {
return this.player;
}
}
public static class Player {
private final String name;
public Player(String name) {
this.name = name;
}
}
public static class Field {
private final Ring ring;
public Field(Ring ring) {
this.ring = ring;
}
public Ring getRing() {
return this.ring;
}
}
// you probably want to fill it somehow...
public static int DIM_X = 100;
public static int DIM_Y = 42;
public static Field[][] fields = null;
/** Position on a rectangular grid */
public static class Position {
final int x;
final int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
}
/** Shortcut for accessing fields at a given position */
public static Field field(Position p) {
return fields[p.x][p.y];
}
/** Generates stream of neighboring positions */
public static Stream<Position> neighborhood(Position pos) {
return Stream.of(
new Position(pos.x + 1, pos.y),
new Position(pos.x - 1, pos.y),
new Position(pos.x, pos.y + 1),
new Position(pos.x, pos.y - 1)
);
}
/** Generates stream of neighboring fields */
public static Stream<Field> neighboringFields(Position pos) {
return neighborhood(pos).
filter(p -> p.x >= 0 && p.x < DIM_X && p.y >= 0 && p.y < DIM_Y).
map(p -> field(p));
}
/** This is the piece of code that you've tried to implement */
public static boolean checkRingsInNeighborhood(Position pos, Player player) {
return neighboringFields(pos).anyMatch(
field -> field.getRing().getPlayer() == player
);
}
}
You obviously shouldn't try to cram everything into a single file and declare it public static, it's just an example.
You could create a BiFunction<Integer, Integer, Player> that, given x and y coordinates, returns a Player:
BiFunction<Integer, Integer, Player> fun = (coordX, coordY) ->
fields[coordX][coordY].getRing().getPlayer();
Now, to check whether a given player's ring is above, under or next to a given pair of coordinates, you could use:
boolean result = List.of(
fun.apply(x, y - 1),
fun.apply(x, y + 1),
fun.apply(x - 1, y),
fun.apply(x + 1, y))
.contains(player);
This uses Java 9's List.of. If you are not in Java 9 yet, just use Arrays.asList.
Besides, it also uses the List.contains method, which checks if a given object belongs to the list by means of the Objects.equals method, which in turn uses the equals method (taking care of nulls). If Player doesn't override equals, then identity equality == will be used as a fallback.
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);
}
I have several small arrayLists (800~1500) and for each one of those I must verify if it contains all items from a evaluation arrayList in the best possible time. Both the target arrayList (let's say, tSet) and the evaluation arrayList (eSet) have 1 to 5 elements.
I have tried a sequence of simple loops (current implementation), with a execution time of ~10 seonds, and containsAll(), with an inconsistent execution time ranging from 8 seconds to 16 seconds (using the same tSet). Is there a reason for this inconsistency? Is there a better way to perform this action?
Array elements are from the following class:
public class ItemBD_Temp implements Comparable<ItemBD_Temp> {
private String sTabela;
private String sValor;
private String sNome;
...
}
which also has a compareTo() method:
public int compareTo(ItemBD_Temp o) {
String concatThis;
String concatOther;
if(this.sTabela.equals("*AnyTable*") || o.sTabela.equals("*AnyTable*")){
concatThis = "";
concatOther = "";
}
else if(this.sNome.equals("*AnyAtrib*") || o.sNome.equals("*AnyAtrib*")){
concatThis = this.sTabela;
concatOther = o.sTabela;
}
else if(this.sValor.equals("*AnyValue*") || o.sValor.equals("*AnyValue*")){
concatThis = this.sTabela + this.sNome;
concatOther = o.sTabela + o.sNome;
}
else{
concatThis = this.sTabela + this.sNome + this.sValor;
concatOther = o.sTabela + o.sNome + o.sValor;
}
return concatThis.compareTo(concatOther);
}
and this is a very simplified version of what I have so far:
for(int j = 0; j < eSet.itens.size() && tSetAllowed == true; j++){
itemFound = false;
//CURRENT ITEM TO BE SEARCHED
eItem = new ItemBD_Temp(eSet.itens.get(j));
//CHECK IF CURRENT ITEM IS ON THE CURRENT tSet. IF FOUND, STOPS AND CHECKS NEXT eItem
for(int k = 0; k < tSet.size() && itemFound == false; k++){
tItem = tSet.get(k);
if(tItem.compareTo(eItem) == 0){
itemFound = true;
}
else{
itemFound = false;
}
}
//IF tItem WASN'T FOUND, THEN tSet CAN BE DISCARTED
if(itemFound==false){
tSetAllowed = false;
}
}
EDIT 1:
In order to use arrayList.containsAll() I also had to override the Equals method, as follows:
#Override
public int hashCode() {
int hash = 3;
hash = 89 * hash + (this.sTabela != null ? this.sTabela.hashCode() : 0);
hash = 89 * hash + (this.sValor != null ? this.sValor.hashCode() : 0);
hash = 89 * hash + (this.sNome != null ? this.sNome.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
System.out.println("OVERRIDED EQUALS");
if (getClass() == obj.getClass()) {
if(this.sTabela.equals("*AnyTable*") || ((ItemBD_Temp)obj).sTabela.equals("*AnyTable*")){
return true;
}
else if(this.sNome.equals("*AnyAtrib*") || ((ItemBD_Temp)obj).sNome.equals("*AnyAtrib*")){
if(this.sTabela.equals(((ItemBD_Temp)obj).sTabela))
return true;
else
return false;
}
else if(this.sValor.equals("*AnyValue*") || ((ItemBD_Temp)obj).sValor.equals("*AnyValue*")){
if((this.sTabela+this.sNome).equals( (((ItemBD_Temp)obj).sTabela+((ItemBD_Temp)obj).sNome) ))
return true;
else
return false;
}
else{
if((this.sTabela+this.sNome+this.sValor).equals( (((ItemBD_Temp)obj).sTabela+((ItemBD_Temp)obj).sNome+((ItemBD_Temp)obj).sValor) ))
return true;
else
return false;
}
}
else{
return (this == obj);
}
}
This is needed because different objects like obj1 = {sTabela = "1", sNome = "2", sValor="3"} and obj2 = {sTabela = "AnyTable", sNome = "AnyAtrib", sValor="AnyValue"} should be considered equivalent.
You are using ArrayList as a data structure. It is an unsynchronized data structure. In your question there are only read operations, so should not be a problem. However, overall in your program with so many unsynchronized lists, think about thread safety.
For ArrayList accessing element via iterator or via index is almost the same in terms of speed. However, that is not an official benchmark. You might consider trying your code with iterators also.
I have several small arrayLists (800~1500) and for each one of those I
must verify if it contains all items from a evaluation arrayList in
the best possible time. Both the target arrayList (let's say, tSet)
and the evaluation arrayList (eSet) have 1 to 5 elements.
You have between 800 and 1500 array lists. I suppose you "are obliged" to use that datastructure.
You have 1 evaluation arrayList. Here I would consider a change maybe. I would use a Hash table/map as a data structure.
In average the search is faster. This is proven to be correct. The average time complexity for inserting/deleting/searching an element in a hash table/map is O(1). This means constant time in average. (The worst case is O(n), but in general we are interested in the average).
"If a target list contains all items of an evaluation list" is equivalent to "all evaluation list items are in target list". In your example you loop through target list and compare, but you could as well loop through evaluation list and compare.
Now assuming that you always want to test whether evaluation
list is a sub set of target list. It is better to loop through
evaluation list and do the comparison as it is expected to have less
elements.
I will go through your code later. But there is one thing that I don't feel comfortable with:
The conditions in your loop! Are you sure your algorithm works as expected?