점액 : 영토 전쟁


18

당신은 점액입니다. 당연히, 점액이기 때문에 가능한 한 많은 영역을 스며 들고 싶습니다. 그러나 똑같은 일을하고 싶은 다른 세 가지 슬라임이 있습니다. 우수한 점액은 누구입니까?

기술

모든 점액은 하나의 경기장으로 모일 것입니다. 심사 위원 (즉, 통제 프로그램)은 가능한 모든 4 점액 조합의 전체 목록을 검토하여 테이블 모서리에 놓고 대부분의 점액이 가장 많이 나오는 점을 관찰합니다.

슬라임은 매번 3 가지 동작 중 하나를 수행 할 수 있습니다 : 확산, 점프 또는 병합. 이러한 의미에 대한 자세한 설명은 출력에 제공됩니다. 섹션에 .

보드 / 아레나

경기장은 정사각형 보드가 될 것입니다 (현재 8x8이지만 향후 변경 될 수 있습니다). 진행중인 게임의 예는 다음과 같습니다.

11111222
11111444
11.22444
.1222.4.
333.3244
33333.44
333...44
333....4

점액은 1에서 4까지의 숫자 (플레이어 1에서 4까지)로 표시되며 빈 공간은 점으로 표시됩니다 (. )으로 . 처음에, 보드는 왼쪽 상단 모서리에있는 플레이어 1의 점액 단일 유닛, 오른쪽 상단에 플레이어 2, 왼쪽 하단에 플레이어 3, 오른쪽 하단에 플레이어 4를 제외한 모든 빈 공간으로 시작합니다.

좌표는 코드에서 읽기 쉽도록 0 기반 행 및 열 인덱스로 표시됩니다. 예를 들어, 좌표 (3, 6)는 4 번째 행 (위의 예에서 a 4) 의 7 번째 사각형을 나타냅니다 . (이렇게하면 정사각형에 쉽게 액세스 할 수 있습니다 board[coords.x][coords.y].) 시각적 설명은 다음과 같습니다.

(0, 0) (0, 1) (0, 2)
(1, 0) (1, 1) (1, 2)
(2, 0) (2, 1) (2, 2)

입력

프로그램의 입력은 당신이 어떤 선수 (1, 2, 3, 4), 쉼표 ( ,), 보드 / 아레나의 내용 (줄 바꿈이 쉼표로 대체 됨)이 될 것입니다. 예를 들어, 위 시나리오에서 플레이어 3 인 경우 입력은 다음과 같습니다.

3,11111222,11111444,11.22444,.1222.4.,333.3244,33333.44,333...44,333....4

산출

프로그램은 4 개의 정수를 출력해야합니다. 처음 두 개는 이동하려는 점액의 행 및 열 인덱스이고 다음 두 개는 이동하려는 점액의 행 및 열 인덱스입니다.

차례마다 세 가지 선택이 있습니다 : 스프레드, 점프 또는 병합.

  • 전파

    퍼지려면 대상 좌표가 이동중인 점액에서 정확히 1 제곱 떨어져 있어야하며 대상 좌표의 사각형은 빈 공간이어야합니다. 퍼질 때, 목표 좌표에 새로운 점액이 생성되고 기존 점액은 제거 되지 않습니다 . 새로운 점액이 생성되면이 새로운 점액 주위의 8 개 사각형에있는 모든 적 점액이 이동 한 플레이어로 변환됩니다.

    예를 들어, 그림 1의 보드에서 플레이어 1이 출력 0 1 1 2되면 결과는 그림 2의 보드가됩니다.

    1.         2.
      11.22      11.12
      1..22      1.112
      ..22.      ..11.
      .....      .....
    
  • 도약

    점프하려면 목표 좌표가 이동중인 점액에서 정확히 2 제곱 떨어져 있어야하며 목표 좌표의 정사각형은 빈 공간이어야합니다. jupming 할 때, 목표 좌표에 새로운 점액이 생성되고 기존 점액이 제거됩니다. 새로운 점액이 생성 된 후이 새로운 점액 주위의 8 개 사각형에있는 모든 적 점액이 이동 한 플레이어로 변환됩니다.

    예를 들어, 그림 1의 보드에서 플레이어 1이 출력 0 1 2 3되면 결과는 그림 2의 보드가됩니다.

    1.         2.    
      11..2      1...2
      1...2      1...1
      ....2      ...11
      ...22      ...11
    
  • 병합

    병합하려면 대상 좌표가 이동중인 점액에서 정확히 한 칸 떨어져 있어야하며 대상 좌표의 사각형이 동일한 플레이어의 점액이어야합니다. 병합 할 때 오래된 점액이 제거됩니다. 그런 다음 대상 점액 주위의 8 개 사각형에있는 모든 빈 공간이 이동 한 플레이어로 변환됩니다 (이전 점액은 이동하지 않음).

    예를 들어, 그림 1의 보드에서 플레이어 1이 출력 0 1 1 2되면 결과는 그림 2의 보드가됩니다.

    1.         2.
      11..2      1.112
      1.1.2      11112
      ....2      .1112
      ..222      ..222
    

유효하지 않은 좌표 (예 :)를 간단히 출력하여 전달할 수도 있습니다 0 0 0 0.

규칙과 제약

추가 규칙은 다음과 같습니다.

  • 데이터를 유지하기 위해 자신의 폴더 내에서 파일을 읽고 쓸 수 있지만 (제출물은에 저장 됨 players/YourBotName/yourBotName.language) 폴더 외부의 다른 어떤 것도 수정하거나 액세스 할 수 없습니다. 인터넷 접속은 금지되어 있습니다.
  • 귀하의 제출물은 다른 제출물을 돕기 위해 특별히 코딩되어 있지 않을 수 있습니다. (여러 개의 제출물이있을 수 있지만 특정 방식으로 서로 상호 작용해서는 안됩니다.)
  • 한 번의 제출 시간은 0.1 초를 넘지 않아야합니다. 제출이 때때로 0.105 초가 걸리더라도 괜찮지 만이 시간 제한보다 지속적으로 오래 걸리지 않을 수 있습니다. (이것은 주로 테스트에 너무 오랜 시간이 걸리지 않도록 위생 검사입니다.)
  • 제출 한 언어가 다른 경우에도 제출 한 내용이 다른 사람과 정확하게 중복 (즉, 동일한 논리를 사용)해서는 안됩니다.
  • 귀하의 제출은 진지한 제출이어야합니다. 이것은 의견에 근거한 것이지만, 제출 한 내용이 문제를 해결하려고 시도하지 않는 경우 (예 : 매번 통과하는 경우) 실격 처리됩니다.

