What's up, everyone? I am trying to create a simple game where depending on moves a player makes, some character gets appended to their String (likewise for a second player). The game is supposed to detect whether specific characters show up in those Strings, regardless of where in the Strings they appear. Combinations of 3 characters are needed to make progress.
So, for example, one successful move a player might make would append the characters "c", "d", and "e" somewhere in their String, say "abcde". When the game detects "cde" in their String, they win something. However, if that player's String were instead "ifc4_d'e", the game doesn't detect that win, despite containing the same characters.
EDIT: There are three code snippets below, but don't be alarmed; the latter two are just the first one but with a slightly altered array and/or findWinPatterns()
method.
Here was my initial code:
// The following is used for determining local/global wins.
static final String[][] winPatterns = new String[][] {
// Local board 1
{"!\"#", "$%&", "\'()", "!$\'", "\"%(", "#&)", "!%)", "\'%#"},
// Local board 2
{"*+,", "-./", "0:;", "*-0", "+.:", ",/;", "*.;", "0.,"},
// Local board 3
{"<=>", "?@A", "BCD", "<?B", "=@C", ">AD", "<@D", "B@>"},
// Local board 4
{"EFG", "HIJ", "KLM", "EHK", "FIL", "GJM", "EIM", "KIG"},
// Local board 5
{"NPQ", "RST", "UVW", "NRU", "PSV", "QTW", "NSW", "USQ"},
// Local board 6
{"YZ[", "\\]^", "`ab", "Y\\`", "Z]a", "[^b", "Y]b", "`]["},
// Local board 7
{"cde", "fgh", "ijk", "cfi", "dgj", "ehk", "cgk", "ige"},
// Local board 8
{"lmn", "opq", "rst", "lor", "mps", "nqt", "lpt", "rpn"},
// Local board 9
{"uvw", "xyz", "{}~", "ux{", "vy}", "wz~", "uy~", "{yw"},
// Global board
{"123", "456", "789", "147", "258", "369", "159", "357"}
};
// WIN DETECTION METHOD
// Flag variables
static boolean flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8 = true;
static void findWinPatterns(String score) {
for (int i = 0; i < winPatterns.length; i++) {
for (String pattern : winPatterns[i]) {
if (score.contains(pattern)) {
System.out.println("3 in a row!" + " i = " + i);
/*
switch (i) {
case 0:
if (flag0) {
System.out.println("[Player] has won Local Board 1!");
flag0 = false;
}
break;
case 1:
if (flag1) {
System.out.println("[Player] has won Local Board 2!");
flag1 = false;
}
break;
case 2:
if (flag2) {
System.out.println("[Player] has won Local Board 3!");
flag2 = false;
}
break;
case 3:
if (flag3) {
System.out.println("[Player] has won Local Board 4!");
flag3 = false;
}
break;
case 4:
if (flag4) {
System.out.println("[Player] has won Local Board 5!");
flag4 = false;
}
break;
case 5:
if (flag5) {
System.out.println("[Player] has won Local Board 6!");
flag5 = false;
}
break;
case 6:
if (flag6) {
System.out.println("[Player] has won Local Board 7!");
flag6 = false;
}
break;
case 7:
if (flag7) {
System.out.println("[Player] has won Local Board 8!");
flag7 = false;
}
break;
case 8:
if (flag8) {
System.out.println("[Player] has won Local Board 9!");
flag8 = false;
}
break;
case 9:
// WINNER DECLARED
break;
}
*/
}
}
}
}
// MAIN METHOD HERE
This compiled, but because the contains()
method only detects exact Strings, in order, it isn't suitable for my game. Then I tried this:
// The following is used for determining local/global wins.
static final String[][] winPatterns = new String[][] {
// Local board 1
{"[!\"#]", "[$%&]", "[\'()]", "[!$\']", "[\"%(]", "[#&)]", "[!%)]", "[\'%#]"},
// Local board 2
{"[*+,]", "[-./]", "[0:;]", "[*-0]", "[+.:]", "[,/;]", "[*.;]", "[0.,]"},
// Local board 3
{"[<=>]", "[?@A]", "[BCD]", "[<?B]", "[=@C]", "[>AD]", "[<@D]", "[B@>]"},
// Local board 4
{"[EFG]", "[HIJ]", "[KLM]", "[EHK]", "[FIL]", "[GJM]", "[EIM]", "[KIG]"},
// Local board 5
{"[NPQ]", "[RST]", "[UVW]", "[NRU]", "[PSV]", "[QTW]", "[NSW]", "[USQ]"},
// Local board 6
{"[YZ\\[]", "[\\\\]^]", "[`ab]", "[Y\\`]", "[Z\\]a]", "[\\[^b]", "[Y\\]b]", "[`\\]\\[]"},
// Local board 7
{"[cde]", "[fgh]", "[ijk]", "[cfi]", "[dgj]", "[ehk]", "[cgk]", "[ige]"},
// Local board 8
{"[lmn]", "[opq]", "[rst]", "[lor]", "[mps]", "[nqt]", "[lpt]", "[rpn]"},
// Local board 9
{"[uvw]", "[xyz]", "[{}~]", "[ux{]", "[vy}]", "[wz~]", "[uy~]", "[{yw]"},
// Global board
{"[123]", "[456]", "[789]", "[147]", "[258]", "[369]", "[159]", "[357]"}
};
// WIN DETECTION METHOD
// Flag variables
static boolean flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8 = true;
static void findWinPatterns(String score) {
for (int i = 0; i < winPatterns.length; i++) {
for (String pattern : winPatterns[i]) {
if (score.matches(pattern)) {
System.out.println("3 in a row!" + " i = " + i);
// ... all the same stuff as before ...
}
}
}
}
// MAIN METHOD HERE
This also compiled, but it didn't work, and I assume it is because my RegEx is terrible. I used this website to confirm this, but fixing it was going to take ages and it didn't seem at all clean either. So I opted to use the Pattern and Matcher classes to make some easier-to-read code, and... well:
// The following is used for determining local/global wins; here's where things get UGLY.
static final Pattern[][] winPatterns = new Pattern[][] {
// Local board 1
{Pattern.compile("!\"#", Pattern.LITERAL), Pattern.compile("$%&", Pattern.LITERAL), Pattern.compile("'()", Pattern.LITERAL), Pattern.compile("!$'", Pattern.LITERAL), Pattern.compile("\"%(", Pattern.LITERAL), Pattern.compile("#&)", Pattern.LITERAL), Pattern.compile("!%)", Pattern.LITERAL), Pattern.compile("'%#", Pattern.LITERAL)},
// Local board 2
{Pattern.compile("*+,", Pattern.LITERAL), Pattern.compile("-./", Pattern.LITERAL), Pattern.compile("0:;", Pattern.LITERAL), Pattern.compile("*-0", Pattern.LITERAL), Pattern.compile("+.:", Pattern.LITERAL), Pattern.compile(",/;", Pattern.LITERAL), Pattern.compile("*.;", Pattern.LITERAL), Pattern.compile("0.,", Pattern.LITERAL)},
// Local board 3
{Pattern.compile("<=>", Pattern.LITERAL), Pattern.compile("?@A", Pattern.LITERAL), Pattern.compile("BCD", Pattern.LITERAL), Pattern.compile("<?B", Pattern.LITERAL), Pattern.compile("=@C", Pattern.LITERAL), Pattern.compile(">AD", Pattern.LITERAL), Pattern.compile("<@D", Pattern.LITERAL), Pattern.compile("B@>", Pattern.LITERAL)},
// Local board 4
{Pattern.compile("EFG", Pattern.LITERAL), Pattern.compile("HIJ", Pattern.LITERAL), Pattern.compile("KLM", Pattern.LITERAL), Pattern.compile("EHK", Pattern.LITERAL), Pattern.compile("FIL", Pattern.LITERAL), Pattern.compile("GJM", Pattern.LITERAL), Pattern.compile("EIM", Pattern.LITERAL), Pattern.compile("KIG", Pattern.LITERAL)},
// Local board 5
{Pattern.compile("NPQ", Pattern.LITERAL), Pattern.compile("RST", Pattern.LITERAL), Pattern.compile("UVW", Pattern.LITERAL), Pattern.compile("NRU", Pattern.LITERAL), Pattern.compile("PSV", Pattern.LITERAL), Pattern.compile("QTW", Pattern.LITERAL), Pattern.compile("NSW", Pattern.LITERAL), Pattern.compile("USQ", Pattern.LITERAL)},
// Local board 6
{Pattern.compile("YZ[", Pattern.LITERAL), Pattern.compile("\\]^", Pattern.LITERAL), Pattern.compile("`ab", Pattern.LITERAL), Pattern.compile("Y\\`", Pattern.LITERAL), Pattern.compile("Z]a", Pattern.LITERAL), Pattern.compile("[^b", Pattern.LITERAL), Pattern.compile("Y]b", Pattern.LITERAL), Pattern.compile("`][", Pattern.LITERAL)},
// Local board 7
{Pattern.compile("cde", Pattern.LITERAL), Pattern.compile("fgh", Pattern.LITERAL), Pattern.compile("ijk", Pattern.LITERAL), Pattern.compile("cfi", Pattern.LITERAL), Pattern.compile("dgj", Pattern.LITERAL), Pattern.compile("ehk", Pattern.LITERAL), Pattern.compile("cgk", Pattern.LITERAL), Pattern.compile("ige", Pattern.LITERAL)},
// Local board 8
{Pattern.compile("lmn", Pattern.LITERAL), Pattern.compile("opq", Pattern.LITERAL), Pattern.compile("rst", Pattern.LITERAL), Pattern.compile("lor", Pattern.LITERAL), Pattern.compile("mps", Pattern.LITERAL), Pattern.compile("nqt", Pattern.LITERAL), Pattern.compile("lpt", Pattern.LITERAL), Pattern.compile("rpn", Pattern.LITERAL)},
// Local board 9
{Pattern.compile("uvw", Pattern.LITERAL), Pattern.compile("xyz", Pattern.LITERAL), Pattern.compile("{}~", Pattern.LITERAL), Pattern.compile("ux{", Pattern.LITERAL), Pattern.compile("vy}", Pattern.LITERAL), Pattern.compile("wz~", Pattern.LITERAL), Pattern.compile("uy~", Pattern.LITERAL), Pattern.compile("{yw", Pattern.LITERAL)},
// Global board
{Pattern.compile("123", Pattern.LITERAL), Pattern.compile("456", Pattern.LITERAL), Pattern.compile("789", Pattern.LITERAL), Pattern.compile("147", Pattern.LITERAL), Pattern.compile("258", Pattern.LITERAL), Pattern.compile("369", Pattern.LITERAL), Pattern.compile("159", Pattern.LITERAL), Pattern.compile("357", Pattern.LITERAL)}
};
// WIN DETECTION METHOD
// Flag variables
static boolean flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8 = true;
static void findWinPatterns(String score) {
for (int i = 0; i < winPatterns.length; i++) {
for (Pattern pattern : winPatterns[i]) {
Matcher matcher = pattern.matcher(score);
boolean matchFound = matcher.find();
if (matchFound) {
System.out.println("3 in a row!" + " i = " + i);
// ... again, all the same stuff as before ...
}
}
}
}
// MAIN METHOD HERE
This worked... exactly the same as my initial code. The order here still matters, and I really don't know why. I'm really close to just throwing in the towel and using org.apache.commons.lang3.StringUtils.containsAny()
.
Just addressing something quick: the switch
block is currently a comment because it is easier to test this thing's functionality with a System.out.println
for now. It should work already, but it is admittedly clunky; 9 boolean flags... I'll take suggestions there, too, if you're willing.
But anyway, I'd greatly appreciate some help with this conundrum. Thanks!
Your heart of your question seems to be:
Given a String of characters, how can I check that all those characters exist in another String
There are a couple of ways to do this:
Regex:
The regex for detecting all of "abc"
in a string is "^(?=.*a)(?=.*b)(?=.*c).*"
. You could either hardcode the regex, or build it from the string like this:
String search = "abc";
String target = "bxaxc"
String regex = "^" + search.replaceAll(".", "(?=.*$0)") + ".*";
if (target.matches(regex)) // true
Use Set contains:
String search = "abc";
Set<Integer> searches = search.chars().boxed().collect(toSet());
String target = "bxaxc";
Set<Integer> targets = target.chars().boxed().collect(toSet());
if (searches.stream().allMatch(target::contains)) // true
I would expect the performance of the second option to be somewhat faster, but the code where the comparison is made is easier to understand with the first (regex) option.
I leave it to you to weave one of these options, or your own, into your project.