Поиск шаблона в массиве строк (Java) - PullRequest
1 голос
/ 06 августа 2020

Как дела, все? Я пытаюсь создать простую игру, в которой в зависимости от ходов, которые делает игрок, некоторый персонаж добавляется к их строке (аналогично для второго игрока). Игра должна определять, появляются ли указанные c символов в этих строках, независимо от того, где в строках они появляются. Для достижения прогресса необходимы комбинации из 3 символов.

Так, например, один успешный ход, который может сделать игрок, добавит символы «c», «d» и «e» где-нибудь в их строке. скажите "abcde". Когда игра обнаруживает «cde» в их строке, они что-то выигрывают. Однако, если строка этого игрока была вместо «ifc4_d'e», игра не обнаружит этот выигрыш, несмотря на то, что содержит те же символы.

EDIT : Ниже приведены три фрагмента кода, но не пугайтесь; последние два - только первые, но с немного измененным массивом и / или методом findWinPatterns().

Вот мой исходный код:

// 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

Он скомпилирован, но потому что contains() метод определяет только точные строки, по порядку, он не подходит для моей игры. Затем я попробовал следующее:

// 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

Это тоже скомпилировано, но не сработало, и я предполагаю, что это потому, что мой RegEx ужасен. Я использовал этот веб-сайт , чтобы подтвердить это, но на то, чтобы исправить это, потребовались годы, и он тоже не казался чистым. Поэтому я решил использовать классы Pattern и Matcher, чтобы упростить чтение кода, и ... ну:

// 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

Это сработало ... точно так же, как мой исходный код. Порядок здесь по-прежнему имеет значение, и я действительно не знаю почему. Я очень близок к тому, чтобы просто выбросить полотенце и использовать org.apache.commons.lang3.StringUtils.containsAny().

Просто быстро решаю что-то: блок switch в настоящее время является комментарием, потому что легче проверить функциональность этой вещи с помощью System.out.println на данный момент. Он должен уже работать, но, по общему признанию, неуклюж; 9 булевых флагов ... Я тоже приму предложения, если вы хотите.

Но в любом случае я был бы очень признателен за помощь в этой головоломке. Спасибо!

1 Ответ

1 голос
/ 06 августа 2020

В основе вашего вопроса, кажется, следующее:

Учитывая строку символов, как я могу проверить, что все эти символы существуют в другой строке

Есть несколько способов сделать это:

Regex:

Регулярное выражение для обнаружения всего "abc" в строке - "^(?=.*a)(?=.*b)(?=.*c).*". Вы можете либо жестко закодировать регулярное выражение, либо построить его из строки следующим образом:

String search = "abc";
String target = "bxaxc"
String regex = "^" + search.replaceAll(".", "(?=.*$0)") + ".*";
if (target.matches(regex)) // true

Use Set содержит:

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

Я ожидал бы производительности второй вариант будет несколько быстрее, но код, в котором производится сравнение, легче понять с первым параметром (регулярное выражение).

Я оставляю вам возможность создать один из этих вариантов или свой собственный, в свой проект.

...