제출 한 내용이 이러한 규칙 중 하나라도 위반하거나 사양을 준수하지 않으면 자격이 박탈되고에서 제거되며 playerlist.txt게임이 처음부터 다시 시작됩니다. 귀하의 제출이 실격되면, 나는 귀하의 게시물에 이유를 설명하는 의견을 남길 것입니다. 그렇지 않으면 제출 한 내용이 리더 보드에 추가됩니다. (리더 보드에 제출 한 내용이 표시되지 않고 게시물에 대한 설명이없고 아래 "최종 업데이트"시간 전에 제출 한 내용을 게시 한 경우 알려주세요. 실수로 간과했을 수 있습니다.)

참가시 다음을 포함하십시오 :

  • 이름.
  • 쉘 명령 (예를 들어, 프로그램을 실행 java MyBot.java, ruby MyBot.rb, python3 MyBot.py, 등).
    • 입력 (플레이어 및 맵)이 여기에 명령 줄 인수로 추가됩니다.
    • 프로그램은 Ubuntu 14.04에서 테스트되므로 코드를 자유롭게 실행할 수 있는지 확인하십시오.
  • 코드가 다른 언어 버전에서 다르게 작동하는 경우 버전 번호입니다.
  • 봇 코드.
  • 필요한 경우 코드를 컴파일하는 방법에 대한 지침.

컨트롤러 코드 / 테스트, 예제 봇

컨트롤러 코드는 C ++로 작성되었으며 Github에서 찾을 수 있습니다 . 코드를 실행하고 테스트하는 방법에 대한 추가 지침은 여기에서 찾을 수 있습니다.

simplebot.rb또한 매 턴마다 임의의 점액을 임의의 위치로 퍼뜨 리거나 뛰어 넘는 매우 간단한 봇이 Github에 게시됩니다 .

채점 및 리더 보드

보드의 모든 사각형이 채워지면 게임이 끝나고 점수가 계산됩니다. 플레이어의 최종 점수는 게임이 끝날 때 점액이 포함 된 사각형의 양입니다. 2000 턴이 지나고 (각 플레이어 당 500) 게임이 여전히 끝나지 않으면 게임은 종료되고 게임이 종료 된 것처럼 점수가보고됩니다.

토너먼트가 끝나면 모든 게임의 점수는 평균적으로 각 플레이어의 최종 점수를 계산하여 순위표에 게시됩니다. 제출 마감일이 없습니다. 새로운 제출이 접수 될 때마다 정기적으로 순위표를 계속 업데이트하겠습니다.

실제 리더 보드가 나타날 때까지 4 개의 제출이 필요합니다.

+--------------------------+-----------+--------------------+
| Name                     | Avg Score | Last Updated (UTC) |
+--------------------------+-----------+--------------------+
| GreedySlime              | 47.000    | Jul 22 10:27 PM    |
| Jumper                   | 12.000    | Jul 22 10:27 PM    |
| ShallowBlue              | 5.000     | Jul 22 10:27 PM    |
| Lichen                   | 0.000     | Jul 22 10:27 PM    |
+--------------------------+-----------+--------------------+

최종 업데이트 : Jul 22 10:27 PM (UTC).


흠, 나는 그것을 놓쳤을지도 모른다. 그러나 당신은 선수 사이의 상호 작용이 어떻게 될지 설명했습니까? 모두가 동시에 움직입니까? 1 번 선수?
justhalf

1
어쩌면 이것이 조금 불명확 한 것을 발견했을 수도 있지만 정확히 "두 정사각형"을 어떻게 정의합니까?
arshajii

90 년대 음료를 바탕으로 한 많은 게임을 생각 나게합니다. ;-)
Benny

@justhalf 플레이어 1이 먼저 움직입니다.
Doorknob

1
@arshajii "두 제곱 거리"는 공식적으로 "X의 최대 변화와 Y의 변화가 2 인 모든 위치"를 의미합니다.
손잡이

답변:


4

욕심

점액 단위의 최대 순이익을 창출하는 움직임을 간단히하십시오.

이것은 Python 2.x 로 작성되었습니다 .

def gen_moves(board, pos):
    """Generate valid moves for a given position.

    Return value is a tuple of the form
       (type, from_x, from_y, to_x, to_y)

    The move 'type' is a single character with:
        - 's' = spread
        - 'j' = jump
        - 'm' = merge
    """

    N = len(board)
    x0, y0 = pos
    player = board[x0][y0]

    for i in -2,-1,0,1,2:
        for j in -2,-1,0,1,2:
            if (i == 0 and j == 0):
                continue

            x1, y1 = x0 + i, y0 + j

            if not ((0 <= x1 < N) and (0 <= y1 < N)):
                continue

            c = board[x1][y1]

            if -1 <= i <= 1 and -1 <= j <= 1:
                if c == '.':
                    yield ('s', x0, y0, x1, y1)
                elif c == player:
                    yield ('m', x0, y0, x1, y1)
            else:
                if c == '.':
                    yield ('j', x0, y0, x1, y1)

def eval_move(board, move, initial_net={'s': 1, 'j': 0, 'm': -1}):
    """Evaluates given move in given context.

    - Assumes move is valid.
    - `move` argument is a tuple of the form
       (type, from_x, from_y, to_x, to_y)
    - The move 'type' is a single character with:
        - 's' = spread
        - 'j' = jump
        - 'm' = merge
    """

    N = len(board)
    move_type = move[0]
    x0, y0, x1, y1 = move[1:]
    player = board[x0][y0]

    net = initial_net[move_type]
    for i in -1,0,1:
        for j in -1,0,1:
            if (i == 0 and j == 0):
                continue

            x2, y2 = x1 + i, y1 + j

            if not ((0 <= x2 < N) and (0 <= y2 < N)):
                continue

            c = board[x2][y2]

            if (move_type == 'm' and c == '.') or (move_type != 'm' and c != player and c != '.'):
                net += 1

    return net

def main():
    from sys import argv
    data = argv[1]

    player, board = data.split(',', 1)
    board = map(list, board.split(','))
    N = len(board)

    all_pos_gen = ((a,b) for a in range(N) for b in range(N) if board[a][b] == player)
    all_move_gen = (move for pos in all_pos_gen for move in gen_moves(board, pos))
    move = max(all_move_gen, key=lambda move: eval_move(board, move))

    print move[1], move[2], move[3], move[4]

if __name__ == "__main__":
    main()

예제 실행 (챌린지 설명에 제공된 예제를 사용하고 코드가이라는 파일에 저장되었다고 가정 slime.py) :

$ python slime.py 3,11111222,11111444,11.22444,.1222.4.,333.3244,33333.44,333...44,333....4
4 0 2 2

3

얕은 파랑

