Проверка количества смежных плиток, принадлежащих игроку, и подсчет очков

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

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

    public void calculate(PowerToken[][] allTokens){
            boolean[][] occupiedRed = new boolean[9][9];
            boolean[][] occupiedWhite = new boolean[9][9];
    
            boolean[][] countedRed = new boolean[9][9];
            boolean[][] countedWhite = new boolean[9][9];
    
            for (int i = 0; i < 9; i++){
                for (int j = 0; j < 9; j++){
                    if (allTokens[i][j].isOnBoard()) {
                        if (allTokens[i][j].getPlayerColor() == Color.RED){
                            occupiedRed[i][j] = true;
                        } else {
                            occupiedWhite[i][j] = true;
                        }
                    }
                }
        }



        // Test printing
        for (int i = 0; i < 9; i++){
            for (int j = 0; j < 9; j++){
                System.out.print(occupiedWhite[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();

        for (int i = 0; i < 9; i++){
            for (int j = 0; j < 9; j++){
                System.out.print(occupiedRed[i][j] + " ");
            }
            System.out.println();
        }
    }

Класс токенов силы

public class PowerToken {
    private int positionX;
    private int positionY;

    private boolean onBoard;

    private Color playerColor;

    public PowerToken(int positionX, int positionY) {
        setPositionX(positionX);
        setPositionY(positionY);
    }

    public PowerToken(int positionX, int positionY, boolean onBoard, Color playerColor) {
        setPositionX(positionX);
        setPositionY(positionY);
        setOnBoard(onBoard);
        setPlayerColor(playerColor);
    }

    public int getPositionX() {
        return positionX;
    }

    public void setPositionX(int positionX) {
        this.positionX = positionX;
    }

    public int getPositionY() {
        return positionY;
    }

    public void setPositionY(int positionY) {
        this.positionY = positionY;
    }

    public boolean isOnBoard() {
        return onBoard;
    }

    public void setOnBoard(boolean onBoard) {
        this.onBoard = onBoard;
    }

    public Color getPlayerColor() {
        return playerColor;
    }

    public void setPlayerColor(Color playerColor) {
        this.playerColor = playerColor;
    }

    @Override
    public String toString() {
        return "PowerToken{" +
                "positionX = " + positionX +
                ", positionY = " + positionY +
                ", onBoard = " + onBoard +
                ", playerColor = " + playerColor +
                '}';
    }
}

Так, например, на этом изображении есть 2 набора из 3 смежных плиток в каждой и 1 набор из 4 смежных плиток.

Обновление 2 Это код, который у меня есть сейчас, однако в результате я получаю пустую карту

public void calculate(PowerToken[][] allTokens){
        boolean[][] occupiedRed = new boolean[9][9];
        boolean[][] occupiedWhite = new boolean[9][9];

        boolean[][] countedRed = new boolean[9][9];
        boolean[][] countedWhite = new boolean[9][9];

        int scoreRed;
        int scoreWhite;

        for (int i = 0; i < 9; i++){
            for (int j = 0; j < 9; j++){
                if (allTokens[i][j].isOnBoard()) {
                    if (allTokens[i][j].getPlayerColor() == Color.RED){
                        occupiedRed[i][j] = true;
                    } else {
                        occupiedWhite[i][j] = true;
                    }
                }
            }
        }

        List<List<Point>> clusters = new ArrayList<>();

        int n = occupiedRed.length;
        int[][] label = new int[n][n];
        int last = 1;
        List<int[]> touching = new ArrayList<>();

        //first pass
        for(int i = 1; i<n; i++){
            for(int j = 1; j<n; j++){
                if (occupiedRed[i][j]){
                    //4 way connectivity.
                    int north = 0;
                    int west = 0;
                    int next = 0;
                    if ( i-1 > 0 && occupiedRed[i-1][j]){
                        west = label[i-1][j];
                    }
                    if ( j-1 < 0 && occupiedRed[i][j-1]){
                        north = label[i][j-1];
                    }
                    if (west != 0){
                        if (north != 0){
                            if (north == west){
                                next = north;
                            } else if (north < west){
                                next = north;
                                touching.add( new int[]{north, west} );
                            } else{
                                next = west;
                                touching.add( new int[]{west, north} );
                            }
                        } else{
                            next = west;
                        }
                    } else if ( north != 0 ){
                        next = north;
                    } else{
                        next = last++;
                    }
                } else{
                    continue;
                }
            }
        }


        Map<Integer, Integer> map = touching.stream()
                .collect(Collectors.toMap(
                        arr -> arr[0],  // key mapping function
                        arr -> arr[1]   // value mapping function
                ));

        System.out.println(map);
    }

Можете ли вы предоставить класс PowerToken?

Jordy 21.02.2023 12:27

Да, я изменю свой пост, чтобы добавить его. я добавил это

Roman 21.02.2023 12:28

Да, я также добавлю схему к вопросу

Roman 21.02.2023 12:38

Да, квадрат 2x2 - это 4 смежных квадрата/плитки.

Roman 21.02.2023 12:43

Как мне это сделать? Я не встречал ни того, ни другого раньше

Roman 21.02.2023 12:49

Вот теория, стоящая за этим. Я могу написать это, хотя это займет немного времени. en.wikipedia.org/wiki/…

matt 21.02.2023 13:19

Я еще не работал с алгоритмами раньше, поэтому я совершенно не уверен, с чего начать, даже с псевдокодом.

Roman 21.02.2023 13:34

Я обновил свой ответ, он завершен, и я считаю, что он работает.

matt 22.02.2023 10:21
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
Лучшая компания по разработке спортивных приложений
Лучшая компания по разработке спортивных приложений
Ищете лучшую компанию по разработке спортивных приложений? Этот список, несомненно, облегчит вашу работу!
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Если вы являетесь веб-разработчиком или тестировщиком, вы можете быть знакомы с Selenium, популярным инструментом для автоматизации работы...
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Что такое Java 8 Streams API? Java 8 Stream API
Деревья поиска (Алгоритм4 Заметки к учебнику)
Деревья поиска (Алгоритм4 Заметки к учебнику)
(1) Двоичные деревья поиска: среднее lgN, наихудшее N для вставки и поиска.
0
8
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По сути, вы собираетесь использовать алгоритм связанных компонентов. На входе у вас будет таблица истинности 9x9 для одного из цветов.

static Map<Integer, List<int[]>> cluster( boolean[][] occupied )

Это двухпроходный алгоритм компонента соединения. Первый проход проходим и делаем предварительные метки, так же создаем «касательный» список, который отслеживает соседние друг с другом регионы.

    int n = occupied.length;
    int[][] label = new int[n][n];
    int last = 1;
    List<int[]> touching = new ArrayList<>();

    //first pass
    for(int i = 0; i<n; i++){
        for(int j = 0; j<n; j++){
            if (occupied[i][j]){
                //4 way connectivity.
                int north = 0;
                int west = 0;
                int next = 0;
                if ( i > 0 && occupied[i-1][j]){
                    west = label[i-1][j];
                }
                if ( j > 0 && occupied[i][j-1]){
                    north = label[i][j-1];
                }
                if (west != 0){
                    if (north != 0){
                        //two labelled regions.
                        if (north == west){
                            //they're the same, it's ok.
                            next = north;
                        } else if (north < west){
                            //label it with the minimum one
                            next = north;
                            touching.add( new int[]{west, north} );
                        } else{
                            next = west;
                            touching.add( new int[]{north, west} );
                        }
                    } else{
                        next = west;
                    }
                } else if ( north != 0 ){
                    next = north;
                } else{
                    next = last++;
                }
                label[i][j] = next; //assign the label.
            } else{
                //not occupied.
                continue;
            }
        }
    }

Это первый проход, в конце первого прохода области помечаются, но есть соприкасающиеся области, которые нужно объединить. Это можно сделать со списком touching, но его нужно немного доработать.

На этом первом шаге все соприкасающиеся метки объединяются в связанные кластеры.

    List<TreeSet<Integer>> clusters = new ArrayList<>();
    
    for(int[] pair: touching){
        TreeSet<Integer> pair0 = null;
        TreeSet<Integer> pair1 = null;
        for(TreeSet<Integer> cluster: clusters){
            if (cluster.contains(pair[0])){
                pair0 = cluster;
            }
            if (cluster.contains(pair[1])){
                pair1 = cluster;
            }
        }
        if ( pair0 == null && pair1 == null){
            //new cluster
            TreeSet<Integer> newCluster = new TreeSet<>();
            newCluster.add(pair[0]);
            newCluster.add(pair[1]);
            clusters.add(newCluster);
        } else if ( pair0 == null ){
            pair1.add(pair[0]);
        } else if ( pair1 == null ){
            pair0.add(pair[1]);
        } else{
            if (pair0 == pair1) continue;
            //both labels are already in clusters but different clusters.
            pair0.addAll(pair1);
            clusters.remove(pair1);
        }
    }

Это проходит и создает сопоставление, так что все значения в кластере будут сопоставлены с наименьшим значением.

    Map<Integer, Integer> fin = new HashMap<>();
    for( TreeSet<Integer> cluster: clusters){
        Integer low = cluster.first();
        for(Integer i: cluster){
            fin.put(i, low);
        }
    }

Второй проход — это просто вопрос связывания меток с их ключами.

    Map<Integer, List<int[]>> result = new HashMap<>();
    //second pass
    for(int i = 0; i<n; i++){
        for(int j = 0; j<n; j++){
            if ( occupied[i][j] ){
                Integer f = fin.computeIfAbsent( label[i][j], k -> k );
                result.computeIfAbsent( f, k -> new ArrayList<>() ).add( new int[]{i, j} );
                label[i][j] = f;
            }
        }
    }

Результат будет содержать метку и набор int[], которые представляют все точки. Чтобы использовать это.

Map<Integer, List<int[]>> whiteClusters = cluster(occupiedWhite);
Map<Integer, List<int[]>> redClusters = cluster(occupiedRed);

Для полноты вот компилируемая рабочая версия.

import java.util.*;

public class ConnComp{
    static void printArray(int[][] arr){
        for(int[] row: arr){
            for(int i: row){
                System.out.printf("%3d",i);
            }
            System.out.println();
        }
    }
    
    static void printArray(boolean[][] arr){
        for(boolean[] row: arr){
            for(boolean i: row){
                System.out.print(i ? "  t" : "  f");
            }
            System.out.println();
        }
    }
    
    static Map<Integer, List<int[]>> cluster( boolean[][] occupied ){
        int n = occupied.length;
        int[][] label = new int[n][n];
        int last = 1;
        List<int[]> touching = new ArrayList<>();

        //first pass
        for(int i = 0; i<n; i++){
            for(int j = 0; j<n; j++){
                if (occupied[i][j]){
                    //4 way connectivity.
                    int north = 0;
                    int west = 0;
                    int next = 0;
                    if ( i > 0 && occupied[i-1][j]){
                        west = label[i-1][j];
                    }
                    if ( j > 0 && occupied[i][j-1]){
                        north = label[i][j-1];
                    }
                    if (west != 0){
                        if (north != 0){
                            //two labelled regions.
                            if (north == west){
                                //they're the same, it's ok.
                                next = north;
                            } else if (north < west){
                                //label it with the minimum one
                                next = north;
                                touching.add( new int[]{west, north} );
                            } else{
                                next = west;
                                touching.add( new int[]{north, west} );
                            }
                        } else{
                            next = west;
                        }
                    } else if ( north != 0 ){
                        next = north;
                    } else{
                        next = last++;
                    }
                    label[i][j] = next; //assign the label.
                } else{
                    //not occupied.
                    continue;
                }
            }
        }
        
        //map reduce
        Comparator<int[]> c = Comparator.comparingInt( arr -> arr[0] );
        Comparator<int[]> c2 = Comparator.comparingInt( arr -> arr[1] );
        c = c.thenComparing(c2);
        
        touching.sort( c );
        List<TreeSet<Integer>> clusters = new ArrayList<>();
        
        for(int[] pair: touching){
            TreeSet<Integer> pair0 = null;
            TreeSet<Integer> pair1 = null;
            for(TreeSet<Integer> cluster: clusters){
                if (cluster.contains(pair[0])){
                    pair0 = cluster;
                }
                if (cluster.contains(pair[1])){
                    pair1 = cluster;
                }
            }
            if ( pair0 == null && pair1 == null){
                //new cluster
                TreeSet<Integer> newCluster = new TreeSet<>();
                newCluster.add(pair[0]);
                newCluster.add(pair[1]);
                clusters.add(newCluster);
            } else if ( pair0 == null ){
                pair1.add(pair[0]);
            } else if ( pair1 == null ){
                pair0.add(pair[1]);
            } else{
                if (pair0 == pair1) continue;
                //both labels are already in clusters but different clusters.
                pair0.addAll(pair1);
                clusters.remove(pair1);
            }
        }
        
        Map<Integer, Integer> fin = new HashMap<>();
        for( TreeSet<Integer> cluster: clusters){
            Integer low = cluster.first();
            for(Integer i: cluster){
                fin.put(i, low);
            }
        }
        
        
        
        System.out.println("occupied");
        printArray(occupied);
        System.out.println("labelled");
        printArray(label);
        
        Map<Integer, List<int[]>> result = new HashMap<>();
        //second pass
        for(int i = 0; i<n; i++){
            for(int j = 0; j<n; j++){
                if ( occupied[i][j] ){
                    Integer f = fin.computeIfAbsent( label[i][j], k -> k );
                    result.computeIfAbsent( f, k -> new ArrayList<>() ).add( new int[]{i, j} );
                    label[i][j] = f;
                }
            }
        }
        System.out.println("after labelling");
        
        printArray(label);        
        
        return result;
    }
    
    static Random r = new Random(42);
    static boolean[][] getBoard(){
        int n = 9;
        boolean[][] board = new boolean[n][n];
        for(int i = 0; i<50; i++){
            int x = r.nextInt(n);
            int y = r.nextInt(n);
            board[x][y] = true;
        }
        return board;
    }
    
    public static void main(String[] args){
        
        cluster(getBoard());
        cluster(getBoard());
        
    }
}

Я не уверен, что это правильный способ закончить это? for(int i = 1; i<n; i++) { for (int j = 1; j < n; j++) { if (occupiedRed[i][j]) { label[i][j] = touching.get(i)[j]; } } } Похоже, что нет, так как я не получаю хороших результатов, когда распечатываю этикетку.

Roman 21.02.2023 13:53

Как бы вы порекомендовали мне правильно преобразовать его?

Roman 21.02.2023 14:25
Map<Integer, Integer> map = touching.stream() .collect(Collectors.toMap( arr -> arr[0], // key mapping function arr -> arr[1] // value mapping function )); Кажется, это не дает мне хороших результатов, это дает мне пустую карту
Roman 21.02.2023 14:31

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

Roman 21.02.2023 14:38

Другие вопросы по теме