진한 파란색 은 가능한 움직임에 대한 철저한 트리 검색을 통해 미래에 어떤 일이 일어날 지 알아 내려고 하지만 불행히도 다음 차례보다 더 이상 얻지 못합니다. 그는 다음 턴 후 가능한 각 보드 스테이트에서 반 반점을 치고 똑같이 어리석은 공식으로 각 지점에 대한 점수를 계산합니다.

편집 : 원래 코드가 너무 느리게 실행되어 가능한 모든 이동의 무작위 샘플 만 가져 오도록 수정했습니다. 가능한 움직임이 거의 없을 때 거의 모든 움직임을 시도하고 가능한 움직임이 많을 때 더 적은 비율을 시도합니다.

import java.awt.Point;  

    public class ShallowBlue {
        private static final int MAX_ROUNDS = 5, PLAYERS = 4;
        static int me = 0;

        public static void main(String[] args) {
            if (args[0] == null) {
                return;
            }

            me = Integer.parseInt(args[0].split(",", 2)[0]);
    String board = args[0].split(",", 2)[1];

    System.out.println(getBestMove(board, me, MAX_ROUNDS - 1));
}

private static String getBestMove(String board, int player, int rounds) {
    String [] boards = new String[24];
    int checkedBoards = 1;
    char playerChar = Integer.toString(player).charAt(0);
    String tempMove = getMove(0, 0, 0, 0);
    String tempBoard = calculateMove(board, tempMove); 
    boards[0] = tempBoard;
    String bestMove = tempMove;
    double us = numberOfUs(board, playerChar); 
    double skip = (us*2.5/(us*2.5 + 1))/4 + 0.735;
    if (rounds == MAX_ROUNDS - 2) {
        skip = skip*skip;
    }

    float bestScore, worstScore, averageScore, tempScore;
    int scores;

    if (rounds == 0) {
        tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
    } else {
        tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
    }

    scores = 1;
    bestScore = tempScore;
    worstScore = tempScore;
    averageScore = tempScore;

    for (int x = 0; x < 8; x++) {
        for (int y = 0; y < 8; y++) {
            if (getCharAt(board, x, y) == playerChar) {
                Point[] possibleMergers = getNeighboringMatches(board, new Point(x, y), playerChar);
                if (possibleMergers[0] != null) {
                    tempMove = getMove(possibleMergers[0].x, possibleMergers[0].y, x, y); 
                    tempBoard = calculateMove(board, tempMove);
                    if (addIfUnique(boards, tempBoard, checkedBoards)) {
                        checkedBoards++;
                        if ((rounds != MAX_ROUNDS - 1) && (rounds == 0 || Math.random() < skip)) {
                            tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
                        } else {
                            tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
                        }

                        if (tempScore > bestScore) {
                            bestMove = tempMove;
                        }
                        bestScore = Math.max(tempScore, bestScore);
                        worstScore = Math.min(tempScore, worstScore);

                        scores++;
                        averageScore = (averageScore*(scores - 1) + tempScore)/scores;
                    }
                }
            } else if (getCharAt(board, x, y) == '.') {
                Point[] possibleSpreaders = getNeighboringMatches(board, new Point(x, y), playerChar);
                int i = 0;
                while (i < possibleSpreaders.length && possibleSpreaders[i] != null) {
                    tempMove = getMove(possibleSpreaders[i].x, possibleSpreaders[i].y, x, y); 
                    tempBoard = calculateMove(board, tempMove);
                    if ((rounds != MAX_ROUNDS - 1) && (rounds == 0 || Math.random() < skip)) {
                        tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
                    } else {
                        tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
                    }

                    if (tempScore > bestScore) {
                        bestMove = tempMove;
                    }
                    bestScore = Math.max(tempScore, bestScore);
                    worstScore = Math.min(tempScore, worstScore);

                    scores++;
                    averageScore = (averageScore*(scores - 1) + tempScore)/scores;

                    i++;
                }
                Point[] possibleJumpers = getNextNeighboringMatches(board, new Point(x, y), playerChar);
                i = 0;
                while (i < possibleJumpers.length && possibleJumpers[i] != null) {
                    tempMove = getMove(possibleJumpers[i].x, possibleJumpers[i].y, x, y); 
                    tempBoard = calculateMove(board, tempMove);
                    if ((rounds != MAX_ROUNDS - 1) && (rounds == 0 || Math.random() < skip)) {
                        tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
                    } else {
                        tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
                    }

                    if (tempScore > bestScore) {
                        bestMove = tempMove;
                    }
                    bestScore = Math.max(tempScore, bestScore);
                    worstScore = Math.min(tempScore, worstScore);

                    scores++;
                    averageScore = (averageScore*(scores - 1) + tempScore)/scores;

                    i++;
                }
            }
        }
    }

    if (rounds == MAX_ROUNDS - 1) {
        return (bestMove);
    } else {
        return getScoreString(bestScore, worstScore, averageScore);
    }
}

private static int numberOfUs(String board, char playerChar) {
    int us = 0;

    for (int i = 0; i < board.length(); i++ ) {
         if (board.charAt(i) == playerChar) {
            us++;
        }
    }

    return us;
}

private static float calculateScore(String board, int roundsPassed) {
    int empties = 0;
    int us = 0;
    int enemy1 = 0;
    int enemy2 = 0;
    int enemy3 = 0;
    for (int i = 0; i < board.length(); i++ ) {
        if (board.charAt(i) == '.') {
            empties++;
        } else if (board.charAt(i) == Integer.toString(me).charAt(0)) {
            us++;
        } else if (board.charAt(i) == Integer.toString(me%PLAYERS + 1).charAt(0)) {
            enemy1++;
        } else if (board.charAt(i) == Integer.toString(me%PLAYERS + 2).charAt(0)) {
            enemy2++;
        } else if (board.charAt(i) == Integer.toString(me%PLAYERS + 3).charAt(0)) {
            enemy3++;
        }
    }

    if (us != 0) {
        us += roundsPassed;
    }

    if (enemy1 != 0) { 
        enemy1 = enemy1 + (roundsPassed + 3)%PLAYERS;
    }

    if (enemy2 != 0) { 
        enemy2 = enemy2 + (roundsPassed + 2)%PLAYERS;
    }

    if (enemy3 != 0) { 
        enemy3 = enemy3 + (roundsPassed + 1)%PLAYERS;
    }

    return us*(empties + 1)/(Math.max(Math.max(enemy1, enemy2), enemy3) + 1);
}

private static float getScore(String scoreString) {
    float bestScore, worstScore, averageScore;
    String[] scores = new String[3];

    scores = scoreString.split(",");
    bestScore = Float.parseFloat(scores[0]);
    worstScore = Float.parseFloat(scores[1]);
    averageScore = Float.parseFloat(scores[2]);


    return (float) Math.sqrt(Math.sqrt(bestScore*averageScore*worstScore*worstScore));
}

private static String getScoreString(float bestScore, float worstScore, float averageScore) {
    return Float.toString(bestScore) + ',' + Float.toString(worstScore) + ',' + Float.toString(averageScore);
}

private static boolean addIfUnique(String[] boards, String board, int checkedBoards) {
    int i = 0;

    while (i < boards.length && boards[i] != null) {
        if (boards[i].equals(board)) {
            return false;
        }
        i++;
    }

    if (i < boards.length) {
        boards[i] = board;
    } else {
        boards[checkedBoards%boards.length] = board;
    }

    return true;
}

private static String calculateMove(String board, String move) {
    int x1 = Integer.parseInt(Character.toString(move.charAt(0)));
    int y1 = Integer.parseInt(Character.toString(move.charAt(2)));
    int x2 = Integer.parseInt(Character.toString(move.charAt(4)));
    int y2 = Integer.parseInt(Character.toString(move.charAt(6)));

    if ((Math.abs(y1 - y2) == 2 || Math.abs(x1 - x2) == 2) 
            &&  getCharAt(board, x2, y2) == '.') {
        Point[] enemies = new Point[8];

        enemies = getNeighboringEnemies(board, new Point(x1, y1), Integer.parseInt(Character.toString(getCharAt(board, x1, y1))));

        board = replace(board, enemies, getCharAt(board, x1, y1));
        Point[] middle = {new Point(x1, y1)};
        board = replace(board, middle, '.');
    }

    if ((Math.abs(y1 - y2) == 1 || Math.abs(x1 - x2) == 1)) { 
        if (getCharAt(board, x2, y2) == '.' || getCharAt(board, x1, y1) == getCharAt(board, x2, y2)) {
            boolean merge = true;
            if (getCharAt(board, x2, y2) == '.') {
                merge = false;
            }

            Point[] spaces = new Point[8];
            spaces = getNeighboringMatches(board, new Point(x1, y1), '.');
            board = replace(board, spaces, getCharAt(board, x1, y1));

            if (merge) {
                Point[] source = {new Point(x1, y1)};
                board = replace(board, source, '.');
            }
        }
    }

    return board;
}

private static String replace(String board, Point[] targets, char source) {
    int i = 0;

    while (i < targets.length && targets[i] != null) {
        if (targets[i].x == 7 && targets[i].y == 7) {
            board = board.substring(0, getIndexAt(targets[i].x, targets[i].y)) + source;
        } else if (targets[i].x == 0 && targets[i].y == 0) {
            board = source + board.substring(getIndexAt(targets[i].x, targets[i].y) + 1);
        } else {
            board = board.substring(0, getIndexAt(targets[i].x, targets[i].y)) + source + board.substring(getIndexAt(targets[i].x, targets[i].y) + 1);
        }
        i++;
    }

    return board;
}

private static Point[] getNeighboringMatches(String board, Point coord, char match) {
    Point[] matches = new Point[8];

    int i = 0;
    for (int x = coord.x - 1; x <= coord.x + 1; x++) {
        for (int y = coord.y - 1; y <= coord.y + 1; y++) {
            if ((y != coord.y || x != coord.x ) && getCharAt(board, x, y) == match){
                matches[i] = new Point(x, y);
                i++;
            }
        }
    }

    return matches;
}

private static Point[] getNeighboringEnemies(String board, Point coord, int player) {
    Point[] enemies = new Point[8];

    for (int i = 1; i <= PLAYERS; i++){
        enemies = mergeArr(enemies, getNeighboringMatches(board, coord, Integer.toString((player + i - 1)%PLAYERS + 1).charAt(0)));
    }

    return enemies;
}

private static Point[] getNextNeighboringMatches(String board, Point coord, char match) {
    Point[] matches = new Point[16];

    int i = 0;
    for (int x = coord.x - 2; x <= coord.x + 2; x++) {
        for (int y = coord.y - 2; y <= coord.y + 2; y++) {
            if ((Math.abs(y - coord.y) == 2 || Math.abs(x - coord.x) == 2) && getCharAt(board, x, y) == match){
                matches[i] = new Point(x, y);
                i++;
            }
        }
    }

    return matches;
}

private static char getCharAt(String board, int x, int y) {

    if (x >= 0 && x < 8 && y >= 0 && y < 8) {
        return board.charAt(9*x + y);
    } else {
        return '\0';
    }
}

private static int getIndexAt(int x, int y) {
    return 9*x + y;
}

private static Point[] mergeArr(Point[] arr1, Point[] arr2) {
    int i = 0;
    int j = 0;

    while (i < arr1.length && arr1[i] != null) {
        i++;
    }

    while (j < arr2.length && arr2[j] != null) {
        arr1[i + j] = arr2[j];
        j++;
    }

    return arr1;
}

private static String getMove(int x1, int y1, int x2, int y2) {
    return Integer.toString(x1) + " " + Integer.toString(y1) + " " + Integer.toString(x2) + " " + Integer.toString(y2);
    }
}

나는 프로그래머가 많지 않고이 접근법은 내가 예상했던 것보다 훨씬 복잡했습니다.이 코드는 오전 3시이므로 아직 테스트하지 않았으며 내일 일찍 일해야합니다. 내 봇이 시간 초과되거나 전혀 작동하지 않을 수 있습니다. 나는 또한 좌표를 잘못 얻었을 수도 있습니다. 내일도 신선한 눈으로 다시 볼 수 있지만 여분의 쌍 (또는 그 이상)은 언제나 환영합니다.
오버 액터

이에 대한 많은 예외가 발생합니다 ( 스택 추적 채팅 참조 ).
Doorknob

내 코드가 마침내 실행되고 있지만 건너 뛰는 지점의 백분율을 줄일 수 있도록 필연적으로 속도를 높여야합니다. 누구 든지이 혼란을 개선하는 방법을 알고 있습니까?
overactor

골프가 아니기 때문에 Code Review 에 게시 할 수 있습니다 ... 규칙에 포함되거나 눈에 띄게 됩니까?
trichoplax

1
나는 이틀 전에이 답변을 보았지만, "Shallow Blue"가 유명한 "Deep Blue"의 말장난임을 깨달았습니다.
justhalf

2

점퍼

더 중간으로 점프하는 것을 좋아합니다.

슬라임이 없으면 점프합니다.

C ++ , 간단히 컴파일해야 함g++ jumper.cpp -o jumper

#include <math.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#define maxn(x, y) ((x) > (y) ? (x) : (y))
#define absn(x) ((x) < 0 ? -(x) : (x))
class Board {
 public:
    Board(std::string input_string);
    void Move();
 private:
    void ParseBoardState(std::string console_string);
    int Slimes(int cell);
    void GetXY(int cell, int& r, int& c);
    bool CanJumpFromHere(int cell, int& jump_to_cell, int& rad);
    int CalcRadius(int cell);
    bool CheckJumpDist(int x, int y);

    int player_num_;
    std::size_t board_dim_;
    std::size_t sq_;
    std::vector< std::vector<int> > slimes_;
};
Board::Board(std::string input_string) 
    : player_num_(0), 
      board_dim_(0),
      slimes_() {
    board_dim_ = std::count(input_string.begin(), input_string.end(), ',');
    sq_ = board_dim_ * board_dim_;
    std::istringstream temp(input_string.substr(0,1));
    temp >> player_num_;
    ParseBoardState(input_string);
}
void Board::ParseBoardState(std::string console_string) {
    int place = 0;
    for (std::size_t row = 0; row < board_dim_; ++row ) {
        slimes_.push_back(std::vector<int>());
        place = console_string.find(",",place+1);
        std::string temp2 = console_string.substr(place+1, 8);
        for (std::size_t col = 0; col < board_dim_; ++col ) {
            int sl = 0;
            std::istringstream bint(temp2.substr(col,1));
            bint >> sl;
            slimes_[row].push_back(sl);
        }
    }
}
int Board::Slimes(int cell) {
    int r = 0;
    int c = 0;
    GetXY(cell, r, c);
    return  slimes_[r][c];
}
void Board::GetXY(int cell, int& r, int& c) {
    for (std::size_t row = 0; row < board_dim_; ++row ) {
        for (std::size_t col = 0; col < board_dim_ ; ++col ) {
            if ( (row * board_dim_ + col) == cell) {
                r = row;
                c = col;
            }
        }
    }
}
void Board::Move() {

    // go through each cell:
    int index = 0;
    int jump_to_cell = 0;
    int rad = 0;
    int min_rad = 1000;
    int best_jump_to = -1;
    int best_jump_from = -1;
    for (int c = 0; c < sq_; ++c) {
        if (Slimes(c) == player_num_) {
            if (CanJumpFromHere(c, jump_to_cell , rad)) {
                if (rad < min_rad) {
                    best_jump_from = c;
                    best_jump_to = jump_to_cell;
                    min_rad = rad;
                }
                index += 1;
            }
        }
    }

    int ret_row = 0;
    int ret_col = 0;

    if (index == 0) {
        // can't jump so dont bother:
        std::cout << "0 0 0 0" << std::endl;
    } else {
        GetXY(best_jump_from, ret_row, ret_col);
        std::cout << ret_row << " " << ret_col  << " ";
        GetXY(best_jump_to, ret_row, ret_col);
        std::cout << ret_row << " " << ret_col << std::endl;
    }
}
bool Board::CanJumpFromHere(int cell, int& ret_jump_to_cell, int & ret_rad) {
    int r = 0;
    int c = 0;
    int rad = 10000;
    int jump_to_cell = 0;
    int rad_min_for_this_cell = 10000;
    GetXY(cell, r, c);
    bool jumpable = false;
    for (int row_test = -2; row_test < 3; ++row_test) {
        for (int col_test = -2; col_test < 3; ++col_test) {
            if ( (r + row_test) > 0 &
                 (r + row_test) < board_dim_ &&
                 (c + col_test) > 0 &&
                 (c + col_test) < board_dim_ &&
                 (CheckJumpDist(col_test, row_test)) &&
                 (slimes_[r+row_test][c+col_test] == 0)) {

                jumpable = true;
                jump_to_cell = (r + row_test) * board_dim_ + c + col_test;
                rad = CalcRadius(jump_to_cell);

                if (rad < rad_min_for_this_cell) {
                    ret_rad = rad;
                    ret_jump_to_cell = jump_to_cell;
                    rad_min_for_this_cell = ret_rad;
                }
            }
        }
    }
    return jumpable;
}
bool Board::CheckJumpDist(int x, int y) {
    int maxDelta = maxn(absn(x), absn(y));
    if (maxDelta <= 0 || maxDelta > 2) {
        return false;
    } else {
        return true;
    }
}
int Board::CalcRadius(int cell) {
    int r = 0;
    int c = 0;
    GetXY(cell, r, c);
    // unnecessary accuracy considering how bad this bot is:
    float mid = static_cast<float>(board_dim_) / 2;
    float rad = sqrt((r - mid) * (r - mid) + (c-mid)*(c-mid));
    int ret = static_cast<int>(rad + 0.5);
    return ret;
}
int main(int argc, char* argv[]) {
    if (argc != 2) {
        return 0;
    } else {
        std::string input_string(argv[1]);
        Board board(input_string);
        board.Move();
    }
    return 0;
}

이동 확인을 미안했습니다. 또한 시작한 직후에 올바른 코딩 방법을 포기 했으므로 보지 마십시오. 그러나 모든 크기의 보드에서 실행되는 것 같습니다.


2

데스 슬림 :

설명 : 가장 약한 적을 사냥하고 파괴하려고합니다. 반복.

실행 방법 : ruby ​​DeathSlime.rb

루비 버전 : 2.1.2

#!/usr/bin/env ruby
class PlayerPosition;
  attr_accessor :x, :y;
  def initialize(x, y) @x = x; @y = y; end
  def distance(pos) Math.sqrt((pos.x - @x)**2 + (pos.y - @y)**2); end
end

class Board
  attr_reader :player, :empty_positions
  def initialize(player_id, game_state_string)
    @player_positions = {}
    @empty_positions = []

    @enemies = []
    @player = Player.new

    row = 0
    col = 0
    game_state_string.chars.each do |tile|
      row += 1 and col = 0 and next if tile == ','
      @empty_positions << PlayerPosition.new(col, row) and col += 1 and next if tile == '.'

      @player_positions[tile] ||= []
      @player_positions[tile] << PlayerPosition.new(col, row)
      col += 1
    end

    @player_positions.each do |id, positions|
      @enemies << Player.new(id, positions) if id != player_id
      @player = Player.new(id, positions) if id == player_id
    end
  end

  def border_space(player_positions, possible_border, allowance = 1)
    near = []
    possible_border.each do |border|
      is_near = false
      player_positions.each {|pos| is_near = true and break if pos.distance(border) <= allowance}
      near << border if is_near
    end
    near
  end

  def closest_to(player_positions, enemy_positions)
    player_closest_block = nil
    shortest_distance = 1000
    enemy_closest_block = nil
    player_positions.each do |player|
      enemy_positions.each do |enemy|
        if player.distance(enemy) < shortest_distance
          shortest_distance = player.distance(enemy)
          enemy_closest_block = enemy
          player_closest_block = player
        end
      end
    end
    return player_closest_block, enemy_closest_block
  end

  def empty_space_near(player_positions, allowance = 1); border_space(player_positions, @empty_positions, allowance); end
  def weakest_enemy; @enemies.select{|enemy| !enemy.dead? }.sort {|x,y| x.strength <=> y.strength}.first; end
end

class Player
  attr_reader :positions
  def initialize(id = -1, positions = []); @id = id; @positions = positions; end
  def dead?; @positions.length == 0; end
  def strength; @positions.length; end
  def can_hurt?(enemy)
    is_close_enough = false
    self.positions.each do |my_pos|
      enemy.positions.each {|enemy_pos| is_close_enough = true and break if my_pos.distance(enemy_pos) <= 2 }
    end
    is_close_enough
  end
end




class DeathSlime

  def initialize(arg_string)
    game_state = arg_string[2..-1]
    player_id = arg_string[0]
    @board = Board.new(player_id, game_state)
  end

  def attack
    if @board.weakest_enemy
      try_to_spread_to_weakest || try_to_jump_to_weakest || try_to_merge_to_weakest || try_to_move_to_weakest
    else
      try_to_move if @empty_positions.length > 0
    end
  end


  def try_to_spread_to_weakest
    mine = @board.empty_space_near(@board.player.positions, 1)
    theirs = @board.empty_space_near(@board.weakest_enemy.positions, 1)
    target_space = mine.detect{|space| theirs.include?(space) }
    return move(@board.closest_to(@board.player.positions, [target_space]).first, target_space) if target_space
    false
  end

  def try_to_jump_to_weakest
    mine = @board.empty_space_near(@board.player.positions, 2)
    theirs = @board.empty_space_near(@board.weakest_enemy.positions, 1)
    target_space = mine.detect{|space| theirs.include?(space) }
    return move(@board.closest_to(@board.player.positions, [target_space]).first, target_space) if target_space
    false
  end

  def try_to_merge_to_weakest
    definite_border = nil
    definite_merge = nil
    possible_border = @board.border_space(@board.weakest_enemy.positions, @board.player.positions)
    possible_border.each do |border|
      possible_merges = @board.border_space([ border ], @board.player.positions.select{|space| space != border })
      definite_merge = possible_merges.first and definite_border = border and break if possible_merges.length > 0
    end
    return move(definite_merge, definite_border) if definite_border && definite_merge
    false
  end

  def try_to_move_to_weakest
    player_closest, enemy_closest = @board.closest_to(@board.player.positions, @board.weakest_enemy.positions)
    spreading_distance = @board.empty_space_near([player_closest], 1)
    jumping_distance = @board.empty_space_near([player_closest], 2)
    theirs = @board.empty_space_near(@board.player.positions, 2)

    spreading_space = spreading_distance.detect{|space| theirs.include?(space) }
    return move(@board.closest_to(@board.player.positions, [spreading_space]).first, spreading_space) if spreading_space

    jumping_space = jumping_distance.detect{|space| theirs.include?(space) }
    return move(@board.closest_to(@board.player.positions, [jumping_space]).first, jumping_space) if jumping_space

    return move(@board.closest_to(@board.player.positions, [spreading_distance]).first, spreading_distance) if spreading_distance.length > 0
    return move(@board.closest_to(@board.player.positions, [jumping_distance]).first, jumping_distance) if jumping_distance.length > 0

    #merge randomly
    closest_enemy = @board.closest_to(@board.player.positions, @board.weakest_enemy.positions).first
    return move(@board.closest_to(@board.player.positions.select{|space| space != closest_enemy }, [closest_enemy]).first, closest_enemy)
  end

  def try_to_move
    spreading_distance = @board.empty_space_near(board.player.positions, 1)
    jumping_distance = @board.empty_space_near(board.player.positions, 2)

    return move(@board.closest_to(@board.player.positions, [spreading_distance]).first, spreading_distance) if spreading_distance.length > 0
    return move(@board.closest_to(@board.player.positions, [jumping_distance]).first, jumping_distance) if jumping_distance.length > 0
  end

  def move(start_block, end_block)
    STDOUT.write "#{start_block.x} #{start_block.y} #{end_block.x} #{end_block.y}"
    true
  end
end

slime_of_death = DeathSlime.new(ARGV[0])
slime_of_death.attack

1

이끼

이것은 R로 작성된 봇입니다 Rscript Lichen.R.를 사용하여 트리거해야합니다 .

input <- strsplit(commandArgs(TRUE),split=",")[[1]]
me <- input[1]
arena <- do.call(rbind,strsplit(input[-1],""))
n <- sum(arena==me)
where <- which(arena==me,arr.ind=TRUE)
closest <- function(a,b){
    x <- abs(outer(a[,1],b[,1],`-`))
    y <- abs(outer(a[,2],b[,2],`-`))
    matrix(which(x<2&y<2,arr.ind=TRUE),ncol=2)
    }
if(n==0){ #No slime on the board
    out <- "0 0 0 0"
    }else if(n==1){ #One slime on the board
        x <- where[1]+c(1,-1)
        y <- where[2]+c(1,-1)
        out <- paste(where[1]-1,where[2]-1,x[x%in%2:(nrow(arena)-1)]-1,y[y%in%2:(nrow(arena)-1)]-1,sep=" ")
    }else{
        area <- apply(which(arena==me,arr.ind=TRUE),2,range,na.rm=TRUE)
        empty <- matrix(which(arena==".",arr.ind=TRUE),ncol=2)
        opponents <- c("1","2","3","4")[c("1","2","3","4")!=me]
        for(i in seq_along(opponents)){
            if(i==1){
                other <- which(arena==opponents[i],arr.ind=TRUE)
                }else{other <- rbind(other,which(arena==opponents[i],arr.ind=TRUE))}
            }
        fillable <- matrix(empty[empty[,1]%in%area[1,1]:area[2,1]&empty[,2]%in%area[1,2]:area[2,2],],ncol=2)
        enemies <- matrix(other[other[,1]%in%area[1,1]:area[2,1]&other[,2]%in%area[1,2]:area[2,2],],ncol=2)
        if(length(unique(where[,2]))==1 | length(unique(where[,2]))==1){ #Slimes form a line
            W <- closest(where,empty)
            if(nrow(W)){
                out <- paste(c(where[W[1,1],]-1,empty[W[1,2],]-1),collapse=" ")
            }else{out <- "0 0 0 0"}
        }else if(length(enemies)&length(fillable)){ #There are enemies and empty spaces in habitable area
            w <- closest(enemies, fillable)
            if(nrow(w)){
                X <- abs(where[,1]-fillable[w[1,2],1])
                Y <- abs(where[,2]-fillable[w[1,2],2])
                W <- which(X<2&Y<2)
                out <- paste(c(where[W[1],]-1,fillable[w[1,2],]-1),collapse=" ")
            }else{out <- "0 0 0 0"}
        }else if(length(fillable)){ #There are empty spaces in habitable area
            w <- closest(fillable,where)
            out <- paste(c(where[w[1,2],]-1,fillable[w[1,1],]-1),collapse=" ")
        }else{
            x <- area[!area[,1]%in%c(1,nrow(arena)),1]
            y <- area[!area[,2]%in%c(1,ncol(arena)),2]
            if(sum(arena[x+(-1:1),y+(-1:1)]==".")>1){
                w <- where[where[,1]%in%(x+c(1,-1))&where[,2]%in%(y+c(1,-1)),]
                out <- paste(w[1]-1,w[2]-1,x-1,y-1,sep=" ")
            }else{
                W <- closest(where, empty)
                if(nrow(W)){
                    out <- paste(c(where[W[1,1],]-1,empty[W[1,2],]-1),collapse=" ")
                }else{out <- "0 0 0 0"}
            }
        }
    }
cat(out)

의도 된 알고리즘은 사각형 영역을 덮으려고합니다 (를 사용하여 공백 채우기 spread). 사각형이 완성되면 merges모서리 중 하나 (보드 모서리에서 가장 먼 영역)에있는 두 개의 슬림형으로 "거주 가능"영역을 확장 한 다음 새로 정의 된 사각형 등을 채 웁니다 jump.

.....   .....   .....   .....   .....   ..333
.....   .333.   3333.   3333.   3333.   33333
333..   3333.   3333.   3333.   3333.   33.33
333..   3.33.   3.33.   3333.   3333.   3333.
333..   333..   333..   333..   3333.   3333.

적이 거주 가능 지역에 있고 그 지역에 빈 공간이 있으면 그 옆에 빈 공간을 채 웁니다. 거주 지역을 확장 할 때 합쳐 져야 할 점액이 적들로 둘러싸여 있다면,이 점액 spread대신이 점액이 합쳐집니다.


이것에 대해 많은 오류가 발생합니다 ( 스택 추적 채팅 참조 ).
Doorknob

0 0 0 0은 보드에 점액이 남아 있지 않을 때 보냅니다 .
plannapus

0

코너 슬림

이 점액에는 모퉁이라는 개념이 있거나 적어도 C #으로 처음 쓸 때 더 이상 확실하지 않습니다.

C ++로 작성된 것으로, 아마도 gcc로 인자없이 컴파일 할 것입니다. 잘만되면 나는 우연히 MSVC에 특정한 것을 사용하지 않았다.

수정 된 서버 (내가있는 멋진 새로운 C ++ 컴파일러가 아님)에서 독점적으로 자체 테스트를 수행 했으므로 수행 방법에 대한 단서가 없으므로 너무 느려서 실격되지 않기를 바랍니다. 이 봇에는 현재 임의성이 없지만 나중에 추가 할 수 있습니다.

이것은 C ++을 실제로 알지 못하는 사람에 의해 C ++로 포팅 된 C #입니다 (속도 문제로 인해). 셀의 배열을 만드는 것으로 시작합니다. 셀의 주위에있는 셀에 대한 도움이되지 않는 모든 정보 (셀 수, 슬라임 수, 그 종류)로 채워집니다. 그런 다음이 정보를 사용하여 해당 정보를 작성하는 데 사용 된 정보를보다 면밀히 검토해야하는지 여부를 결정한 다음 해당 정보를 사용하여 의미있는 결과를 생성 할 수 있습니다.

#include <iostream>

#define min(a,b) a>b?b:a;
#define max(a,b) a>b?a:b;

#define null 0 // fun times

struct Cell
{
public:
    int t;
    int x, y;
    int counts1[5];
    int counts2[5];
    int ecount1;
    int ecount2;
    bool safe1;
    bool safe2;

    bool canspread;
    bool canjump;
    bool canmerge;

    bool spreadable;
    bool jumpable;
    bool mergeable;

    Cell()
    {
        for (int i = 0; i < 5; i++)
        {
            counts2[i]=counts1[i]=0;
        }
        ecount1=ecount2=0;
        safe1=safe2=mergeable=jumpable=spreadable=canmerge=canjump=canspread=false;
    }

    Cell(int tN, int xN, int yN) // not sure why I can't call () constructor here
    {
        for (int i = 0; i < 5; i++)
        {
            counts2[i]=counts1[i]=0;
        }
        ecount1=ecount2=0;
        safe1=safe2=mergeable=jumpable=spreadable=canmerge=canjump=canspread=false;

        t = tN;
        x = xN;
        y = yN;
    }

    void findOptions(int moi)
    {
        if (t == 0)
        {
            if (counts1[moi] > 0)
                spreadable = true;
            if (counts2[moi] > 0)
                jumpable = true;
        }
        else if (t == moi)
        {
            if (counts1[moi] > 0)
                mergeable = canmerge = true;
            if (counts1[0] > 0)
                canspread = true;
            if (counts2[0] > 0)
                canjump = true;
        }
    }
};

const int dim = 8;
const int hdim = 4;

int moi;
int chezMoi;

int target;
int chezTarget;

Cell cells[dim][dim];

int cornerCounts[4][5];
int totalCounts[5];

// ring ness - why why why

// end ring ness

int tlx;
int tly;
int thx;
int thy;

int alx;
int aly;
int ahx;
int ahy;

int rj;
int rstate;

void ring(int x, int y, int dist)
{   
    tlx=x-dist;
    tly=y-dist;
    thx=x+dist;
    thy=y+dist;

    alx=max(0, tlx);
    aly=max(0, tly);
    ahx=min(dim-1, thx);
    ahy=min(dim-1, thy);

    rstate = 0;
}

bool nextR(Cell** outc)
{
    if (rstate == 1)
    {
        goto state1;
    }
    if (rstate == 2)
    {
        goto state2;
    }
    if (rstate == 3)
    {
        goto state3;
    }
    if (rstate == 4)
    {
        goto state4;
    }

    if (alx == tlx)
    {
        rj = aly - 1;
        rstate = 1;
    }
state1:
    if (alx == tlx)
    {
        if (++rj <= ahy)
        {
            *outc = (cells[alx]+rj);
            return true;
        }
        alx++;
    }

    if (ahx == thx)
    {
        rj = aly - 1;
        rstate = 2;
    }
state2:
    if (ahx == thx)
    {
        if (++rj <= ahy)
        {
            *outc = (cells[ahx]+rj);
            return true;
        }
        ahx--;
    }

    if (aly == tly)
    {
        rj = alx - 1;
        rstate = 3;
    }
state3:
    if (aly == tly)
    {
        if (++rj <= ahx)
        {
            *outc = (cells[rj]+aly);
            return true;
        }
    }

    if (ahy == thy)
    {
        rj = alx - 1;
        rstate = 4;
    }
state4:
    if (ahy == thy)
    {
        if (++rj <= ahx)
        {
            *outc = (cells[rj]+ahy);
            return true;
        }
    }

    return null;
}

int cox;
int coy;

int ci;
int cj;

void corner(int idx)
{
    cox = (idx / 2) * hdim;
    coy = (idx % 2) * hdim;

    ci = 0;
    cj = -1;
}

bool nextC(Cell** outc)
{
    for (;ci < hdim;ci++)
    {
        for (;++cj < hdim;)
        {
            *outc = (cells[ci+cox]+cj+coy);
            return true;
        }
        cj = -1;
    }

    return false;
}

void cornerCount(int idx, int* c)
{
    int ox = (idx / 2) * hdim;
    int oy = (idx % 2) * hdim;

    for (int i = 0; i < hdim; i++)
    {
        for (int j = 0; j < hdim; j++)
        {
            c[cells[i+ox][j+oy].t]++;
        }
    }
}

void ringCount(int x, int y, int dist, int* c)
{
    int tlx=x-dist;
    int tly=y-dist;
    int thx=x+dist;
    int thy=y+dist;

    int alx=max(0, tlx);
    int aly=max(0, tly);
    int ahx=min(dim-1, thx);
    int ahy=min(dim-1, thy);

    if (alx == tlx)
    {
        for (int j = aly; j <= ahy; j++)
            c[cells[alx][j].t]++;
        alx++;
    }
    if (ahx == thx)
    {
        for (int j = aly; j <= ahy; j++)
            c[cells[ahx][j].t]++;
        ahx--;
    }
    if (aly == tly)
    {
        for (int i = alx; i <= ahx; i++)
            c[cells[i][aly].t]++;
    }
    if (ahy == thy)
    {
        for (int i = alx; i <= ahx; i++)
            c[cells[i][ahy].t]++;
    }
}

int trans(char c)
{
    return c<48?0:c-48;
}

std::string res(Cell* ca, Cell* cb)
{
    char buff[100]; // shhh
    sprintf_s(buff, "%d %d %d %d\n", ca->x, ca->y, cb->x, cb->y);
    return std::string(buff);
}

std::string go(char* inp)
{
    moi = trans(inp[0]);

    int a = 2;

    for (int i = 0; i < dim; i++)
    {
        for (int j = 0; j < dim; j++)
        {
            cells[i][j] = Cell(trans(inp[a]), i, j);
            a++;
        }
        a++;
    }

    // count corners and totals
    for (int i = 0; i < 4; i++)
    {
        cornerCount(i, cornerCounts[i]);
        for (int j = 0; j < 5; j++)
        {
            totalCounts[j] += cornerCounts[i][j];
        }
    }

    // count and find cell options
    for (int i = 0; i < dim; i++)
    {
        for (int j = 0; j < dim; j++)
        {
            Cell* c = cells[i]+j;

            ringCount(i, j, 1, c->counts1);
            ringCount(i, j, 2, c->counts2);

            // safeness
            for (int r = 1; r < 5; r++)
            {
                if (r != moi)
                {
                    c->ecount1 += c->counts1[r];
                    c->ecount2 += c->counts2[r];
                }
            }
            c->safe1 = c->ecount1 == 0 && c->counts1[0] == 0; // surrounded by moi
            c->safe2 = c->ecount1 == 0 && c->ecount2 == 0; // no enemies in sight

            // that funcion which does stuff
            c->findOptions(moi);
        }
    }

    // find chezMoi
    chezMoi = moi-1; // might work, can't be bothered to work it out
    for (int i = 1; i < 4; i++)
    {
        if (cornerCounts[i][moi] > cornerCounts[chezMoi][moi])
            chezMoi = i;
    }

    int best = 0;

    if (cornerCounts[chezMoi][moi] < hdim * hdim)
    {
        // fill our corner
        best = 0;
        Cell* ac = null;
        Cell* bc = null;

        corner(chezMoi);
        Cell* c;
        while (nextC(&c))
        {
            if (c->spreadable && c->ecount1 + 1 > best)
            {
                ring(c->x, c->y, 1);
                Cell* oc;
                while (nextR(&oc))
                {
                    if (oc->canspread)
                    {
                        best = c->ecount1 + 1;
                        ac = oc;
                        bc = c;
                        break;
                    }
                }
            }
            if (c->mergeable && c->counts1[0] - 1 > best)
            {
                ring(c->x, c->y, 1);
                Cell* oc;
                while (nextR(&oc))
                {
                    if (oc->safe2 && oc->canmerge && c->counts1[0] > 0)
                    {
                        best = c->counts1[0] - 1;
                        ac = oc;
                        bc = c;
                        break;
                    }
                }
            }
        }

        if (bc != null)
        {
            return res(ac, bc);
        }
    }

    // pick target (why?)
    target = -1;
    best = 0;
    for (int i = 0; i < 4; i++)
    {
        if (i == moi)
            continue;
        int cur = totalCounts[i];
        if (target == -1 || cur > best)
        {
            target = i;
            best = cur; 
        }
    }

    if (target != -1)
    {
        for (int i = 0; i < 4; i++)
        {
            if (i == chezMoi)
                continue;
            int cur = cornerCounts[i][target];
            if (chezTarget == -1 || cur > best)
            {
                chezTarget = i;
                best = cur;
            }
        }

        // attack chosen target (not sure it does this anymore...)
        best = 0;
        Cell* ac = null;
        Cell* bc = null;

        for (int i = 0; i < dim; i++)
        {
            for (int j = 0; j < dim; j++)
            {
                Cell* c = cells[i]+j;

                if (c->spreadable && c->ecount1 + 1 > best)
                {
                    ring(c->x, c->y, 1);
                    Cell* oc;
                    while (nextR(&oc))
                    {
                        if (oc->canspread)
                        {
                            best = c->ecount1 + 1;
                            ac = oc;
                            bc = c;
                            break;
                        }
                    }
                }
                if (c->jumpable && c->ecount1 - 1 > best)
                {
                    ring(c->x, c->y, 2);
                    Cell* oc;
                    while (nextR(&oc))
                    {
                        if (oc->safe2 && oc->canjump)
                        {
                            best = c->ecount1 - 1;
                            ac = oc;
                            bc = c;
                            break;
                        }
                    }
                }
            }
        }

        if (bc != null)
        {
            return res(ac, bc);
        }
    }

    return "0 0 0 0\n";
}

int main(int argc, char* args[])
{
    printf(go(args[1]).c_str());
    return 0;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.