Lưu viên đạn cuối cùng cho chính mình


51

Cuộc thi bây giờ đã kết thúc. Hèn nhát là người chiến thắng. Bạn có thể xem trận đấu cuối cùng ở đây .

Đột nhiên zombie xuất hiện! ÔI KHÔNG!

Trong thử thách vua đồi này, bạn phải tạo ra một con bot để sống sót trong ngày tận thế zombie. Hoặc ít nhất, giữ càng lâu càng tốt.

Khi bắt đầu trò chơi, 50 trường hợp của mỗi mục sẽ được đặt ngẫu nhiên trong một khu vực chơi hình xuyến lớn - nghĩa là nó có vẻ là hình vuông, nhưng bao quanh. Kích thước của khu vực chơi sẽ thay đổi tùy thuộc vào số lượng mục, nhưng ban đầu 6% hình vuông sẽ bị chiếm. Mỗi đối thủ bắt đầu với 3 viên đạn.

Vào đầu mỗi lượt, một thây ma sẽ trồi lên khỏi mặt đất tại một địa điểm ngẫu nhiên, phá hủy bất cứ thứ gì ở trên nó. Bất kỳ người chơi nào ở cạnh zombie khi bắt đầu lượt chơi sẽ trở thành zombie.

Đối với mỗi người chơi sống, mã của họ sau đó sẽ được gọi. Nó sẽ nhận được một đối tượng PlayerContext , chứa thông tin về trạng thái hiện tại của họ và môi trường xung quanh. Mỗi người chơi có thể nhìn thấy 8 ô vuông theo bất kỳ hướng nào.

Người chơi phải chọn di chuyển (đứng yên là một chuyển động hợp lệ), bằng cách trả lại một Movehoặc bắn một người hoặc zombie gần đó, bằng cách trả lại a Shoot. Súng của bạn có tầm bắn tối đa là 5 ô vuông. Vì bạn ở trong tầm bắn của súng nên bạn có thể tự bắn, miễn là bạn còn đạn. Nếu hai người chơi bắn nhau, cả hai đều chết.

Nếu hai người chơi cố gắng di chuyển vào cùng một hình vuông, họ sẽ thất bại và cả hai sẽ quay lại quảng trường mà họ bắt đầu. Nếu vẫn còn xung đột, điều này sẽ được lặp lại cho đến khi không có xung đột, điều đó có thể có nghĩa là mọi người đã trở lại nơi họ bắt đầu.

Nếu một người chơi chết vì một phát súng, xác chết của họ sẽ vẫn còn và tạo thành một hàng rào vĩnh viễn. Bất kỳ viên đạn nào họ đang mang vẫn còn trên người, và có thể được người chơi nhặt sạch trong các ô vuông liền kề. Nếu có nhiều người chơi chiếm các ô vuông cạnh xác chết, thì những viên đạn sẽ được chia sẻ giữa họ, nhưng phần còn lại sẽ bị mất.

Nếu một người chơi trở thành zombie, thì đạn của họ sẽ bị mất. Zombie sẽ vô thức bước về phía người chơi sống gần nhất.

Bài dự thi được tính vào khoảng thời gian người chơi sống sót lâu nhất của họ tồn tại.

Mục

Một chương trình kiểm soát có sẵn tại https://github.com/jamespic/zombie . Đơn giản chỉ cần sao chép nó, và chạy mvn compile exec:java.

Để đủ điều kiện, các mục nhập phải được viết bằng ngôn ngữ JVM, phải có thể mang theo được và phải có thể xây dựng từ Maven mà không cần thiết lập đặc biệt. Điều này là để đảm bảo rằng các đối thủ cạnh tranh không cần phải cài đặt nhiều môi trường thời gian chạy để kiểm tra bot của họ trước các đối thủ cạnh tranh.

Các mục mẫu hiện có sẵn bằng các ngôn ngữ sau:

Nếu bạn muốn cạnh tranh bằng một ngôn ngữ không được liệt kê, bạn có thể đăng bình luận yêu cầu và tôi sẽ điều tra khả năng tích hợp ngôn ngữ bạn đã chọn vào chương trình kiểm soát. Hoặc, nếu bạn không kiên nhẫn, bạn có thể gửi yêu cầu kéo đến chương trình điều khiển.

Chỉ một trường hợp (theo nghĩa Java của từ) sẽ được tạo cho mỗi mục. Ví dụ Java này sẽ được gọi nhiều lần trong mỗi lượt - một lần cho mỗi người chơi còn sống.

API

package zombie

// You implement this. Your entry should be in package `player`
interface Player {
    Action doTurn(PlayerContext context)
}

// These already exist
class PlayerContext {
    // A square array, showing the area around you, with you at the centre
    // playFields is indexed by x from West to East, then y from North to South
    PlayerId[][] getPlayField()
    int getBullets() // Current bullets available
    int getGameClock() // Current turn number
    PlayerId getId() // Id of the current player instance
    int getX() // Your current x co-ordinate
    int getY() // Your current y co-ordinate
    int getBoardSize() // The size of the current playing field
    Set<PlayerId> shootablePlayers() // A helper function that identifies players in range.
}

class PlayerId {
    String getName() // The name of the entrant that owns this player
    int getNumber() // A unique number, assigned to this player
}

// Don't implement this. Use either `Move` or `Shoot`
interface Action {}

enum Move implements Action {
    NORTHWEST, NORTH, NORTHEAST,
    EAST, STAY, WEST,
    SOUTHEAST, SOUTH, SOUTHWEST;
    static move randomMove();
}

class Shoot implements Action {
    Shoot(PlayerId target);
}

Quy tắc bổ sung

Mỗi mục phải có một tên duy nhất, để hoạt động chính xác với chương trình điều khiển.

Các mục nhập không nên cố gắng can thiệp vào những người tham gia khác, hoặc với chương trình kiểm soát, hoặc bằng cách khác tận dụng môi trường thời gian chạy để "phá vỡ bức tường thứ tư", và có được một lợi thế không có trong ngày tận thế zombie "thực sự" .

Giao tiếp giữa những người chơi được cho phép.

Người chiến thắng là người đăng ký có bot có số điểm cao nhất trong bài kiểm tra mà tôi sẽ chạy vào ngày 3 tháng 8 năm 2014.

Kết quả cuối cùng

Kết quả cuối cùng là trong! Hèn nhát là người chiến thắng!

Vào ngày 2 tháng 8, tôi đã chạy 19 vòng của chương trình điều khiển và xếp hạng từng người chơi theo điểm trung bình của họ. Kết quả như sau:

Coward: 4298
Fox: 3214
Shotguneer: 2471
Cocoon: 1834
JohnNash: 1240
HuddleWolf: 1112
Sokie: 1090
SOS: 859
GordonFreeman: 657
Jack: 657
Waller: 366
SuperCoward: 269
MoveRandomly: 259
StandStill: 230
Vortigaunt: 226
ThePriest: 223
Bee: 61
HideyTwitchy: 52
ZombieHater: 31
Gunner: 20
ZombieRightsActivist: 16
SunTzu: 11
EmoWolfWithAGun: 0

Vòng cuối cùng có sẵn để xem ở đây .

Kết quả chạy

Kết quả cá nhân của mỗi trong số 19 lần chạy là:

#Run at 03-Aug-2014 14:45:35#
Bee: 21
Cocoon: 899
Coward: 4608
EmoWolfWithAGun: 0
Fox: 3993
GordonFreeman: 582
Gunner: 18
HideyTwitchy: 37
HuddleWolf: 2836
Jack: 839
JohnNash: 956
MoveRandomly: 310
SOS: 842
Shotguneer: 2943
Sokie: 937
StandStill: 250
SunTzu: 3
SuperCoward: 318
ThePriest: 224
Vortigaunt: 226
Waller: 258
ZombieHater: 41
ZombieRightsActivist: 10

#Run at 03-Aug-2014 14:56:48#
Bee: 97
Cocoon: 3073
Coward: 5699
EmoWolfWithAGun: 0
Fox: 4305
GordonFreeman: 1252
Gunner: 24
HideyTwitchy: 25
HuddleWolf: 3192
Jack: 83
JohnNash: 1195
MoveRandomly: 219
SOS: 884
Shotguneer: 3751
Sokie: 1234
StandStill: 194
SunTzu: 69
SuperCoward: 277
ThePriest: 884
Vortigaunt: 564
Waller: 1281
ZombieHater: 10
ZombieRightsActivist: 2

#Run at 03-Aug-2014 15:01:37#
Bee: 39
Cocoon: 2512
Coward: 2526
EmoWolfWithAGun: 0
Fox: 2687
GordonFreeman: 852
Gunner: 21
HideyTwitchy: 91
HuddleWolf: 1112
Jack: 1657
JohnNash: 944
MoveRandomly: 312
SOS: 660
Shotguneer: 1067
Sokie: 1356
StandStill: 169
SunTzu: 8
SuperCoward: 351
ThePriest: 223
Vortigaunt: 341
Waller: 166
ZombieHater: 25
ZombieRightsActivist: 47

#Run at 03-Aug-2014 15:08:27#
Bee: 27
Cocoon: 2026
Coward: 3278
EmoWolfWithAGun: 0
Fox: 2677
GordonFreeman: 611
Gunner: 16
HideyTwitchy: 11
HuddleWolf: 1694
Jack: 600
JohnNash: 1194
MoveRandomly: 48
SOS: 751
Shotguneer: 5907
Sokie: 1233
StandStill: 62
SunTzu: 9
SuperCoward: 252
ThePriest: 173
Vortigaunt: 107
Waller: 276
ZombieHater: 53
ZombieRightsActivist: 38

#Run at 03-Aug-2014 15:14:01#
Bee: 26
Cocoon: 1371
Coward: 5121
EmoWolfWithAGun: 0
Fox: 3878
GordonFreeman: 464
Gunner: 29
HideyTwitchy: 130
HuddleWolf: 955
Jack: 101
JohnNash: 698
MoveRandomly: 269
SOS: 1314
Shotguneer: 2444
Sokie: 3217
StandStill: 233
SunTzu: 10
SuperCoward: 269
ThePriest: 318
Vortigaunt: 266
Waller: 494
ZombieHater: 49
ZombieRightsActivist: 9

#Run at 03-Aug-2014 15:19:43#
Bee: 25
Cocoon: 2098
Coward: 4855
EmoWolfWithAGun: 0
Fox: 4081
GordonFreeman: 227
Gunner: 43
HideyTwitchy: 28
HuddleWolf: 2149
Jack: 1887
JohnNash: 1457
MoveRandomly: 117
SOS: 1068
Shotguneer: 4272
Sokie: 636
StandStill: 53
SunTzu: 9
SuperCoward: 209
ThePriest: 220
Vortigaunt: 227
Waller: 366
ZombieHater: 19
ZombieRightsActivist: 49

#Run at 03-Aug-2014 15:24:03#
Bee: 46
Cocoon: 682
Coward: 3588
EmoWolfWithAGun: 0
Fox: 4169
GordonFreeman: 764
Gunner: 13
HideyTwitchy: 21
HuddleWolf: 842
Jack: 1720
JohnNash: 1260
MoveRandomly: 259
SOS: 636
Shotguneer: 777
Sokie: 586
StandStill: 75
SunTzu: 6
SuperCoward: 390
ThePriest: 189
Vortigaunt: 208
Waller: 334
ZombieHater: 61
ZombieRightsActivist: 20

#Run at 03-Aug-2014 15:29:49#
Bee: 90
Cocoon: 516
Coward: 4298
EmoWolfWithAGun: 0
Fox: 1076
GordonFreeman: 581
Gunner: 8
HideyTwitchy: 87
HuddleWolf: 4298
Jack: 4715
JohnNash: 727
MoveRandomly: 102
SOS: 859
Shotguneer: 2471
Sokie: 2471
StandStill: 427
SunTzu: 24
SuperCoward: 159
ThePriest: 359
Vortigaunt: 94
Waller: 398
ZombieHater: 54
ZombieRightsActivist: 21

#Run at 03-Aug-2014 15:36:50#
Bee: 18
Cocoon: 3127
Coward: 3124
EmoWolfWithAGun: 0
Fox: 5094
GordonFreeman: 255
Gunner: 43
HideyTwitchy: 17
HuddleWolf: 1078
Jack: 272
JohnNash: 1270
MoveRandomly: 55
SOS: 723
Shotguneer: 3126
Sokie: 1388
StandStill: 179
SunTzu: 7
SuperCoward: 45
ThePriest: 519
Vortigaunt: 172
Waller: 200
ZombieHater: 45
ZombieRightsActivist: 8

#Run at 03-Aug-2014 15:40:59#
Bee: 78
Cocoon: 1834
Coward: 4521
EmoWolfWithAGun: 0
Fox: 1852
GordonFreeman: 657
Gunner: 7
HideyTwitchy: 2
HuddleWolf: 969
Jack: 895
JohnNash: 1596
MoveRandomly: 277
SOS: 694
Shotguneer: 1397
Sokie: 844
StandStill: 325
SunTzu: 7
SuperCoward: 192
ThePriest: 148
Vortigaunt: 369
Waller: 232
ZombieHater: 16
ZombieRightsActivist: 17

#Run at 03-Aug-2014 15:44:22#
Bee: 23
Cocoon: 2638
Coward: 2269
EmoWolfWithAGun: 0
Fox: 2067
GordonFreeman: 730
Gunner: 21
HideyTwitchy: 60
HuddleWolf: 763
Jack: 1469
JohnNash: 1494
MoveRandomly: 273
SOS: 3181
Shotguneer: 3181
Sokie: 653
StandStill: 450
SunTzu: 19
SuperCoward: 272
ThePriest: 215
Vortigaunt: 299
Waller: 510
ZombieHater: 62
ZombieRightsActivist: 16

#Run at 03-Aug-2014 15:48:03#
Bee: 97
Cocoon: 2009
Coward: 2798
EmoWolfWithAGun: 0
Fox: 1907
GordonFreeman: 958
Gunner: 22
HideyTwitchy: 93
HuddleWolf: 925
Jack: 288
JohnNash: 476
MoveRandomly: 422
SOS: 3723
Shotguneer: 2076
Sokie: 1090
StandStill: 134
SunTzu: 92
SuperCoward: 141
ThePriest: 470
Vortigaunt: 216
Waller: 340
ZombieHater: 32
ZombieRightsActivist: 20

#Run at 03-Aug-2014 16:03:38#
Bee: 121
Cocoon: 501
Coward: 9704
EmoWolfWithAGun: 0
Fox: 3592
GordonFreeman: 588
Gunner: 20
HideyTwitchy: 54
HuddleWolf: 749
Jack: 1245
JohnNash: 1345
MoveRandomly: 451
SOS: 835
Shotguneer: 1548
Sokie: 589
StandStill: 166
SunTzu: 11
SuperCoward: 158
ThePriest: 93
Vortigaunt: 246
Waller: 1350
ZombieHater: 18
ZombieRightsActivist: 11

#Run at 03-Aug-2014 16:10:24#
Bee: 66
Cocoon: 1809
Coward: 3295
EmoWolfWithAGun: 0
Fox: 3214
GordonFreeman: 1182
Gunner: 15
HideyTwitchy: 52
HuddleWolf: 1514
Jack: 101
JohnNash: 745
MoveRandomly: 211
SOS: 862
Shotguneer: 6335
Sokie: 1504
StandStill: 384
SunTzu: 14
SuperCoward: 259
ThePriest: 244
Vortigaunt: 262
Waller: 1356
ZombieHater: 24
ZombieRightsActivist: 20

#Run at 03-Aug-2014 16:28:05#
Bee: 61
Cocoon: 692
Coward: 11141
EmoWolfWithAGun: 0
Fox: 1955
GordonFreeman: 1234
Gunner: 42
HideyTwitchy: 24
HuddleWolf: 1862
Jack: 609
JohnNash: 1579
MoveRandomly: 167
SOS: 958
Shotguneer: 11141
Sokie: 284
StandStill: 422
SunTzu: 66
SuperCoward: 121
ThePriest: 207
Vortigaunt: 128
Waller: 259
ZombieHater: 22
ZombieRightsActivist: 7

#Run at 03-Aug-2014 16:32:10#
Bee: 207
Cocoon: 4414
Coward: 2670
EmoWolfWithAGun: 0
Fox: 978
GordonFreeman: 620
Gunner: 19
HideyTwitchy: 135
HuddleWolf: 962
Jack: 657
JohnNash: 1200
MoveRandomly: 147
SOS: 687
Shotguneer: 2258
Sokie: 2433
StandStill: 249
SunTzu: 49
SuperCoward: 1056
ThePriest: 602
Vortigaunt: 326
Waller: 593
ZombieHater: 31
ZombieRightsActivist: 10

#Run at 03-Aug-2014 16:38:56#
Bee: 265
Cocoon: 2231
Coward: 4228
EmoWolfWithAGun: 0
Fox: 4737
GordonFreeman: 532
Gunner: 9
HideyTwitchy: 75
HuddleWolf: 2375
Jack: 1237
JohnNash: 1249
MoveRandomly: 109
SOS: 860
Shotguneer: 6470
Sokie: 1096
StandStill: 126
SunTzu: 15
SuperCoward: 393
ThePriest: 133
Vortigaunt: 184
Waller: 257
ZombieHater: 32
ZombieRightsActivist: 12

#Run at 03-Aug-2014 16:52:16#
Bee: 67
Cocoon: 1534
Coward: 9324
EmoWolfWithAGun: 0
Fox: 2458
GordonFreeman: 1019
Gunner: 24
HideyTwitchy: 72
HuddleWolf: 601
Jack: 399
JohnNash: 1366
MoveRandomly: 275
SOS: 506
Shotguneer: 1007
Sokie: 475
StandStill: 230
SunTzu: 135
SuperCoward: 361
ThePriest: 61
Vortigaunt: 112
Waller: 4106
ZombieHater: 12
ZombieRightsActivist: 22

#Run at 03-Aug-2014 17:03:04#
Bee: 26
Cocoon: 1159
Coward: 7796
EmoWolfWithAGun: 0
Fox: 3948
GordonFreeman: 878
Gunner: 3
HideyTwitchy: 17
HuddleWolf: 1490
Jack: 513
JohnNash: 1240
MoveRandomly: 487
SOS: 1460
Shotguneer: 1481
Sokie: 832
StandStill: 457
SunTzu: 8
SuperCoward: 480
ThePriest: 527
Vortigaunt: 171
Waller: 3729
ZombieHater: 30
ZombieRightsActivist: 10

1
@Pureferret Mã giải phóng bao gồm tệp Frege chứa các ràng buộc tại github.com/jamespic/zombie/blob/master/src/main/frege-bindings/ trộm và một lớp trình trợ giúp Java gọi vào Frege tại github.com/jamespic / zombie / blob / master / src / main / java / zombie / . Nếu bạn có thể sao chép repo (hoặc tải xuống dưới dạng zip từ github.com/jamespic/zombie/archive/master.zip ) thì Maven sẽ xử lý bản dựng cho bạn.
James_pic

1
@Pureferret Cố gắng thiết lập dự án bằng tay sẽ rất đau đớn . Chưa có ai thực sự sử dụng chúng, nhưng có trình biên dịch và phiên dịch cho nửa tá ngôn ngữ. Sự phản chiếu được cho phép (thực sự, một số ngôn ngữ động không thể hoạt động mà không có nó), miễn là nó không được sử dụng để làm xáo trộn trò chơi hoặc đối thủ của bạn. Nhìn vào theo dõi loot của Coward để biết ví dụ về "giao tiếp".
James_pic

1
@sokie Nghe có vẻ ổn - một số mục đã làm một cái gì đó như thế này và tôi đã hình dung ra khi tôi đặt ra thách thức rằng một số người tham gia sẽ muốn bot của họ gặp nhau ở đâu đó hoặc trao đổi thông tin về môi trường xung quanh. Chúng tôi sẽ nói rằng các cầu thủ đã có bộ đàm.
James_pic

2
@James_pic Tôi đã thêm mã này vào bản sao cục bộ của mình ( pastebin.com/PutPn9ff ) trong Game.java để tôi có thể sử dụng các phím mũi tên để tiến và lùi trong trò chơi. Nghĩ rằng nó có thể hữu ích cho bạn để thêm
Moop

2
Thất vọng nhẹ mà người chiến thắng cho phép bản thân chịu đựng sự hình thành nhất định thay vì tự sát.
Sparr

Câu trả lời:


15

nhát gan

Những quy tắc hèn nhát.

  1. Nếu bạn không thể chạy trốn, hoảng loạn và bắn mọi thứ bạn không biết.
  2. Chạy!!!
  3. Khi chạy, bạn có thể nhặt một số viên đạn. Sâu bên dưới bạn biết bạn không thể chạy mãi mãi.
  4. Khi chạy, tìm kiếm những kẻ hèn nhát khác. Khốn khổ yêu công ty. Và họ có thể ăn anh chàng kia trước.
package player;

import java.lang.Math.*;
import java.util.Set;
import java.util.HashSet;
import zombie.*;
import static zombie.Constants.*;

public class Coward implements Player {

    private static final Set<PlayerId> killed = new HashSet<>();
    private static final Set<PlayerId> looted = new HashSet<>();

    @Override
    public Action doTurn(PlayerContext context) {

        PlayerId[][] field = context.getPlayField();

        // Panic and shoot
        if (context.getBullets() > 0) {
            int distEnemy = VISION_WIDTH;
            int distZombie = VISION_WIDTH;
            PlayerId targetEnemy = null;
            PlayerId targetZombie = null;
            for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION + SHOOT_RANGE; x++) {
                for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION + SHOOT_RANGE; y++) {
                    PlayerId player = field[x][y];
                    if (player != null && !killed.contains(player)) {
                        int dist = getDistance(x, y);
                        if (player.getName().equals("Zombie")) {
                            if( dist < distZombie ) {
                                distZombie = dist;
                                targetZombie = player;
                            }
                        } else if (isEnemy(player.getName()) && dist <= distEnemy ) {
                            distEnemy = dist;
                            targetEnemy = field[x][y];
                        }
                    }
                }
            }

            if (targetZombie != null && distZombie <= 3) {
                killed.add(targetZombie);
                return new Shoot( targetZombie );
            } else if (targetEnemy != null && distEnemy <= 5 ) {
                killed.add(targetEnemy);
                return new Shoot( targetEnemy );
            }
        }

        // Looted?
        for( int xx = CENTRE_OF_VISION-VISION_RANGE+1; xx <= CENTRE_OF_VISION+VISION_RANGE-1; xx++ ) {
            for( int yy = CENTRE_OF_VISION-VISION_RANGE+1; yy <= CENTRE_OF_VISION+VISION_RANGE-1; yy++ ) {
                PlayerId player = field[xx][yy];
                if( player != null && !player.getName().equals("Zombie") && !player.getName().equals("DeadBody")) {
                    for( int x = -1; x <= 1; x++ ) {
                        for( int y = -1; y <= 1; y++ ) {
                            PlayerId loot = field[xx+x][yy+y];
                            if( loot != null && !looted.contains(loot) && loot.getName().equals("DeadBody")) {
                                looted.add(loot);
                            }
                        }
                    }
                }
            }
        }

        // Run away
        int bestScore = -10000000;
        Move bestMove = Move.randomMove();

        for( int x = -1; x <= 1; x++ ) {
            for( int y = -1; y <= 1; y++ ) {
                PlayerId center = field[CENTRE_OF_VISION+x][CENTRE_OF_VISION+y];
                if( center == null ) {
                    int thisScore = 0;
                    for( int xx = CENTRE_OF_VISION+x-VISION_RANGE+1; xx < CENTRE_OF_VISION+x+VISION_RANGE; xx++ ) {
                        for( int yy = CENTRE_OF_VISION+y-VISION_RANGE+1; yy < CENTRE_OF_VISION+y+VISION_RANGE; yy++ ) {
                            PlayerId player = field[xx][yy];
                            if( player != null) {
                                int dist = getDistance(xx-x,yy-y);

                                if( player.getName().equals("Coward")) { // Prefer lose groups
                                    thisScore += (int)Math.pow( 2, ( 6 - Math.abs( dist - 5 )));
//                                    if( dist >= 3 && dist <= 6 ) {
//                                        thisScore += 32;
//                                    } else if( dist > 3 ) {
//                                        thisScore += 16;
//                                    }
                                } else if( player.getName().equals("DeadBody")) { // Visit dead bodies on the route
                                    if( !looted.contains(player)) {
                                        thisScore += (32+VISION_RANGE-dist)*(VISION_RANGE-dist);
                                    }
                                } else if( player.getName().equals("Zombie")) { // Avoid zombies
                                    if( dist <= 5 ) {
                                        thisScore -= (int)Math.pow( 10, ( 6 - dist ));
                                    }
//                                    if( dist <= 2 ) {
//                                        thisScore -= 10000;
//                                    } else if( dist <= 3 ) {
//                                        thisScore -= 1000;
//                                    } else if( dist <= 4 ) {
//                                        thisScore -= 100;
//                                    }
                                } else if( isEnemy(player.getName())) { // Avoid strangers
                                    thisScore -= (int)Math.pow( 10, ( 9 - dist ));
//                                    if( dist == 7 ) {
//                                        thisScore -= 100;
//                                    } else if( dist <= 6 ) {
//                                        thisScore -= 1000;
//                                    }
                                }
                            }
                        }
                    }
                    if( thisScore > bestScore ) {
                        bestScore = thisScore;
                        bestMove = Move.inDirection( x, y );
                    }
                }
            }
        }

        return bestMove;
    }

    private boolean isEnemy(String name) {
        switch (name) {
            case "Coward":
            case "DeadBody":
            case "GordonFreeman":
            case "EmoWolfWithAGun":
            case "HuddleWolf":
            case "ThePriest":
            case "Shotguneer":
            case "Vortigaunt":
            case "Fox":
            case "Cocoon":
            case "SuperCoward":
            case "SOS":
            case "JohnNash":
            case "MoveRandomly":
                return false;
            default:
                return true;
        }
    }

    private int getDistance(int x, int y) {
        return Math.max(Math.abs(CENTRE_OF_VISION - x), Math.abs(CENTRE_OF_VISION - y));
    }
}

Tôi rất phấn khích để thử điều này. Tất cả các mục cho đến nay đã tập trung vào chiến đấu, nhưng không ai cố gắng chạy hoặc trốn.
James_pic

Ồ, và bạn không cần phải theo dõi những gì bạn đã giết. Nó sẽ hiển thị dưới dạng DeadBodyvới một id khác, thay vì bất cứ thứ gì trước đây.
James_pic

1
Nó không phải để theo dõi, nó không bắn cùng một thứ hai lần trong cùng một vòng.
Thaylon

1
Thực hiện một số thay đổi, chạy tốt nhất với trận đấu lịch sử là vào lúc 2681. dl.dropboxusercontent.com/u/13918324/2681.html
Thaylon

1
@Thaylon Định dạng mã nguồn mới nhất cho bạn. pastebin.com/4WDb6s8C
HuddleWolf

44

Emo Sói Với Súng

Anh ấy đã trở lại . Anh ghét zombie. Anh vẫn ghét Java. Không có ý xâm phạm bản quyền.

package player;

import zombie.*;

public class EmoWolfWithAGun implements Player {

    @Override
    public Action doTurn(PlayerContext context) {
        PlayerId myself = context.getId();
        return new Shoot(myself);
    }

}

3
+1 Tạo thêm nhiều bức tường cho Wallers ...
Moop

13

Nhà hoạt động vì quyền Zombie

Phong trào Quyền Zombie nhanh chóng trở nên phổ biến ở phần bù của ngày tận thế. Ý tưởng giết chết mọi thây ma trong tầm mắt mà không hối hận là hoàn toàn tàn nhẫn đối với chúng, vì vậy chúng bắn vào những người chơi khác không tin vào nguyên nhân. Hiểu được cuộc đấu tranh, họ sẽ ôm zombie nếu không có kẻ thù trong tầm mắt.

package player;
import zombie.*;
import static zombie.Constants.*;
import static java.lang.Math.*;

public class ZombieRightsActivist implements Player {

@Override
public Action doTurn(PlayerContext context) {
    if (context.getBullets() > 0) {
        for (PlayerId player: context.shootablePlayers()) {
            switch(player.getName()) {
                case "ZombieRightsActivist":
                case "DeadBody":
                case "Zombie":   
                    break;
                default:
                    return new Shoot(player);//Kill the non-believers
            }
        }
    }
    double farthest=0;
    Move move=Move.randomMove();
    for (int x = 0; x < VISION_WIDTH; x++) {//Find a lonely zombie and give it a hug
        for (int y = 0; y < VISION_WIDTH; y++) {
            PlayerId friend = context.getPlayField()[x][y];
            if (friend!= null && (friend.getName().equals("Zombie"))) {
                double distance=sqrt(pow(x-context.getX(),2)+pow(y-context.getY(),2));
                if (distance>farthest){
                    farthest = distance;
                    move = Move.inDirection(x - CENTRE_OF_VISION, y -CENTRE_OF_VISION);
                }
            }
        }
    }
    return move;
}

}

12

HuddleWolf - Java

Quy tắc 8 : Du lịch theo nhóm

HuddleWolf thực hiện quy tắc thứ sáu của Zombieland. Nó sẽ đuổi theo và rúc vào bất kỳ vật thể không thù địch nào mà nó nhìn thấy. Nếu HuddleWolf thấy không có ai để chen lấn, anh ta sẽ mạo hiểm đi về hướng đông bắc để tìm kiếm các khu vực đông dân hơn. HuddleWolf cũng ghét Zombie và sẽ bắn vào tầm nhìn.

HuddleWolf đã nhận ra Coward là một thực hiện tốt hơn nhiều ý tưởng ban đầu của mình. Anh ta cúi đầu trước uy quyền của Coward và hiện đang tích cực ưu tiên công ty của Coward hơn những người không có đạo đức khác.

package player;

import zombie.*;
import static zombie.Constants.*;
import static java.lang.Math.*;

public class HuddleWolf implements Player {

    @Override
    public Action doTurn(PlayerContext context) {
        if (context.getBullets() > 0) {
            for (PlayerId player: context.shootablePlayers()) {
                if (isEnemy(player.getName())) {
                    return new Shoot(player);
                }
            }
        }
        Move bestDirection = Move.NORTHEAST;
        int bestDistance = Integer.MAX_VALUE;
        bool foundACoward = false;
        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {
                int distance = max(abs(x - CENTRE_OF_VISION), abs(y - CENTRE_OF_VISION));
                PlayerId playerAtLocation = context.getPlayField()[x][y];
                if (playerAtLocation != null
                        && !(isEnemy(playerAtLocation.getName()))
                        && !(playerAtLocation.equals(context.getId()))
                        && distance < bestDistance
                        && (!foundACoward || playerAtLocation.getName().equals("Coward"))) {
                    if (playerAtLocation.getName().equals("Coward"))
                    {
                        foundACoward = true;
                    }
                    bestDistance = distance;
                    bestDirection = Move.inDirection(x - CENTRE_OF_VISION, y -CENTRE_OF_VISION);
                }
            }
        }
        return bestDirection;
    }

    private boolean isEnemy(String name) {
        switch(name) {
            case "ZombieRightsActivist":
            case "ZombieHater":
            case "HideyTwitchy" :
            case "Gunner":
            case "Zombie" :
                return true;
            default:
                return false;
        }
    }
}

HuddleWolf: Bây giờ giết chết Pháo thủ
HuddleWolf

Bạn cũng có thể muốn thêm && !(playerAtLocation.equals(context.getId()))vào điều kiện lộn xộn của bạn. Ngay bây giờ, nó di chuyển về phía người chơi gần nhất - ngoại trừ người chơi gần nhất là bạn, vì vậy nó vẫn đứng yên.
James_pic

Ý bạn là Quy tắc 8 ....?
Pureferret

@Pureferret: Bạn nói đúng. Cảm hứng ban đầu của tôi không phải là pháo Zombieland.
HuddleWolf

FYI nhìn vào ZombieHater. Tôi không nghĩ anh ấy thực sự ghét zombie. Anh ta chỉ bắn tất cả chúng tôi như xạ thủ. Bạn có lẽ nên thêm anh ta vào danh sách các mục tiêu bắt buộc.
kaine

11

cáo

Cáo cần một cái hố.

Sử dụng một phần tốt của Coward của tôi nhưng theo một chiến lược khác. Nếu bạn chọn chấp nhận nhiệm vụ (phụ), cáo sẽ chọn xây dựng một cái hố.

package player;

import java.lang.Math.*;
import java.util.Set;
import java.util.HashSet;
import zombie.*;
import static zombie.Constants.*;

public class Fox implements Player {

    private static int lastround = -1;
    private static final Set<PlayerId> killed = new HashSet<>();
    private static final Set<PlayerId> looted = new HashSet<>();

    @Override
    public Action doTurn(PlayerContext context) {

        PlayerId[][] field = context.getPlayField();

        // Cleanup
        if (context.getGameClock() > lastround) {
            lastround = context.getGameClock();
            killed.clear();
        }

        // Snipe
        if (context.getBullets() > 0) {
            int distEnemy = 1;
            PlayerId targetEnemy = null;
            for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION + SHOOT_RANGE; x++) {
                for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION + SHOOT_RANGE; y++) {
                    PlayerId player = field[x][y];
                    if (player != null && !killed.contains(player)) {
                        int dist = getDistance(x, y);
                        if (!player.getName().equals("Zombie") && isEnemy(player.getName()) && dist >= distEnemy ) {
                            distEnemy = dist;
                            targetEnemy = field[x][y];
                        }
                    }
                }
            }
            if (targetEnemy != null) {
                killed.add(targetEnemy);
                return new Shoot( targetEnemy );
            }
        }

        // Check Foxhole
        int foxhole = 0;
        PlayerId target = null;

        for( int x = -2; x <= 2; x++ ) {
            for( int y = -2; y <= 2; y++ ) {
                PlayerId player = field[CENTRE_OF_VISION+x][CENTRE_OF_VISION+y];
                if (player != null && getDistance(CENTRE_OF_VISION+x,CENTRE_OF_VISION+y) == 2) {
                    if (player.getName().equals("DeadBody") || player.getName().equals("Fox")) {
                        foxhole++;
                    }
                    if( player.getName().equals("Zombie")) {
                        target = player;
                    }
                }
            }
        }

        if (context.getBullets() + foxhole >= 16) {
            if (target!=null) {
                return new Shoot( target );
            } else {
                return Move.STAY;
            }
        }

        // Looted?
        for( int xx = CENTRE_OF_VISION-VISION_RANGE+1; xx <= CENTRE_OF_VISION+VISION_RANGE-1; xx++ ) {
            for( int yy = CENTRE_OF_VISION-VISION_RANGE+1; yy <= CENTRE_OF_VISION+VISION_RANGE-1; yy++ ) {
                PlayerId player = field[xx][yy];
                if( player != null && !player.getName().equals("Zombie") && !player.getName().equals("DeadBody")) {
                    for( int x = -1; x <= 1; x++ ) {
                        for( int y = -1; y <= 1; y++ ) {
                            PlayerId loot = field[xx+x][yy+y];
                            if( loot != null && !looted.contains(loot) && loot.getName().equals("DeadBody")) {
                                looted.add(loot);
                            }
                        }
                    }
                }
            }
        }

        // Collect bullets
        int bestScore = -10000000;
        Move bestMove = Move.randomMove();

        for( int x = -1; x <= 1; x++ ) {
            for( int y = -1; y <= 1; y++ ) {
                PlayerId center = field[CENTRE_OF_VISION+x][CENTRE_OF_VISION+y];
                if( center == null ) {
                    int thisScore = 0;
                    for( int xx = CENTRE_OF_VISION+x-VISION_RANGE+1; xx < CENTRE_OF_VISION+x+VISION_RANGE; xx++ ) {
                        for( int yy = CENTRE_OF_VISION+y-VISION_RANGE+1; yy < CENTRE_OF_VISION+y+VISION_RANGE; yy++ ) {
                            PlayerId player = field[xx][yy];
                            if( player != null) {
                                int dist = getDistance(xx-x,yy-y);

                                if( player.getName().equals("DeadBody")) {
                                    if( !looted.contains(player)) {
                                        thisScore += (32+VISION_RANGE-dist)*(VISION_RANGE-dist);
                                    }
                                } else if( player.getName().equals("Zombie")) {
                                    if( dist <= 5 ) {
                                        thisScore -= (int)Math.pow( 10, ( 6 - dist ));
                                    }
                                }
                            }
                        }
                    }
                    if( thisScore > bestScore ) {
                        bestScore = thisScore;
                        bestMove = Move.inDirection( x, y );
                    }
                }
            }
        }

        return bestMove;
    }

    private boolean isEnemy(String name) {
        switch (name) {
            case "Fox":
            case "Coward":
            case "DeadBody":
            case "GordonFreeman":
            case "EmoWolfWithAGun":
            case "HuddleWolf":
            case "ThePriest":
            case "Shotguneer":
            case "Vortigaunt":
            case "Cocoon":
            case "SuperCoward":
            case "SOS":
            case "JohnNash":
            case "MoveRandomly":
                return false;
            default:
                return true;
        }
    }

    private int getDistance(int x, int y) {
        return Math.max(Math.abs(CENTRE_OF_VISION - x), Math.abs(CENTRE_OF_VISION - y));
    }
}

Tôi thích nó. Tôi lo lắng tôi sẽ thiết lập một tiền lệ nguy hiểm bằng cách cho phép nhiều mục (một số mục tích cực hơn có thể có thể đạt được bằng cách thêm tay sai), nhưng mục này rõ ràng không giúp được Coward (nếu ai đó đã viết nó, họ có thể đã làm ít nhiều cùng một thứ), vì vậy tôi sẽ cho phép nó. Tôi sẽ có cơ hội để kiểm tra nó vào ngày mai.
James_pic

Đã thêm điểm tốt hơn (không còn đứng yên do quan hệ) và đánh dấu thêm DeadBodys bị cướp phá. Có thể muốn thử tính toán mối đe dọa tốt hơn nhưng quá trình thử nghiệm mất quá nhiều thời gian với sự hèn nhát thỉnh thoảng chạy đến 15000 vòng. Điều này có lẽ chủ yếu là do sân chơi lớn hơn và do đó giảm khả năng sinh ra bởi một thây ma. Chiến lược tốt nhất dường như là: đưa càng nhiều người chơi vào vòng 1000 càng tốt, ngừng di chuyển và sau đó để may mắn quyết định.
Thaylon

10

Waller - Java

Waller yêu những bức tường, và tìm kiếm chúng để trốn tránh zombie. Lý tưởng nhất là Waller rất thích được bọc trong một bức tường và chờ ngày tận thế ra ngoài.

Bức tường lý tưởng

Bức tường lý tưởng là nơi Waller được hoàn thành bao quanh bởi các bức tường:

   DDD 
   DWD 
   DDD

Vì cách duy nhất để chết là bị bắn hoặc zombie xuất hiện bên dưới hoặc bên cạnh bạn. Đó là tỷ lệ cược tốt nhất có thể để tránh chúng.

Bức tường lý tưởng khó có thể đến, nhưng Waller sẽ tìm vị trí tốt nhất có thể và chờ zombie hoặc những người chơi khác đến để bắn và mở rộng bức tường của anh ta.


Thuật toán tương đối đơn giản

  1. Có một zombie sắp cắn? bắn chúng.
  2. Tìm vị trí tường tốt nhất (điểm 0 - 8) trong trường nhìn
  3. Tìm con đường ngắn nhất đến vị trí đó và chạy đến đó!
  4. Hãy thử tăng tường
  5. Chờ đợi...

Đây là một công việc đang tiến triển, hãy thoải mái lấy bất cứ thứ gì tôi viết để sử dụng cho chính mình. Tôi đã viết một Thuật toán A * đơn giản để tìm đường dẫn tốt nhất đến một vị trí mong muốn có tính đến các bức tường xem xét và những người chơi khác. Nó được tính toán lại mỗi vòng vì các bức tường có thể đã thay đổi giữa chúng.


Thay đổi:

  • Đã cố gắng cải thiện hiệu suất trò chơi sớm bằng cách chờ đợi và tránh những người chơi hung hăng trong vài lượt đầu tiên trước khi tìm / xây tường.

  • Đã thêm trọng số cho việc tìm đường để có lộ trình tốt nhất về khoảng cách và điểm vị trí. Sẽ loot thường xuyên hơn bây giờ và hy vọng không hết đạn. Cải thiện trò chơi mở đầu bằng cách chạy trốn khỏi những người chơi hung hăng.

  • Đã sửa lỗi tìm đường kết thúc ở điểm bị chiếm

  • Làm sạch thêm mã. Đã thêm nhiều bức tường để ghi một vị trí hơn là chỉ các bức tường lân cận. Mở rộng bao xa Waller sẽ mở rộng bức tường của mình.

  • Làm sạch mã lên một chút. Đã triển khai đăng ký bắn để tránh hai Wallers bắn cùng một người chơi trong cùng một lượt (lấy cảm hứng từ Thaylon)

  • Đã thêm đường tìm giữa zombie gần nhất và Walelr hiện tại. Waller sẽ chỉ bắn một thây ma nếu nó có thể tiếp cận anh ta trong một số động tác nhất định. Điều này hy vọng sẽ cứu được một số viên đạn khi chúng là một bức tường chặn đường đi của zombie.


Các vấn đề

  • Waller có thể ở một vị trí tốt, nhưng nhìn thấy một vị trí tường tốt hơn. Họ sẽ vô thức chạy qua vùng đất bị nhiễm zombie để đến địa điểm mới đó. (Tôi cần ngăn cản điều này)

  • Đầu trò chơi là khó khăn cho Waller, không có pháo đài tốt nào ở gần và rất nhiều người chơi hung hăng. (Tôi cần cải thiện hiệu suất trò chơi sớm)

  • Không có giao tiếp giữa Wallers trong cùng một vị trí. Cần phải có họ làm việc cùng nhau để xây dựng bức tường tốt nhất có thể.


Đây là đoạn mã, tôi không phải là lập trình viên java (C #) nên hãy tha thứ cho lỗi java của tôi.

package player;

import java.lang.Math.*;
import java.util.Set;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;
import java.util.Collections;
import java.util.Comparator;
import zombie.*;
import static zombie.Constants.*;

public class Waller implements Player {

    private static final int MaximumDistanceToShootZombie = 2;
    private static final int PointsPerWall = 3;
    private static final int PointsPerLoot = 3;
    private static final int PointsPerZombie = -500;
    private static final int PointsPerAggressor = -500;  

    private static final Set<PlayerId> shooting = new HashSet<PlayerId>();
    private static final Set<PlayerId> dontLoot = new HashSet<PlayerId>();
    private static final Set<Point> zombieLocations = new HashSet<Point>();
    private Point CurrentLocation = new Point(CENTRE_OF_VISION, CENTRE_OF_VISION);

    private static int _lastGameTurn = -1;

    // DEBUG
    private static boolean _DEBUG = true;
    private static int agressiveKills;
    private static int zombieKills;
    private static int wallsBuilt;
    ////////

    private static class Point{
        public int X;
        public int Y;
        public PlayerId Player;
        public int Distance;

        public Point(int x, int y) {
            X = x;
            Y = y;
        }

        public Point(int x, int y, PlayerId player) {
            X = x;
            Y = y;
            Player = player;
        }

        public boolean SameLocation(Point otherPoint) {
            return X == otherPoint.X && Y == otherPoint.Y;
        }

        public List<Point> getAdjacentPoints(PlayerId[][] field, int distance, boolean includeSelf) {
            List<Point> points = new ArrayList<Point>();
            for(int x = X - distance; x <= X + distance; x++) {
                for(int y = Y - distance; y <= Y + distance; y++) { 
                    if(!includeSelf && x == X && y == Y)
                        continue;
                    Point pointToAdd = new Point(x, y);                 
                    if(pointToAdd.isValid()) {
                        pointToAdd.Player = field[x][y];
                        points.add(pointToAdd);
                    }
                }
            }                   
            return points;
        }

        public int GetDistance(Point point) {
            return Math.max(Math.abs(X - point.X), Math.abs(Y - point.Y));
        }

        private boolean isValid() { 
            return X >= 0 && X < VISION_WIDTH && Y >= 0 && Y < VISION_WIDTH;
        }

        @Override
        public int hashCode() {
            return (X*100) + Y;  
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Point))
                return false;
            if (obj == this)
                return true;

            return SameLocation((Point) obj);       
        }

        @Override
        public String toString(){
            return "("+X+","+Y+")";
        }           
    }

    @Override
    public Action doTurn(PlayerContext context) {   
        int gameTurn = context.getGameClock();  

        if(gameTurn != _lastGameTurn){
            _lastGameTurn = gameTurn;               
        }

        PlayerId[][] field = context.getPlayField();         
        int bullets = context.getBullets();

        // Mark all adjacent dead players as already been looted
        for(Point point : getSurrounding(field, CENTRE_OF_VISION, CENTRE_OF_VISION, 1)){
            if(point.Player.getName().equals("DeadBody")) 
                dontLoot.add(point.Player);  
        }

        int x = context.getX();
        int y = context.getY();
        int boardSize = context.getBoardSize();
        List<Point> newZombies = new ArrayList<Point>();
        for(Point point : getSurrounding(field, CENTRE_OF_VISION, CENTRE_OF_VISION, VISION_RANGE)){     
            Point absolutePoint = GetNewTorusPoint(x + point.X - CENTRE_OF_VISION , y + point.Y - CENTRE_OF_VISION, boardSize);         
            if(point.Player.getName().equals("DeadBody") && zombieLocations.contains(absolutePoint)) 
                dontLoot.add(point.Player);  // new zombie kill
            if(isZombie(point.Player))
                newZombies.add(absolutePoint);
        }
        zombieLocations.clear();
        zombieLocations.addAll(newZombies);

        Action action;  

        // 1) Handle immediate threats to life, have to be dealt before anything else
        action = AssessThreats(field, bullets);
        if(action != null) return action;

        //2) Early turn avoidance
        if(gameTurn < 5) {
            action = EarlyTurn(field, bullets, context);
            if(action != null) return action;
        }

        int currentWallCount = countNumberOfSurroundingWalls(field, CENTRE_OF_VISION, CENTRE_OF_VISION);

        switch(currentWallCount) {  
            case 8:     
                action = ShootAgressivePlayers(field, bullets);
                if(action != null) return action; 
                return Move.STAY; // no more moving                 
            case 7:     
                action = ExpandWall(field, bullets, 1);
                if(action != null) return action;
                action = ShootAgressivePlayers(field, bullets);
                if(action != null) return action;                   
            case 6: 
            case 5:              
            case 4: 
                // action = ExpandWall(field, bullets, 2);
                // if(action != null) return action; 
                // break;
            case 2: 
            case 1: 
            default:                                    
                break;
        }                       

        // 2) Score each possible square and find the best possible location(s)
        Set<Point> optimalLocations = scoreSquares(field);  

        action = findShortestPath(field, CurrentLocation, optimalLocations);
        if(action != null) return action;

        action = ShootAgressivePlayers(field, bullets);
        if(action != null) return action;   

        action = ExpandWall(field, bullets, 1);
        if(action != null) return action;    

        // Stay still if nothing better to do
        return Move.STAY;
    }

    private Action EarlyTurn(PlayerId[][] field, int bullets, PlayerContext context) {
        Point bestPoint = CurrentLocation;
        double bestScore = 1000000;

        for(Point futurePoint : CurrentLocation.getAdjacentPoints(field, 1, true)) {            
            double score = 0;
            for(Point adjacentPoint : futurePoint.getAdjacentPoints(field, VISION_RANGE, false)) {
                if(isAgressive(adjacentPoint.Player)){
                    int dist = futurePoint.GetDistance(adjacentPoint);          
                    if(dist > 6){
                        score += 1;             
                    } else {
                        score += 10000;
                    }
                } else if(isZombie(adjacentPoint.Player)) {
                    int dist = futurePoint.GetDistance(adjacentPoint);      
                    if (dist <= 3)
                        score += 10000;
                } else if(isWall(adjacentPoint.Player)) {
                    score -= 2;
                }
            }   
            if(score < bestScore) {
                bestScore = score;
                bestPoint = futurePoint;
            }
        }                           

        //if(_DEBUG) System.out.println("["+_lastGameTurn+"] Best Score: "+bestScore +" point: "+context.getX()+","+context.getY());

        if(bestPoint == CurrentLocation) {
            Action action = ShootAgressivePlayers(field, bullets);
            if(action != null) return action;   
            return Move.STAY;
        }

        if(bestScore >= 1000) {
            Action action = ShootAgressivePlayers(field, bullets);
            if(action != null) return action;   
        }

        return Move.inDirection(bestPoint.X - CurrentLocation.X, bestPoint.Y - CurrentLocation.Y);      
    }

    private Action ShootAgressivePlayers(PlayerId[][] field, int bullets) {
        if(bullets > 0) {       
            for(Point point : getSurrounding(field, CENTRE_OF_VISION, CENTRE_OF_VISION, SHOOT_RANGE)) {
                PlayerId player = point.Player;
                if(isAgressive(player) && shouldShoot(player)) {
                    if(_DEBUG) System.out.println("["+_lastGameTurn+"] Killing Aggressive: "+(++agressiveKills));       
                    return new Shoot(player);
                }           
            }   
        }
        return null;
    }

    private Action ExpandWall(PlayerId[][] field, int bullets, int distance) {
        if(bullets > 0) {
            for(Point point : getSurrounding(field, CENTRE_OF_VISION, CENTRE_OF_VISION, distance)) {
                PlayerId player = point.Player;
                if(!isWall(player) && isEnemy(player) && !isZombie(player) && shouldShoot(player)) {
                    if(_DEBUG) System.out.println("["+_lastGameTurn+"] Expanding Wall: "+(++wallsBuilt)+" Dist: "+CurrentLocation.GetDistance(point));          
                    return new Shoot(player);
                }           
            }
        }
        return null;
    }

    private boolean shouldShoot(PlayerId player) {
        boolean result = shooting.add(player);
        if(result && isZombie(player)){
            dontLoot.add(player);           
        }       
        return result;      
    }

    private boolean canShoot(PlayerId player) {
        return !shooting.contains(player);      
    }

    private Action AssessThreats(PlayerId[][] field, int bullets){ 
        // Find the most threatening zombie     
        List<Point> bestZombies = new ArrayList<Point>();
        int smallestDistance = MaximumDistanceToShootZombie+1;      
        for(Point point : getSurrounding(field, CENTRE_OF_VISION, CENTRE_OF_VISION, MaximumDistanceToShootZombie)) {
            PlayerId zombie = point.Player;
            if(isZombie(zombie)) {              
                LinkedList<Point> path = findShortestPath_astar(field, CurrentLocation, point, false, false);               
                if(path.isEmpty()) 
                    continue;  
                if(path.size() <= smallestDistance && canShoot(zombie)) {
                    if(path.size() < smallestDistance) {
                        smallestDistance = path.size();
                        bestZombies.clear();
                    }
                    bestZombies.add(point);                                                                                            
                }    
            }
        }

        // No zombies to worry about
        if(bestZombies.isEmpty())
            return null;

        if(bestZombies.size() > 1) {
            if(_DEBUG) System.out.println("["+_lastGameTurn+"] Multiple Zombies in striking range, wait them out?");        
            return MoveToBestSpot(field);   
        }

        Point zombie = bestZombies.get(0);

        // Do we have ammo?
        if(bullets > 0 && shouldShoot(zombie.Player)) { 
            if(_DEBUG) System.out.println("["+_lastGameTurn+"] Shooting Zombie: "+(++zombieKills));             
            return new Shoot(zombie.Player);
        } 

        if(_DEBUG) System.out.println("["+_lastGameTurn+"] No Bullets to Shoot Zombie! Should flee");           
        return MoveInDirection(field, CENTRE_OF_VISION - zombie.X, CENTRE_OF_VISION - zombie.Y);    
    }

    private Action MoveToBestSpot(PlayerId[][] field) { 
        int leastZombies = 100000;
        Point bestPoint = CurrentLocation;
        for(Point point : CurrentLocation.getAdjacentPoints(field, 1, false)) {
            if(point.Player == null) {
                int zombies = countNumberOfSurroundingZombies(field, point.X, point.Y);
                if(zombies < leastZombies) {
                    leastZombies = zombies;
                    bestPoint = point;
                }
            }
        }
        return Move.inDirection(bestPoint.X - CurrentLocation.X, bestPoint.Y - CurrentLocation.Y);
    }

    private Action MoveInDirection(PlayerId[][] field, int x, int y) {
        x = (int)Math.signum(x);
        y = (int)Math.signum(y);

        if(y == 0){
            if(field[CENTRE_OF_VISION+x][CENTRE_OF_VISION] != null)
                return Move.inDirection(x,0);
            if(field[CENTRE_OF_VISION+x][CENTRE_OF_VISION-1] != null)
                return Move.inDirection(x,-1);
            if(field[CENTRE_OF_VISION+x][CENTRE_OF_VISION+1] != null)
                return Move.inDirection(x,1);   
        } else if(x == 0){
            if(field[CENTRE_OF_VISION][CENTRE_OF_VISION+y] != null)
                return Move.inDirection(0,y);
            if(field[CENTRE_OF_VISION-1][CENTRE_OF_VISION+y] != null)
                return Move.inDirection(-1,y);
            if(field[CENTRE_OF_VISION+1][CENTRE_OF_VISION+y] != null)
                return Move.inDirection(1,y);   
        } else {        
            if(field[CENTRE_OF_VISION+x][CENTRE_OF_VISION+y] != null)
                return Move.inDirection(x,y);
            if(field[CENTRE_OF_VISION+x][CENTRE_OF_VISION] != null)
                return Move.inDirection(x,0);
            if(field[CENTRE_OF_VISION][CENTRE_OF_VISION+y] != null)
                return Move.inDirection(0,y);   
        }

        return Move.inDirection(0,0);   
    }

    // Implementation of the A* path finding algorithm
    private LinkedList<Point> findShortestPath_astar(PlayerId[][] field, Point startingPoint, Point finalPoint, boolean includeWeights, boolean considerPlayersAsWalls) {   
        LinkedList<Point> foundPath = new LinkedList<Point>();
        Set<Point> openSet = new HashSet<Point>();
        Set<Point> closedSet = new HashSet<Point>();
        Hashtable<Point, Integer> gScores = new Hashtable<Point, Integer>();
        Hashtable<Point, Point> cameFrom = new Hashtable<Point, Point>();

        gScores.put(startingPoint, 0);
        openSet.add(startingPoint);
        Point currentPoint = startingPoint;

        while(!openSet.isEmpty()) {

            // Find minimum F score
            int minF = 10000000;
            for(Point point : openSet) {
                int g = gScores.get(point);
                int h = point.GetDistance(finalPoint); // Assumes nothing in the way                
                int f = g + h;
                if(f < minF) {
                    minF = f;               
                    currentPoint = point;
                }           
            }

            // Found the final point
            if(currentPoint.SameLocation(finalPoint)) {                 
                Point curr = finalPoint;
                while(!curr.SameLocation(startingPoint)) {
                    foundPath.addFirst(curr);
                    curr = cameFrom.get(curr);
                }
                return foundPath;
            }

            openSet.remove(currentPoint);
            closedSet.add(currentPoint);            

            // Add neighbouring squares
            for(Point pointToAdd : currentPoint.getAdjacentPoints(field, 1, false)){                            
                if(closedSet.contains(pointToAdd) || isWall(pointToAdd.Player) || (considerPlayersAsWalls && pointToAdd.Player != null && !pointToAdd.SameLocation(finalPoint) )) 
                    continue;

                int gScore = gScores.get(currentPoint) + 1; // distance should always be one (may change depending on environment)  
                // if(includeWeights){
                    // gScore += (int)-getScore(field,pointToAdd.X,pointToAdd.Y);
                // }   

                boolean distIsBetter = false;   

                if(!openSet.contains(pointToAdd)) {
                    openSet.add(pointToAdd);
                    distIsBetter = true;
                } else if(gScore < gScores.get(pointToAdd)){                    
                    distIsBetter = true;
                }
                if(distIsBetter) {
                    gScores.put(pointToAdd, gScore);
                    cameFrom.put(pointToAdd, currentPoint);                     
                }
            }  
        }

        return foundPath;   
    }

    private Action findShortestPath(PlayerId[][] field, Point startingPoint, Set<Point> finalPoints) {    
        if(finalPoints.isEmpty())
            return null;
        int smallestPath = 10000;       
        Point pointToMoveTo = startingPoint;  

        for(Point finalPoint : finalPoints) {  
            if(finalPoint == startingPoint)
                return null;
            LinkedList<Point> path = findShortestPath_astar(field, startingPoint, finalPoint, true, true);

            // No path between the two points
            if(path.isEmpty()){
                continue;
            }

            // Check if this is the smallest path
            if(path.size() < smallestPath) {                
                smallestPath = path.size();             
                pointToMoveTo = path.getFirst();                
            }           
        }       

        if(pointToMoveTo == startingPoint)
            return null;

        double score = getScore(field, pointToMoveTo.X, pointToMoveTo.Y);
        if(score < -200) {
            if(_DEBUG) System.out.println("["+_lastGameTurn+"] Best Path leads to a bad spot: "+score);     
            return null;
        }

        return Move.inDirection(pointToMoveTo.X - startingPoint.X, pointToMoveTo.Y - startingPoint.Y);          
    }

    private Set<Point> scoreSquares(PlayerId[][] field) {
        double bestScore = getScore(field, CENTRE_OF_VISION, CENTRE_OF_VISION) + 1; // plus one to break ties, and would rather stay
        Set<Point> bestLocations = new HashSet<Point>();
        if(bestScore >= 0) {
            bestLocations.add(CurrentLocation);         
        } else {
            bestScore = 0;
        }

        for(int x = 0; x < VISION_WIDTH; x++){
            for(int y = 0; y < VISION_WIDTH; y++){   
                if(x == CENTRE_OF_VISION && y == CENTRE_OF_VISION) continue;
                if(field[x][y] == null) {                                 
                    double score = getScore(field, x, y);           
                    if(score >= bestScore){
                        if(score > bestScore) {
                            bestLocations.clear();
                            bestScore = score;   
                        }
                        bestLocations.add(new Point(x, y));                      
                    }
                }
            }
        }       
        return bestLocations;
    }

    private double getScore(PlayerId[][] field, int x, int y) {
        int walls = countNumberOfSurroundingWalls(field, x, y); 
        double score = Math.pow(PointsPerWall, walls);      
        int aggressors = countNumberOfSurroundingAggressions(field, x, y);
        score += aggressors * PointsPerAggressor;   
        int zombies = countNumberOfSurroundingZombies(field, x, y);
        score += zombies * PointsPerZombie;
        int loots = countNumberOfSurroundingLoots(field, x, y);
        score += Math.pow(PointsPerLoot, loots);        
        return score;       
    }

    private int countNumberOfSurroundingZombies(PlayerId[][] field, int x, int y) {     
        int zombies = 0;
        Point currentPoint = new Point(x,y);
        for(Point point : getSurrounding(field, x, y, MaximumDistanceToShootZombie+1)){         
            if(isZombie(point.Player)){
                LinkedList<Point> path = findShortestPath_astar(field, currentPoint, point, false, false);
                if(path.isEmpty()) 
                    continue; 
                if(path.size() < MaximumDistanceToShootZombie+1)
                    zombies++;                  
            }            
        }
        return zombies;           
    }

    private int countNumberOfSurroundingLoots(PlayerId[][] field, int x, int y) {     
        int loots = 0;  
        for(Point point : getSurrounding(field, x, y, 1)){
            PlayerId player = point.Player;
            if(isWall(player) && !dontLoot.contains(player)){   
                loots++;                    
            }            
        }
        return loots;   
    }

    private int countNumberOfSurroundingAggressions(PlayerId[][] field, int x, int y) {     
        int aggressors = 0; 
        for(Point point : getSurrounding(field, x, y, SHOOT_RANGE+1)){
            if(isAgressive(point.Player)){
                aggressors++;                   
            }            
        }
        return aggressors;           
    }

    private int countNumberOfSurroundingWalls(PlayerId[][] field, int x, int y) {
        int walls = 0;      
        for(Point point : getSurrounding(field, x, y, 1)){
            if(isWall(point.Player)){
                walls++;                    
            }            
        }
        return walls;
    }

    private static boolean isZombie(PlayerId player) {
        return player != null && player.getName().equals("Zombie");
    }

    private static boolean isWall(PlayerId player) {
        return player != null && player.getName().equals("DeadBody");       
    }

    private static boolean isEnemy(PlayerId player) {
        if(player == null)
            return false;
        switch (player.getName()) {  
            case "Waller":
            case "DeadBody": 
            case "EmoWolfWithAGun":
                return false;
            default:
                return true;
        }
    }

    private static boolean isAgressive(PlayerId player) {
        if(player == null)
            return false;
        switch (player.getName()) {  
            case "Waller":
            case "DeadBody":   
            case "EmoWolfWithAGun":
            case "GordonFreeman":
            case "Vortigaunt": 
            case "StandStill":
            case "MoveRandomly":
            case "Zombie":
                return false;
            default:
                return true;
        }
    }

    // Helper Functions 

    private List<Point> getSurrounding(PlayerId[][] field, int x, int y, int maxDistance) {      
        final Point currentPoint = new Point(x,y);

        List<Point> players = new ArrayList<Point>();
        int minX = coercePoint(x - maxDistance);
        int maxX = coercePoint(x + maxDistance);
        int minY = coercePoint(y - maxDistance);
        int maxY = coercePoint(y + maxDistance);
        for(int i = minX; i <= maxX; i++){
            for(int j = minY; j <= maxY; j++) {
                if(i == x && j == y) continue;
                if(field[i][j] != null) {                
                    Point point = new Point(i,j,field[i][j]);
                    point.Distance = currentPoint.GetDistance(point);
                    players.add(point);
                }
            }
        }           

        Collections.sort(players, new Comparator<Point>() {
            public int compare(Point p1, Point p2) {
                return Integer.compare(p1.Distance, p2.Distance);          
            }});        

        return players;
    }

    private static int coercePoint(int value) {
        if(value < 0)
            return 0;
        if(value >= VISION_WIDTH)
            return VISION_WIDTH-1;
        return value;
    }

    public static Point GetNewTorusPoint(int x, int y, int boardSize) {
        if(x >= boardSize)
            x = boardSize - x;
        if(y >= boardSize)
            y = boardSize - y;
        return new Point(x,y);
    }

    private static int getDistance(int x1, int y1, int x2, int y2) {
        return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
    }
}

Ồ, cái này hay đấy Tôi đã hy vọng ai đó sẽ làm một cái gì đó với thuật toán tìm đường thực sự - tôi đã chơi một vòng với Dijkstra một chút, nhưng điều này có vẻ như nó có thể làm cho công việc của tôi trở nên lỗi thời.
James_pic

@James_pic Cảm ơn, tối nay tôi đã chơi với anh ấy rất nhiều. Rất nhiều điều thú vị để làm khi bạn có con đường tìm kiếm. Các thử nghiệm ban đầu của tôi đặt anh ta ở vị trí thứ ba sau Coward và Shotguneer.
Moop

Không phải người ta có thể làm bất cứ điều gì về nó, nhưng fyi, zombie không chỉ có thể sinh sản trên những cánh đồng trống hoặc người chơi mà dưới cả DeadBody.
Thaylon

@Thaylon Tôi nhận thấy rằng trong khi nhìn vào các bản đồ ouput. Không có gì tôi có thể chuẩn bị cho dù sao, nhưng cảm ơn vì đã quan sát tôi.
Moop

Có thể là một sai lầm khi coi StandStill như một bức tường. Chắc chắn, nó không di chuyển, nhưng nó không có khả năng chống lại zombie
James_pic

8

Gordon Freeman

Gordon Freeman ghét zombie, vì vậy anh ta sẽ không bao giờ tự sát, nhưng anh ta không có ý định nhặt rác để có thêm đạn để bắn nhiều zombie hơn.

package player;

import zombie.*;
import static zombie.Constants.*;
import static java.lang.Math.*;

public class GordonFreeman implements Player {
    @Override
    public Action doTurn(PlayerContext context){
        int ammo = context.getBullets();
        // if I have bullets, shoot some zombies
        if(ammo > 0){
            for(PlayerId player: context.shootablePlayers()){
                switch(player.getName()){
                    case "Zombie":
                       return new Shoot(player);
                    default:
                       break;
                }
            }
        }
        // if no bullets, find a dead body and scavenge
        Move bestDirection = Move.STAY;
        int bestDistance = Integer.MAX_VALUE;
        for(int y = 1; y < VISION_WIDTH - 1; y++) {
            for(int x = 1; x < VISION_WIDTH - 1; x++) {

                PlayerId playerAtLocation = context.getPlayField()[x][y];
                // find a dead body
                if((playerAtLocation != null) && "DeadBody".equals(playerAtLocation.getName())){
                    // check adjacent squares for an empty square
                    for(int yy=-1; yy <= +1; yy++){
                        for(int xx=-1; xx <= +1; xx++){
                            PlayerId playerNearby = context.getPlayField()[x + xx][y + yy];
                            if(playerNearby == null){
                                int distance = max(abs(xx + x - CENTRE_OF_VISION), abs(yy + y - CENTRE_OF_VISION));
                                if(distance < bestDistance){
                                    bestDistance = distance;
                                    bestDirection = Move.inDirection(xx + x - CENTRE_OF_VISION, yy + y - CENTRE_OF_VISION);
                                }
                            }
                        }
                    }
                }
            }
        }
        return bestDirection;
    }
}

Tôi hy vọng bạn không phiền, nhưng tôi đã thực hiện một vài chỉnh sửa nhỏ cho mã của mình để biên dịch mã và sửa một vài lỗi con trỏ null hoặc chỉ mục mảng, khiến nó bị lỗi trong thời gian chạy. Tôi đã không thay đổi logic.
James_pic

@James_pic: Tôi đánh giá cao các bản sửa lỗi, tôi không phải là một lập trình viên Java, mặc dù tôi muốn nghĩ rằng tôi làm đủ tốt cho các thách thức KotH này: D.
Kyle Kanos

Bạn có thể muốn xem lại trận đấu cuối cùng, tại jamespic.github.io/zombie/2014-07-21/0.html . Có vẻ như Tiến sĩ Freeman luôn đi về phía tây bắc, điều này có thể giải thích cho màn trình diễn không nhất quán của ông.
James_pic

@James_pic: Cái nào là Freeman? Có hai chữ G (một màu xanh, màu vàng khác). Nếu của tôi là G màu xanh, thì có vẻ như anh ta di chuyển ngẫu nhiên và không chỉ là NW. Ngoài ra, có cách nào để nói giữa một thây ma chết và một người chết không?
Kyle Kanos

1
Cảm ơn bạn :) Tôi thích sử dụng lại mã khi tôi có thể, nhưng tôi thích thừa nhận khi nó không phải là của tôi.
sokie

7

Linh mục

Nếu bạn có đức tin, bạn không cần phải chạy cũng không phải bắn.

package player;

import zombie.*;
import static zombie.Constants.*;
import static java.lang.Math.*;

public class ThePriest implements Player {

    @Override
    public Action doTurn(PlayerContext context) {
        return Move.NORTH;
    }
}

4
HuddleWolf.... Tôi thấy những gì bạn đã làm ở đó;)
Kyle Kanos

Tôi e rằng bạn sẽ cần đặt tên cho lớp của mình một cái gì đó khác HuddleWolf, vì tên đó đã được sử dụng
James_pic

6

ZombieHater

Trình này ghét zombie! Nó cố gắng bắn zombie gần nhất trong khi nó có đạn, sau đó thu thập thêm đạn để giết nhiều zombie hơn.

Chỉnh sửa: ZombieHater bây giờ không ngần ngại giết người khác để có thêm đạn. Nó cũng phát hiện những trở ngại và cố gắng đi xung quanh chúng.

package player;

import java.awt.Point;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import zombie.*;
import static zombie.Constants.*;

public class ZombieHater implements Player {
    private static final Set<PlayerId> emptyDeadBodies = new HashSet<>();
    private static final Map<PlayerId, Point> lastPos = new HashMap<>();

    @Override
    public Action doTurn(PlayerContext context) {
        PlayerId[][] field = context.getPlayField();
        Point myPos = new Point(context.getX(), context.getY());
        PlayerId myId = context.getId();

        // update dead bodies with the new empty ones
        addEmptyBodies(field);

        // shoot nearest zombie if possible
        if (context.getBullets() > 0) {
            PlayerId nearestZombie = getNearestEnemy(field);
            if (nearestZombie != null) {
                lastPos.remove(myId);
                return new Shoot(nearestZombie);
            }
        }

        // stuck, mostly because of dead body
        if (lastPos.containsKey(myId) && lastPos.get(myId).equals(myPos)) {
            return Move.randomMove();
        }

        // walk towards dead bodies
        Point nearestDeadBody = getNearestDeadBody(field);
        if (nearestDeadBody != null) {
            Move move = Move.inDirection(nearestDeadBody.x - CENTRE_OF_VISION, nearestDeadBody.y - CENTRE_OF_VISION);
            lastPos.put(myId, myPos);
            return move;
        }

        lastPos.remove(myId);
        return Move.randomMove();
    }

    // add surrounding dead bodies to empty bodies
    private void addEmptyBodies(PlayerId[][] field) {
        for (Move move : Move.values()) {
            PlayerId player = field[CENTRE_OF_VISION + move.x][CENTRE_OF_VISION + move.y];
            if (player != null && "DeadBody".equals(player.getName())) {
                emptyDeadBodies.add(player);
            }
        }
    }

    // distance from centre, for example 5 if x=7 and y=3
    private int distanceFromCentre(int x, int y) {
        int dx = Math.abs(CENTRE_OF_VISION - x);
        int dy = Math.abs(CENTRE_OF_VISION - y);
        return Math.max(dx, dy);
    }

    // return nearest enemy or null if none exists
    private PlayerId getNearestEnemy(PlayerId[][] field) {
        int minOffset = Integer.MAX_VALUE;
        PlayerId nearestEnemy = null;
        for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION + SHOOT_RANGE; x++) {
            for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION + SHOOT_RANGE; y++) {
                int offset = distanceFromCentre(x, y);
                PlayerId player = field[x][y];
                if (player != null && isEnemy(player.getName()) && offset < minOffset) {
                    minOffset = offset;
                    nearestEnemy = field[x][y];
                }
            }
        }
        return nearestEnemy;
    }

   // return nearest dead body or null if none exists
    private Point getNearestDeadBody(PlayerId[][] field) {
        int minOffset = Integer.MAX_VALUE;
        Point nearestDeadBody = null;
        for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION + SHOOT_RANGE; x++) {
            for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION + SHOOT_RANGE; y++) {
                int offset = distanceFromCentre(x, y);
                PlayerId player = field[x][y];
                if (player != null && "DeadBody".equals(player.getName()) && offset < minOffset && 
                        !emptyDeadBodies.contains(player)) {
                    minOffset = offset;
                    nearestDeadBody = new Point(x, y);
                }
            }
        }
        return nearestDeadBody;
    }

    private boolean isEnemy(String name) {
        switch (name) {
            case "ZombieHater":
            case "DeadBody":
            case "EmoWolfWithGun": // don't bother shooting him
                return false;
            default:
                return true;
        }
    }
}

-1. Mặc dù khác nhau trong cách thực hiện, nhưng điều này khá giống với Gordon Freeman của tôi ....
Kyle Kanos

2
@KyleKanos. Đó là cùng một ý tưởng, nhưng chi tiết thực hiện tính. Theo dõi các xác chết có loot là một sự đổi mới, ví dụ.
James_pic

Ồ, và về chủ đề theo dõi loot, PlayerIdcó cách triển khai phù hợp equalshashCode, và vẫn như vậy trong suốt "cuộc đời" của người chơi (nó chỉ thay đổi khi họ chết hoặc quay đầu), vì vậy bạn có thể thấy đơn giản hơn để giữ PlayerIds emptyDeadBodieshơn vị trí.
James_pic

@KyleKanos không bao giờ tôi có ý định sao chép logic của bạn. Tất cả những gì tôi đã làm là tạo bot của riêng mình theo cách tôi nghĩ nó sẽ làm tốt nhất.
CommonGuy

1
Mod đẹp quá! Tôi đã bắt đầu lo lắng rằng hầu hết các chiến lược về cơ bản là giống nhau, nhưng sự ngẫu nhiên chuyển động đó đã mang lại cho bạn một sự thúc đẩy to lớn!
James_pic

6

Vòng xoáy

Sẽ luôn đi theo Bác sĩ Gordon Freeman, hoặc đi loanh quanh một cách vô mục đích nếu anh ta không cùng chiều.

package player;

import java.util.ArrayList;

import zombie.*;

public class Vortigaunt implements Player {
    class PlayerLocation {
        private int x;
        int y;
        PlayerId player;

        public PlayerLocation(int x, int y, PlayerId id) {
            this.x = x;
            this.y = y;
            this.player = id;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public PlayerId getPlayer() {
            return player;
        }
    }
    @Override
    public Action doTurn(PlayerContext context) {
        PlayerId[][] field = context.getPlayField();
        PlayerLocation me = new PlayerLocation(context.getX(), context.getY(), context.getId());
        ArrayList<PlayerLocation> freemans = findFreeman(field);
        PlayerLocation nearestFreeman = getNearestFreeman(freemans, me);
        if (nearestFreeman == null) {
            return Move.randomMove();
        } else {
            return Move.inDirection(nearestFreeman.getX(), nearestFreeman.getY());
        }
    }

    private PlayerLocation getNearestFreeman(ArrayList<PlayerLocation> freemans, PlayerLocation me) {
        double nearestDistance = Integer.MAX_VALUE;
        PlayerLocation nearestFreeman = null;
        for (PlayerLocation freeman : freemans) {
            int x = freeman.getX() - me.getX();
            int y = freeman.getY() - me.getY();
            double distance = (int)Math.sqrt((double)(x * x + y * y));
            if (distance < nearestDistance) {
                nearestDistance = distance;
                nearestFreeman = freeman;
            }
        }
        return nearestFreeman;
    }

    private ArrayList<PlayerLocation> findFreeman(PlayerId[][] field) {
        ArrayList<PlayerLocation> freemans = new ArrayList<PlayerLocation>();
        for (int x = field.length; x >= 0; x -= 1) {
            for (int y = field[x].length; y >= 0; y -= 1) {
                if (field[x][y].getName().equals("GordonFreeman")) {
                    freemans.add(new PlayerLocation(x, y, field[x][y]));
                }
            }
        }
        return freemans;
    }

}

Vì vậy, bạn không bao giờ bắn ... nhưng bám sát người nào đó ... Tôi không thể biết liệu điều này có khiến Freeman bị giết hay không nhưng điều này sẽ rất tuyệt vời đối với quần thể zombie ...
kaine

6

Kén - Frege

Thật là ngại quá. Một nửa tá ngôn ngữ để lựa chọn và mọi người chỉ sử dụng Java. Chà, không có ý nghĩa gì khi để chúng lãng phí, vì vậy đây là đối thủ cạnh tranh trong Frege.

Nó sử dụng thuật toán của Dijkstra để tìm một vị trí hẻo lánh để chờ ngày tận thế, tìm kiếm viên đạn nếu nó hết và bắn zombie nếu chúng ở quá gần.

Đã cập nhật

Cocoon hiện bỏ qua các tuyến đường sẽ đưa nó vào khoảng cách đáng kinh ngạc của zombie trong thuật toán định tuyến của nó và bắn zombie khi chúng ở trong 2 ô vuông, thay vì 3 (để xây dựng một cái kén chặt hơn).

module player.Cocoon where
  import zombie.FregeBindings
  import frege.data.TreeMap
  import Data.List(sortBy)
  import Data.Foldable(minimumBy, maximumBy)

  instance Ord PlayerId where
    a <=> b = case a.getName <=> b.getName of
      Eq -> a.getNumber <=> b.getNumber
      x -> x

  instance Show Action where
    show action = action.toString

  -- Dijkstras shortest path algorithm
  data DijkstraNode = Green {d :: Int, pos :: (Int, Int)} | Red {pos :: (Int, Int)} | Yellow {d :: Int, pos :: (Int, Int)}
  data DijkstraState = DijkstraState {board :: Tree (Int, Int) DijkstraNode, yellows :: TreeSet DijkstraNode}
  derive Eq DijkstraNode
  derive Ord DijkstraNode
  derive Show DijkstraNode
  derive Show DijkstraState

  updateState :: Int -> DijkstraState -> (Int, Int) -> DijkstraState
  updateState d (oldState@DijkstraState {board, yellows}) pos  = case (lookup board pos) of
    Nothing -> oldState
    Just Green {d, pos} -> oldState
    Just Red {pos} -> let
        newYellow = Yellow d pos
        newYellows = insert yellows newYellow ()
        newBoard = update board pos newYellow
      in DijkstraState {board = newBoard, yellows = newYellows}
    Just (oldYellow@Yellow {d = oldD, pos = oldPos})
          | oldD <= d = oldState
          | true = let
              newYellow = Yellow d pos
              newYellows = insert (delete yellows oldYellow) newYellow ()
              newBoard = insert board pos newYellow
            in DijkstraState {board = newBoard, yellows = newYellows}

  neighbours :: (Int, Int) -> [(Int, Int)]
  neighbours (x,y) = [(x1 + x, y1 + y) | x1 <- [-1 .. 1], y1 <- [-1 .. 1], x1 != 0 || y1 != 0]

  moveRegion = [(x, y) | x <- [-1 .. 1], y <- [-1 .. 1]]

  findMove :: DijkstraState -> Maybe Move
  findMove DijkstraState {board, yellows}
     | null yellows = Nothing
     | true = let
         tip@Yellow{d, pos} = head (keys yellows)
         rest = delete yellows tip
         newBoard = insert board pos (Green d pos)
         intermediateState = DijkstraState {board = newBoard, yellows = rest}
         neighbourhood = [node | pos <- moveRegion , node <- lookup board pos]
       in if tip.pos == (0, 0)
          then case minimum neighbourhood of
            _ | null neighbourhood = Nothing
            Green {d, pos = (x,y)} -> Just (Move.inDirection x y)
            _ -> Nothing
          else findMove (fold (updateState (d + 1)) intermediateState (neighbours pos))

  insertRed :: Tree (Int, Int) DijkstraNode -> (Int, Int) -> Tree (Int, Int) DijkstraNode
  insertRed board pos = insert board pos (Red {pos})

  removeZombieTerritory :: PlayerContext -> Tree (Int, Int) DijkstraNode -> Tree (Int, Int) DijkstraNode
  removeZombieTerritory ctx board =
    let
      zombies = [pos | pos@(x,y) <- v2, pid <- ctx.lookAround x y, pid.getName == "Zombie"]
      zombieTerritory = [(x + xx, y + yy) | (x,y) <- zombies, xx <- [-2..2], yy <- [-2..2]]
    in fold Tree.delete board zombieTerritory

  v = [-visionRange .. visionRange]
  v2 = sortBy (comparing dist) [(x,y) | x <- v, y <- v]

  shootable = sortBy (comparing dist) [(x, y) | x <- [-shootRange .. shootRange], y <- [-shootRange .. shootRange]]

  moveTo :: (Int, Int) -> PlayerContext -> Maybe Move
  moveTo pos ctx =
    let
      rawBoard = fold insertRed Tree.empty ([p | p@(x, y) <- v2,
                                                  ctx.lookAround x y == Nothing] ++ [(0,0)])
      board = removeZombieTerritory ctx rawBoard
      yellows = Tree.insert Tree.empty (Yellow {d = 0, pos}) ()
    in findMove (DijkstraState {board, yellows})

  dist :: (Int, Int) -> Int
  dist (x,y) = max (abs x) (abs y)

  findBullets :: PlayerContext -> TreeSet PlayerId -> Maybe Action
  findBullets ctx emptyBodies =
    if (ctx.getBullets > 0) then Nothing
    else
      let
        viableBodies = [pos | pos@(x,y) <- v2, pid <- (ctx.lookAround x y), pid.getName == "DeadBody", lookup emptyBodies pid == Nothing]
      in case viableBodies of
         target : _ -> moveTo target ctx
         _ -> Nothing

  isThreat :: String -> (Int, Int) -> Bool
  isThreat name pos = case (name, pos) of
    ("Zombie", pos) | dist pos <= 2 -> true
    ("HideyTwitchy", _) -> true
    ("ZombieHater", _) -> true
    ("ZombieRightsActivist", _) -> true
    ("Gunner", _) -> true
    _ -> false

  shootThreats :: PlayerContext -> Maybe Action
  shootThreats ctx =
    let
      threats = [pid | pos@(x, y) <- shootable, pid <- ctx.lookAround x y, isThreat (pid.getName) pos]
    in case threats of
      target:_ | ctx.getBullets == 0 = Nothing
               | true = Just (Shoot.new target)
      _ -> Nothing

  coziness :: PlayerContext -> (Int, Int) -> Int
  coziness ctx (x,y) =
    let
      wallScores = [3 - dist (xx, yy) | xx <- [-2 .. 2],
                                        yy <- [-2 .. 2],
                                        xx != 0 || yy != 0,
                                        pid <- ctx.lookAround (x + xx) (y + yy),
                                        pid.getName == "DeadBody"]
    in 3 * sum wallScores - dist (x,y)

  gotoCoziest :: PlayerContext -> Maybe Action
  gotoCoziest ctx =
    let
      emptySquares = [pos | pos@(x, y) <- v2, ctx.lookAround x y == Nothing] ++ [(0,0)]
      coziest = maximumBy (comparing (coziness ctx)) emptySquares
    in if null emptySquares then Nothing
       else moveTo coziest ctx

  updateEmptyBodies :: PlayerContext -> TreeSet PlayerId -> TreeSet PlayerId
  updateEmptyBodies ctx current =
    let
      nearbyBodies = [pid | (x,y) <- neighbours (0,0), pid <- ctx.lookAround x y, pid.getName == "DeadBody"]
    in fold (\x -> \y -> insert x y ()) current nearbyBodies

  doStep :: TreeSet PlayerId -> PlayerContext -> Continue
  doStep !bodies ctx =
    let
      emptyBodies = updateEmptyBodies ctx bodies
      plan = (findBullets ctx emptyBodies) `mplus` (shootThreats ctx) `mplus` (gotoCoziest ctx)
    in case plan of
      Just action -> Continue {result = action, andThen = doStep emptyBodies}
      Nothing -> Continue {result = Move.stay, andThen = doStep emptyBodies}

  doTurn = doStep Tree.empty

4

Pháo thủ - Java

Đây là một ví dụ để giúp bạn thoát khỏi các khối. Anh ta bắn bất cứ thứ gì anh ta nhìn thấy, hoặc đi lang thang vô mục đích nếu không có gì xung quanh, hoặc anh ta không có đạn.

package player;

import zombie.*;

public class Gunner implements Player {

    @Override
    public Action doTurn(PlayerContext context) {
        if (context.getBullets() > 0) {
            for (PlayerId player: context.shootablePlayers()) {
                switch(player.getName()) {
                    case "Gunner":
                    case "DeadBody":
                        break;
                    default:
                        return new Shoot(player);
                }
            }
        }
        return Move.randomMove();
    }

}

Bạn có thể làm tốt hơn?


3

HideyTwitchy

Nutjob che giấu mọi thứ trừ khi người chơi đuổi theo anh ta đến trường bắn, trong trường hợp anh ta hoảng loạn và bắn (bao gồm cả loại của mình). Chỉ cướp cơ thể nếu anh ta hết đạn, sau đó thoát khỏi xác chết.

package player;

import static java.lang.Math.*;
import java.awt.Point;
import java.util.HashSet;
import java.util.Set;

import zombie.*;
import static zombie.Constants.*;

public class HideyTwitchy implements Player {

    private Set<Integer> lootedCorpseIds = new HashSet<Integer>();

    @Override
    public Action doTurn(PlayerContext context) {
        Action action = null;

        Point playerP = getClosestPlayerPoint(context);
        Point corpseP = getClosestCorpsePoint(context); 
        Point enemyP = getClosestEnemyPoint(context);

        if (isWithinArea(playerP, Constants.SHOOT_RANGE, Constants.SHOOT_RANGE)) {
            //player spotted within 5x5
            if (context.getBullets() > 0) {
                action = getShootAction(playerP, context); //shoot!
            } else {
                action = getMoveAwayFromPoint(playerP); //run!
            }
        } else if (isWithinArea(enemyP, Constants.VISION_RANGE, Constants.VISION_RANGE)) {
            //players or zombie spotted within 8x8
            action = getMoveAwayFromPoint(enemyP); //run!
        } else if (isWithinArea(corpseP, Constants.VISION_RANGE, Constants.VISION_RANGE)) {
            //corpse spotted within 8x8

            int uniqueCorpseId = getPlayerIdAtPoint(context, corpseP).getNumber();
            if (isWithinArea(corpseP, 1, 1)) {
                //loot the corpse and get the heck away from it
                lootedCorpseIds.add(uniqueCorpseId);
                action = getMoveAwayFromPoint(corpseP);
            } else if (context.getBullets() == 0 && !lootedCorpseIds.contains(uniqueCorpseId)) {
                action = getMoveTowardsPoint(corpseP); //loot corpse if not looted!
            } 
        } else {
            //randomly move
            action = Move.randomMove();
        }

        return action;
    }

    private PlayerId getPlayerIdAtPoint(PlayerContext context, Point p) {
        return context.getPlayField()[(int) p.getX()][(int) p.getY()];
    }

    private Move getMoveTowardsPoint(Point p) {
        return Move.inDirection((int)p.getX() - CENTRE_OF_VISION, (int)p.getY() - CENTRE_OF_VISION);
    }

    private Move getMoveAwayFromPoint(Point p) {
        return Move.inDirection(CENTRE_OF_VISION - (int)p.getX(), CENTRE_OF_VISION - (int)p.getY());
    }

    private Shoot getShootAction(Point p, PlayerContext context) {
        PlayerId id = context.getPlayField()[(int) p.getX()][(int) p.getY()];
        Shoot shootAction = new Shoot(id);

        return shootAction;
    }

    private boolean isWithinArea(Point p, int x, int y) {
        return p != null 
                && abs(CENTRE_OF_VISION - p.getX()) <= x
                && abs(CENTRE_OF_VISION - p.getY()) <= y;
    }

    private Point getClosestEnemyPoint(PlayerContext context) {
        String[] lookFor = {};
        String[] avoid = {Dead.DEADBODYNAME};
        Point p = getClosestEntity(context, lookFor, avoid);

        return p;
    }

    private Point getClosestPlayerPoint(PlayerContext context) {
        String[] lookFor = {};
        String[] avoid = {Dead.DEADBODYNAME, Dead.ZOMBIENAME};
        Point p = getClosestEntity(context, lookFor, avoid);

        return p;
    }

    private Point getClosestCorpsePoint(PlayerContext context) {
        String[] lookFor = {Dead.DEADBODYNAME};
        String[] avoid = {Dead.ZOMBIENAME};
        Point p = getClosestEntity(context, lookFor, avoid);

        return p;
    }

    private Point getClosestEntity(PlayerContext context, String[] lookFor, String[] avoid) {

        int bestDistance = Integer.MAX_VALUE;
        Point closestPoint = null;

        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {


                PlayerId playerAtLocation = context.getPlayField()[x][y];

                if (playerAtLocation != null && !playerAtLocation.equals(context.getId())) {
                    //not empty and not me

                    boolean conditionsMet = true;
                    for (String lookForName : lookFor) {
                        conditionsMet |= playerAtLocation.getName().equals(lookForName);
                    }

                    for (String avoidName : avoid) {
                        conditionsMet &= !playerAtLocation.getName().equals(avoidName);
                    }

                    if (conditionsMet) {
                        int distance = max(abs(x - CENTRE_OF_VISION), abs(y - CENTRE_OF_VISION));
                        if (distance < bestDistance) {
                            bestDistance = distance;
                            closestPoint = new Point(x, y);
                        }
                    }
                }
            }
        }

        return closestPoint;
    }
}

3

SuperCoward - JAVA Tôi biết về đệ trình kép nhưng tôi không thể cưỡng lại. Xin vui lòng cho tôi biết nếu tôi nên loại bỏ nó.

Những kẻ hèn nhát là ai mà bắn và chiến đấu? Trình bày với bạn SUPER Coward, anh ta sẽ chạy trên sân cố gắng tránh kẻ mà anh ta nghĩ là kẻ thù và thây ma. Anh cố gắng giữ an toàn và tránh chướng ngại vật. Nếu anh ta không tìm thấy một tuyến đường tốt, hoảng loạn và giữ nguyên vị trí

package player;

import zombie.*;
import static zombie.Constants.*;

import static java.lang.Math.abs;
import static java.lang.Math.max;

import java.awt.Point;

public class SuperCoward implements Player {

    private enum DANGER{
        SAFE(0),PROBABLY_SAFE(1),UNSAFE(2),DANGER(3);

        private int value;
        private DANGER(int value){
            this.value = value;
        }
    }

    private final int PLAYER_X = 8;
    private final int PLAYER_Y = 8;

    @Override
    public Action doTurn(PlayerContext context) {

        DANGER danger = DANGER.DANGER;
        Point position = null;
        for(int i=-1;i<1;i++){
            for(int j=-1;j<1;j++){
                DANGER positionDanger = isDangerous(context,PLAYER_X+i,PLAYER_Y+j);
                if(positionDanger.value < danger.value){
                    if(canMove(context,PLAYER_X+i,PLAYER_Y+j)){
                        position = new Point(PLAYER_X+i, PLAYER_Y+j);
                    }
                }
            }
        }

        if(position != null){
            return Move.inDirection(position.x, position.y);
        }else{
            return Move.STAY;
        }
    }

    private boolean canMove(PlayerContext context,int posX, int posY){
         PlayerId playerAtLocation = context.getPlayField()[posX][posY];
        if(playerAtLocation == null){
            return true;
        }else{
            return false;
        }
    }

    private DANGER isDangerous(PlayerContext context,int posX, int posY){
        DANGER danger = DANGER.SAFE;

          for (int x = 0; x < VISION_WIDTH; x++) {
                for (int y = 0; y < VISION_WIDTH; y++) {
                     PlayerId playerAtLocation = context.getPlayField()[x][y];

                     if(playerAtLocation != null && isEnemy(playerAtLocation.getName())){
                         int distanceToPlayer = max(abs(x - posX), abs(y - posY));
                         if(playerAtLocation.getName().equals("Zombie")){
                             DANGER currentDanger = null;
                             if(distanceToPlayer <=3){
                                 currentDanger = DANGER.DANGER;
                             }else if(distanceToPlayer <=5){
                                 currentDanger = DANGER.PROBABLY_SAFE;
                             }else if(distanceToPlayer >5){
                                 currentDanger = DANGER.SAFE;
                             }
                             if(currentDanger.value > danger.value){
                                 danger = currentDanger;
                             }
                         }else{
                             DANGER currentDanger = null;
                             if(distanceToPlayer <=5){
                                 currentDanger = DANGER.DANGER;
                             }else if(distanceToPlayer >5){
                                 currentDanger = DANGER.PROBABLY_SAFE;
                             }
                             if(currentDanger.value > danger.value){
                                 danger = currentDanger;
                             }
                         }
                     }
                }
          }
        return danger;
    }

    private boolean isEnemy(String name){
         switch(name) {
            case "DeadBody":
            case "GordonFreeman":
            case "EmoWolfWithAGun":
            case "HuddleWolf":
            case "ThePriest":
            case "Shotguneer":
            case "SuperCoward":
                return false;
            default:
                return true;
         }
    }
}

Suy nghĩ hiện tại của tôi là tôi sẽ cho phép đệ trình gấp đôi miễn là không có sự thông đồng giữa chúng - vì vậy các mục có thể dễ dàng được gửi bởi những người chơi khác nhau đều ổn, nhưng tay sai hoặc lapdogs thì không. Điều này có vẻ như sẽ ổn (trừ khi có ai đó phản đối), vì vậy tôi sẽ kiểm tra nó khi có cơ hội.
James_pic

3
+1 choDANGER danger = DANGER.DANGER;
Andreï Kostyrka

3

Shotguneer

Tôi sẽ thừa nhận rằng mục tiêu chính của tôi là bắn Gunner.

package player;

import zombie.*;
import static zombie.Constants.*;
import static java.lang.Math.*;

public class Shotguneer implements Player {

    @Override
    public Action doTurn(PlayerContext context) {

        double sdistance=1000;

        if (context.getBullets() > 0) {
            for (PlayerId player: context.shootablePlayers()) {
                switch(player.getName()) {
                    case "Gunner":
                    case "ZombieRightsActivist":
                    case "HideyTwitchy":
                    case "ZombieHater":
                    case "Waller";
                    case "Bee";
                    case "SunTzu";
                    //case "Fox":
                    //case "Coward":
                        return new Shoot(player);
                    default:
                        break;
                }
            }
            boolean zombies=false;
            PlayerId TargetZombie = context.getId();
            for (int x = -3; x < +4; x++) {
            for (int y = -3; y < +4; y++) {
                double distance = sqrt(pow(x,2)+pow(y,2));
                PlayerId playerAtLocation = context.getPlayField()[x + CENTRE_OF_VISION][y + CENTRE_OF_VISION];
                if (playerAtLocation != null && playerAtLocation.getName().equals("Zombie") && (distance < sdistance ||zombies==false)) {
                    sdistance = distance;
                    zombies=true;
                    TargetZombie=playerAtLocation;
                }
                //if (playerAtLocation != null && playerAtLocation.getName().equals("Priest") && distance < 2 &&zombies==false) {
                    //TargetZombie=playerAtLocation;
                    //sdistance=distance;
                //}
            }}
            if (zombies || sdistance<3) {
                return new Shoot(TargetZombie);
            }
        }

        if (context.getPlayField()[CENTRE_OF_VISION-1][CENTRE_OF_VISION-1]==null){
            return Move.NORTHWEST;  
        } else if (context.getPlayField()[CENTRE_OF_VISION][CENTRE_OF_VISION-1]==null){
            return Move.NORTH;
        } else {
            return Move.WEST;
        }

    }

}

@Benny làm thế nào để bạn làm điều đó để bạn không phải chỉnh sửa nữa?
kaine

Như nó đứng, điều này không biên dịch. Tôi đã cố gắng sửa nó, nhưng có một vài nơi tôi không thể hiểu ý định ban đầu của mã là gì (ví dụ, trình biên dịch phàn nàn rằng TargetZombiecó thể không được khởi tạo và tôi không chắc là gì bạn muốn làm). Bạn có muốn thực hiện một cú swing khác không?
James_pic

Cảm ơn bạn đã thử. Tôi đã không thiết lập mã của bạn để nó thất bại vì nó không nhận ra hằng số của bạn. Tôi không nhớ nó sẽ không biên dịch nếu TargetZombie không có giá trị mặc định (mặc dù nó sẽ không bao giờ được sử dụng nếu không nhờ vào hằng số zombie). Tôi đã sửa đổi nó để nó giết tôi nếu tôi sai về điều đó!. Đừng lãng phí thời gian của bạn để cố gắng chỉnh sửa nó trừ khi bạn chán, tôi sẽ viết một bình luận khác nếu tôi có thể xác nhận nó hoạt động cùng với những người chơi khác.
kaine

Tôi đã sửa nó để nó sẽ biên dịch và chạy mà không gặp lỗi - chủ yếu là lỗi "tắt do CENTRE_OF_VISION" và một số NPE. Bạn sẽ phải xem qua hoạt động ( jamespic.github.io/zombie/2014-07-23/0.html ) để xem liệu nó có làm những gì bạn mong đợi không.
James_pic

Có vẻ như bạn đã có một tác động lớn đến tuổi thọ của Pháo thủ! Tôi tự hỏi nếu điều này sẽ châm ngòi cho một làn sóng các đối thủ cạnh tranh hàng đầu đưa nhau ra ngoài?
James_pic

2

Sokie - JAVA

Sokie biết rằng bạn tốt hơn trong các gói, vì vậy nó cố gắng đi đến đồng minh gần nhất mà anh ta tìm thấy. Trong khi di chuyển, nếu anh ta gặp nguy hiểm hãy cố gắng chiến đấu hoặc cố gắng chạy. Khi anh ta tiếp cận bạn bè, tất cả họ chiến đấu cùng nhau cho đến khi họ không có đạn, sau đó cố gắng tìm những thi thể gần nhất để nhặt rác.

package player;

import zombie.*;
import static zombie.Constants.*;

import static java.lang.Math.abs;
import static java.lang.Math.max;

import java.awt.Point;
import java.util.HashMap;
import java.util.Map;

public class Sokie implements Player {

    public static Map<Point, Sokie> myPack = new HashMap<>();
    private PlayerContext context;
    private Move moveDirection;
    private final int PLAYER_X = 8;
    private final int PLAYER_Y = 8;

    private enum DANGER {
        SAFE(0), PROBABLY_SAFE(1), UNSAFE(2), DANGER(3);

        private int value;

        private DANGER(int value) {
            this.value = value;
        }
    }

    @Override
    public Action doTurn(PlayerContext context) {
        Point p = new Point(context.getX(), context.getY());
        myPack.put(p, this);
        this.context = context;

        int friends = 0;
        int deadbodyDistance = Integer.MAX_VALUE;
        Move deadbodyDirection = null;
        Point deadBodyPosition = null;
        Move friendsDirection = Move.SOUTHWEST;

        // Find the closest friend to whom we can move
        int maxDistance = Integer.MAX_VALUE;
        for (Sokie bp : myPack.values()) {
            // Skip ourselves
            if (bp.context.equals(context)) {
                continue;
            }
            Point pos = bp.getPosition();
            int x = pos.x;
            int y = pos.y;
            int distance = Math.max(Math.abs(context.getX() - x),
                    Math.abs(context.getY() - y));
            if (distance < maxDistance) {
                if (canMove(context, (int) Math.signum(x), (int) Math.signum(y))
                        && !isDangerous(context, (int) Math.signum(x),
                                (int) Math.signum(y))) {
                    maxDistance = distance;
                    friendsDirection = Move.inDirection((int) Math.signum(x),
                            (int) Math.signum(y));
                } else {
                    if (canMove(context, (int) Math.signum(0),
                            (int) Math.signum(y))
                            && !isDangerous(context, (int) Math.signum(x),
                                    (int) Math.signum(y))) {
                        maxDistance = distance;
                        friendsDirection = Move.inDirection(
                                (int) Math.signum(0), (int) Math.signum(y));
                    } else if (canMove(context, (int) Math.signum(x),
                            (int) Math.signum(0))
                            && !isDangerous(context, (int) Math.signum(x),
                                    (int) Math.signum(y))) {
                        maxDistance = distance;
                        friendsDirection = Move.inDirection(
                                (int) Math.signum(x), (int) Math.signum(0));
                    }
                }
            }
        }

        // Find how many friends we have in close vicinity
        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {
                PlayerId playerAtLocation = context.getPlayField()[x][y];
                if (playerAtLocation != null
                        && playerAtLocation.getName().equals("Sokie")) {
                    friends++;
                }
            }
        }

        // Search for dead bodies
        for (int y = 1; y < VISION_WIDTH - 1; y++) {
            for (int x = 1; x < VISION_WIDTH - 1; x++) {

                PlayerId playerAtLocation = context.getPlayField()[x][y];
                // find a dead body
                if ((playerAtLocation != null)
                        && "DeadBody".equals(playerAtLocation.getName())) {
                    // check adjacent squares for an empty square
                    for (int yy = -1; yy <= +1; yy++) {
                        for (int xx = -1; xx <= +1; xx++) {
                            PlayerId playerNearby = context.getPlayField()[x
                                    + xx][y + yy];
                            if (playerNearby == null) {
                                int distance = max(abs(xx + x
                                        - CENTRE_OF_VISION), abs(yy + y
                                        - CENTRE_OF_VISION));
                                if (distance < deadbodyDistance) {
                                    deadbodyDistance = distance;
                                    deadBodyPosition = getAbsolutePosition(
                                            context, x + xx, y + yy);
                                    deadbodyDirection = Move.inDirection(xx + x
                                            - CENTRE_OF_VISION, yy + y
                                            - CENTRE_OF_VISION);
                                }
                            }
                        }
                    }
                }
            }
        }

        // If we have atleast 2 people close, stay or try to shoot
        // otherwise move randomly, try to find bodies and packs
        if (friends >= 2) {
            // Shoot anybody close
            if (context.getBullets() > 0) {
                int distEnemy = VISION_WIDTH;
                int distZombie = VISION_WIDTH;
                PlayerId targetEnemy = null;
                PlayerId targetZombie = null;
                for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION
                        + SHOOT_RANGE; x++) {
                    for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION
                            + SHOOT_RANGE; y++) {
                        PlayerId player = context.getPlayField()[x][y];
                        if (player != null) {
                            int dist = getDistance(x, y);
                            if (player.getName().equals("Zombie")) {
                                if (dist < distZombie) {
                                    distZombie = dist;
                                    targetZombie = player;
                                }
                            } else if (isEnemy(player.getName())
                                    && dist <= distEnemy) {
                                distEnemy = dist;
                                targetEnemy = context.getPlayField()[x][y];
                            }
                        }
                    }
                }

                if (targetZombie != null && distZombie <= 2) {
                    return new Shoot(targetZombie);
                } else if (targetEnemy != null && distEnemy <= 5) {
                    return new Shoot(targetEnemy);
                }
            }

            for (Sokie bp : myPack.values()) {
                // If someone in the pack has ammo, stay
                if (bp.getAmmo() > 0) {
                    return Move.STAY;
                }
            }

            // If there are bodies close, try to reach them
            int bodyDistance = deadbodyDistance;
            if (deadbodyDistance <= 5) {
                for (Sokie bp : myPack.values()) {
                    int distanceBody = Math.max(
                            Math.abs(deadBodyPosition.x - bp.context.getX()),
                            Math.abs(deadBodyPosition.y - bp.context.getY()));
                    if (deadbodyDistance > distanceBody) {
                        bodyDistance = distanceBody;
                    }
                }
            }
            // If we are not the closest to the body, stay
            if (bodyDistance < deadbodyDistance) {
                return Move.STAY;
            } else {
                return deadbodyDirection;
            }
        } else {
            // We try to reach our closest friend
            // If we are in danger, either fight or run
            if (areWeInDanger(context, PLAYER_X, PLAYER_Y)) {
                if (context.getBullets() > 0) {
                    int distEnemy = VISION_WIDTH;
                    int distZombie = VISION_WIDTH;
                    PlayerId targetEnemy = null;
                    PlayerId targetZombie = null;
                    for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION
                            + SHOOT_RANGE; x++) {
                        for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION
                                + SHOOT_RANGE; y++) {
                            PlayerId player = context.getPlayField()[x][y];
                            if (player != null) {
                                int dist = getDistance(x, y);
                                if (player.getName().equals("Zombie")) {
                                    if (dist < distZombie) {
                                        distZombie = dist;
                                        targetZombie = player;
                                    }
                                } else if (isEnemy(player.getName())
                                        && dist <= distEnemy) {
                                    distEnemy = dist;
                                    targetEnemy = context.getPlayField()[x][y];
                                }
                            }
                        }
                    }

                    if (targetZombie != null && distZombie <= 2) {
                        return new Shoot(targetZombie);
                    } else if (targetEnemy != null && distEnemy <= 5) {
                        return new Shoot(targetEnemy);
                    }
                } else {
                    DANGER danger = DANGER.DANGER;
                    Point position = null;
                    for (int i = -1; i < 1; i++) {
                        for (int j = -1; j < 1; j++) {
                            DANGER positionDanger = getDangerLevel(context,
                                    PLAYER_X + i, PLAYER_Y + j);
                            if (positionDanger.value < danger.value) {
                                if (canMove(context, PLAYER_X + i, PLAYER_Y + j)) {
                                    position = new Point(PLAYER_X + i, PLAYER_Y
                                            + j);
                                }
                            }
                        }
                    }

                    if (position != null) {
                        return Move.inDirection(position.x, position.y);
                    } else {
                        return Move.randomMove();
                    }
                }
            } else {
                return friendsDirection;
            }
        }
        return Move.randomMove();
    }

    private DANGER getDangerLevel(PlayerContext context, int posX, int posY) {
        DANGER danger = DANGER.SAFE;

        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {
                PlayerId playerAtLocation = context.getPlayField()[x][y];

                if (playerAtLocation != null
                        && isEnemy(playerAtLocation.getName())) {
                    int distanceToPlayer = max(abs(x - posX), abs(y - posY));
                    if (playerAtLocation.getName().equals("Zombie")) {
                        DANGER currentDanger = null;
                        if (distanceToPlayer <= 2) {
                            currentDanger = DANGER.DANGER;
                        } else if (distanceToPlayer <= 5) {
                            currentDanger = DANGER.PROBABLY_SAFE;
                        } else if (distanceToPlayer > 5) {
                            currentDanger = DANGER.SAFE;
                        }
                        if (currentDanger.value > danger.value) {
                            danger = currentDanger;
                        }
                    } else {
                        DANGER currentDanger = null;
                        if (distanceToPlayer <= 5) {
                            currentDanger = DANGER.DANGER;
                        } else if (distanceToPlayer > 5) {
                            currentDanger = DANGER.PROBABLY_SAFE;
                        }
                        if (currentDanger.value > danger.value) {
                            danger = currentDanger;
                        }
                    }
                }
            }
        }
        return danger;
    }

    private boolean isDangerous(PlayerContext context, int posX, int posY) {

        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {
                PlayerId playerAtLocation = context.getPlayField()[x][y];

                if (playerAtLocation != null
                        && isEnemy(playerAtLocation.getName())) {
                    int distanceToPlayer = max(abs(x - posX), abs(y - posY));
                    if (playerAtLocation.getName().equals("Zombie")) {
                        if (distanceToPlayer <= 2) {
                            return true;
                        }
                    } else {
                        if (distanceToPlayer <= 5) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;

    }

    // calculates absolute position, from XY in our field of view
    private Point getAbsolutePosition(PlayerContext context, int relativeX,
            int relativeY) {
        int playerX = context.getX();
        int playerY = context.getY();

        return new Point(playerX + (relativeX - PLAYER_X), playerY
                + (relativeY - PLAYER_Y));
    }

    // Gets distance on the field
    private int getDistance(int x, int y) {
        return Math.max(Math.abs(PLAYER_X - x), Math.abs(PLAYER_Y - y));
    }

    public int getAmmo() {
        return context.getBullets();
    }

    public Point getPosition() {
        Point p = new Point(context.getX(), context.getY());
        return p;
    }

    public Move getMoveDirection() {
        return moveDirection;
    }

    // Quick check for dangers around us
    private boolean areWeInDanger(PlayerContext context, int posX, int posY) {
        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {
                PlayerId playerAtLocation = context.getPlayField()[x][y];

                if (playerAtLocation != null
                        && isEnemy(playerAtLocation.getName())) {
                    int distanceToPlayer = max(abs(x - posX), abs(y - posY));
                    if (playerAtLocation.getName().equals("Zombie")) {
                        if (distanceToPlayer <= 2) {
                            return true;
                        }
                    } else {
                        if (distanceToPlayer <= 5) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    private boolean canMove(PlayerContext context, int posX, int posY) {
        PlayerId playerAtLocation = context.getPlayField()[posX][posY];
        if (playerAtLocation == null) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isEnemy(String name) {
        switch (name) {
        case "Sokie":
        case "DeadBody":
        case "GordonFreeman":
        case "EmoWolfWithAGun":
        case "HuddleWolf":
        case "ThePriest":
        case "Shotguneer":
        case "StandStill":
            return false;
        default:
            return true;
        }
    }

}

FYI, tên người chơi của bạn sẽ giống với tên của lớp bạn (trong trường hợp này là "Sokie"). Vì vậy, tôi nghi ngờ playerAtLocation.getName().equals("BetterInPacks2")có lẽ nên được playerAtLocation.getName().equals("Sokie").
James_pic

Đăng! Đó là một số mã còn sót lại trong khi tôi đang thử nghiệm các triển khai khác nhau, tôi sẽ sửa nó ngay lập tức! Cảm ơn bạn
sokie

2

Ong - Trăn

Mục thứ hai, nhưng tôi nghĩ sẽ rất vui nếu thử một thứ khác và bằng một ngôn ngữ khác.

  • Bây giờ những con ong sẽ tránh di chuyển đến cùng một vị trí.
  • Thêm 'Pythonic' bây giờ
  • Chuyển động hình xuyến được tối ưu hóa để những con ong có thể đến với nữ hoàng nhanh hơn (cảm ơn James vì ​​đã cho phép truy cập vào kích thước bảng)

Những con ong thích ở cùng nhau, vì vậy chúng chỉ định một trong những con ong còn sống là Ong chúa và lao về phía cô. Chúng sẽ đâm đối thủ trên đường đến chỗ cô, thích thịt thây ma hơn con người.

from zombie import Player, Move, Shoot, PlayerRegistry, Constants

friends = ['Bee','Waller','DeadBody','ThePriest','StandStill','Vortigaunt','EmoWolfWithAGun']
MID = Constants.CENTRE_OF_VISION
BOARDSIZE = 1
sign = lambda x: (1, -1)[x<0]
isZombie = lambda player: player and player.getName() is "Zombie"
isEnemy = lambda player: player and player.getName() not in friends
isWall = lambda player: player and (player.getName() is "DeadBody" or player.getName() is "StandStill")
distance = lambda x1,y1,x2,y2: max(distance1d(x1,x2), distance1d(y1,y2))
distance1d = lambda x1,x2: min(abs(x1-x2), BOARDSIZE - abs(x1-x2))
Bees = {}
Shot = set()
MoveTo = set()  

def getDirection(x1, x2):  
    diff = x1 - x2  
    if abs(diff) > (BOARDSIZE // 2):
        return sign(diff)
    return -sign(diff)

class Bee(Player):  
    Queen = None
    QueenBeePosition = None
    X = Y = ID = 0
    LastTurn = -1   

    def doTurn(self, context): 
        global BOARDSIZE
        self.ID = context.id.number
        self.X = context.x
        self.Y = context.y
        BOARDSIZE = context.boardSize  
        self.setQueenBee(context.gameClock)                    
        action = self.sting(context)
        if action:
            return action
        return self.moveToQueenBee(context)     

    def setQueenBee(self, turn):
        if turn != Bee.LastTurn:
            Bee.LastTurn = turn     
            MoveTo.clear() # Clear the move set on new turn
        Bees[self.ID] = turn # Report In        
        if not Bee.Queen or (Bee.Queen and Bees[Bee.Queen] < turn - 1):
            Bee.Queen = self.ID
            Bee.QueenBeePosition = (self.X, self.Y)     

    def moveToQueenBee(self, context):
        if self.ID == Bee.Queen:
            return Move.randomMove()

        dist = distance(Bee.QueenBeePosition[0], Bee.QueenBeePosition[1], self.X, self.Y)
        if dist < 4:
            return Move.randomMove()

        signX = getDirection(self.X, Bee.QueenBeePosition[0])      
        signY = getDirection(self.Y, Bee.QueenBeePosition[1])      
        walls = 0
        field = context.playField
        for (deltaX, deltaY) in [(signX,signY),(signX,0),(0,signY),(signX,-signY),(-signX,signY)]:
            player = field[MID + deltaX][MID + deltaY]
            if isWall(player):
                walls += 1
            if not player:               
                point = frozenset([self.X+deltaX,self.Y+deltaY])            
                if point not in MoveTo:
                    MoveTo.add(point)                   
                    return Move.inDirection(deltaX,deltaY)
        if walls > 2:
            return Move.randomMove()
        return Move.STAY

    def sting(self, context):      

        if context.bullets < 1:
            return      
        field = context.playField
        closestZombie,closestPlayer = None,None
        closestZombieDist,bestDist = 3,5   
        for x in range(MID - 5, MID + 5):
            for y in range(MID - 5, MID + 5):
                player = field[x][y]
                if player and not isWall(player) and player not in Shot:
                    dist = distance(MID,MID,x,y)
                    if isZombie(player) and dist < closestZombieDist:   
                        closestZombieDist = dist
                        closestZombie = player
                    elif isEnemy(player) and dist < bestDist: 
                        bestDist = dist
                        closestPlayer = player

        if closestZombie:
            Shot.add(closestZombie)
            return Shoot(closestZombie)        

        if closestPlayer:
            Shot.add(closestPlayer)
            return Shoot(closestPlayer)        

PlayerRegistry.registerPlayer("Bee", Bee())

1
Phù! Tôi đã bắt đầu lo lắng không có gì ngoài Java trong cuộc thi này.
James_pic

Vâng, và mục đầu tiên tìm kiếm trường trên toàn cầu, mà tôi nghĩ là một tính năng gọn gàng.
Moop

Một điều bạn có thể thấy hữu ích là Jython tự động tạo các getters và setters cho JavaBeans có sẵn dưới dạng các thuộc tính. Ví dụ, bạn có thể sử dụng context.gameClockchứ không phải context.getGameClock().
James_pic

@James_pic Cảm ơn vì tiền boa, không biết điều đó.
Moop

2

Ông sát thủ

Cha mẹ anh không phải là người rất tốt. Anh ta không giết người nhưng anh ta sẽ không nghĩ rằng bạn sẽ giúp anh ta sống lâu hơn. Anh ấy đối xử với mọi người như thể họ là đặc biệt và sau đó coi thường điều đó và xếp hạng bạn bằng cách anh ấy muốn bạn gần gũi, anh ấy muốn bạn chết bao nhiêu và quan trọng là bạn đối với tình huống hiện tại.

Như tôi biết rất nhiều điều này được giấu ở đây tôi sẽ giải thích một số. Anh ta thường không bao giờ giết những kẻ có thể giết chết các mối đe dọa của mình trước khi anh ta phải làm thế vì họ không phải là mục tiêu của anh ta. Anh ta sẽ nuôi sống một số người không bao giờ bắn. Với một ngoại lệ, anh ta sẽ giết bạn nếu bạn hiện đang giết anh ta. Anh ta thích tường ở các vị trí mà không bị ép buộc vào mã. Anh ta là Fox phobic và một kẻ hèn nhát. Anh âu yếm với Huddlewolves và dựng lên với Wallers. Anh ta hiện đang tiến về phía những người cùng nhóm (như Sokie mặc dù Sokie bắn anh ta không thương tiếc). Nash nên yêu anh vì những ưu tiên của anh khiến một nhà lý thuyết trò chơi khóc. Tuy nhiên, khách hàng của anh ta dường như rất cuồng nhiệt khi anh ta giết linh mục, người ngoài hành tinh và người mới đến (mặc dù anh ta tha thứ cho bạn vào thứ sáu hoặc thứ bảy nếu bạn không giết anh ta ... chủ nhật là quá muộn). Xin lỗi nếu tôi quên bất cứ ai khác.

package player;
import zombie.*;
import static zombie.Constants.*;
//import static java.lang.Math.*;

public class Jack implements Player {
    @Override
    public Action doTurn(PlayerContext context) {
        int[] Ideal = {1,5,8,7,2,2,7,2,1,5,1,2,1,1,7,2,7,7,7,0,2,3,1,7};
        int[] Threat = {1,4,8,8,1,1,7,1,2,2,2,1,2,0,6,2,6,6,6,1,1,2,6,6};
        int[] Importance = {1,2,4,4,1,1,1,1,3,1,3,1,3,3,1,2,1,1,1,10,2,2,3,2};

        PlayerId Target = context.getId();
        int[][] Bob = {{800-2*Math.max(0,context.getGameClock()),400-Math.max(0,context.getGameClock()),800-Math.max(0,context.getGameClock())},{0,0,0},{0,0,0}};
        double maxDanger=0;
        int zombies=0;

        for (int x = -8; x < +8; x++) {
        for (int y = -8; y < +8; y++) {
            PlayerId playerAtLocation = context.getPlayField()[x + CENTRE_OF_VISION][y + CENTRE_OF_VISION];
            if (playerAtLocation != null && x*y+x+Math.abs(y) != 0){
                if (Math.abs(x)*Math.abs(y)==1 || Math.abs(x) + Math.abs(y)==1){
                    Bob[x+1][y+1]-=100000;
                }
                int dist = Math.max(Math.abs(x),Math.abs(y));
                int Ident = Dats(playerAtLocation);
                double Danger = (Threat[Ident]-dist)*Importance[Ident];
                if(Ident==1 && dist<Threat[Ident]){
                    zombies++;
                    if(context.getPlayField()[TFSAE(x)-1 + CENTRE_OF_VISION][TFSAE(y) -1+ CENTRE_OF_VISION]!=null){ 
                    Danger=0;
                                } else if(dist==2){Danger+=4;} 
                }
                if(Danger>maxDanger && dist<6){
                    maxDanger=Danger;
                    Target=playerAtLocation;
                }
                if(dist != Ideal[Ident]){

                    Bob[TFSAE(x)][TFSAE(y)] += Math.round(200*Importance[Ident]/(dist-Ideal[Ident]));

                    if(TFSAE(x) ==1) {
                        Bob[0][TFSAE(y)] += Math.round(100*Importance[Ident]/(dist-Ideal[Ident]));
                        Bob[2][TFSAE(y)] += Math.round(100*Importance[Ident]/(dist-Ideal[Ident]));
                    } else {
                        Bob[1][TFSAE(y)] += Math.round(100*Importance[Ident]/(dist-Ideal[Ident]));
                    }

                    if(TFSAE(y) ==1) {
                        Bob[TFSAE(x)][0] += Math.round(100*Importance[Ident]/(dist-Ideal[Ident]));
                        Bob[TFSAE(x)][2] += Math.round(100*Importance[Ident]/(dist-Ideal[Ident]));
                    } else {
                        Bob[TFSAE(x)][1] += Math.round(100*Importance[Ident]/(dist-Ideal[Ident]));
                    }
                }
            }
        }}

        if (context.getBullets()>1 && maxDanger>0){
            return new Shoot(Target);
        } else if (context.getBullets()==1 && zombies>3){
            return new Shoot(context.getId());
        } else if (context.getBullets()==1 && maxDanger>7){
            return new Shoot(Target);
        }

        int Xmax=0;
        int Ymax=0;

        for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            if (Bob[x][y]>=Bob[Xmax][Ymax]){
                Xmax=x;
                Ymax=y;
            }
        }}
        return Move.inDirection(Xmax-1, Ymax-1);

    }

    private int Dats (PlayerId WhoDat){
        switch (WhoDat.getName()){
            case "DeadBody": return 0;
            case "Zombie": return 1;
            case "Fox": return 2;
            case "Coward": return 3;
            case "Shotguneer": return 4;
            case "HuddleWolf": return 5;
            case "Sokie": return 6;
            case "GordonFreeman": return 7;
            case "Vortigaunt": return 8;
            case "SuperCoward": return 9;
            case "StandStill": return 10;
            case "JohnNash": return 11;
            case "MoveRandomly": return 12;
            case "Waller": return 13;
            case "HideyTwitchy": return 14;
            case "Bee": return 15;
            case "ZombieHater": return 16;
            case "ZombieRightsActivist": return 17;
            case "Gunner": return 18;
            case "EmoWolfWithAGun": return 19;
            case "Jack": return 20;
              case "SOS": return 21;
              case "SunTzu": return 22;
            default: return 23;
        }

    }
    private int TFSAE(int TBN){
        if(TBN==0){return 1;
        } else if(TBN>0){return 2;}

        return 0;
    }
}

Ồ vâng, Jack thực sự đã cứu viên đạn cuối cùng cho chính mình. Nếu có nhiều hơn một số zombie nhất định xung quanh anh ta và anh ta còn một viên đạn, anh ta sẽ tự sát để ngăn chặn sự lây lan. Vì không thành vấn đề nếu tôi giành chiến thắng (tôi không thể cho mình tiền thưởng), tôi muốn một số nhân vật có chức năng đó.
kaine

@James_pic Điều này hoạt động trong trò chơi (mặc dù phiên bản trước tôi đã nhân bản vài ngày trước). Nó nên hoạt động. Nếu nó không cho tôi biết. Nếu không vào chủ nhật, hãy xóa nó.
kaine

Nó dường như hoạt động tốt trong phiên bản hiện tại của mã. Tôi sẽ đưa nó vào một bài kiểm tra sau hôm nay.
James_pic

Một lần nữa, tôi không biết làm thế nào mục này hoạt động. Nếu bất cứ ai khác đã gửi nó, tôi cho rằng nó không hoạt động, nhưng vì Shotguneer hiện đang đánh bại mục tốt nhất của tôi, tôi thực sự tò mò muốn xem những gì nó thực sự làm.
James_pic

Khá phức tạp và, tôi giả sử, quản lý mối đe dọa / khoảng cách / ưu tiên đã xử lý.
Thaylon

1

SOS (Bắn vào tầm nhìn)

package player;

import zombie.*;
import static zombie.Constants.*;
import static java.lang.Math.*;

public class SOS implements Player {

    @Override
    public Action doTurn(PlayerContext context) {
        if (context.getBullets() > 0) {
            for (PlayerId player: context.shootablePlayers()) {
                switch(player.getName()) {
                    case "Gunner":
                    case "Zombie":
                    case "ZombieRightsActivist":
                        return new Shoot(player);
                    default:
                        break;
                }
            }
        }
        Move bestDirection = Move.NORTH;
        int bestDistance = Integer.MAX_VALUE;
        for (int x = 0; x < VISION_WIDTH; x++) {
            for (int y = 0; y < VISION_WIDTH; y++) {
                int distance = max(abs(x - CENTRE_OF_VISION), abs(y - CENTRE_OF_VISION));
                PlayerId playerAtLocation = context.getPlayField()[x][y];
                if (playerAtLocation != null
                        && !(playerAtLocation.getName().equals("Zombie"))
                        && !(playerAtLocation.getName().equals("Gunner"))
                        && !(playerAtLocation.getName().equals("ZombieRightsActivist"))
                        && !(playerAtLocation.getName().equals("ZombieHater"))
                        && !(playerAtLocation.equals(context.getId()))
                        && distance < bestDistance) {
                    bestDistance = distance;
                    bestDirection = Move.inDirection(x - CENTRE_OF_VISION, y -CENTRE_OF_VISION);
                }
            }
        }
        return bestDirection;
    }
}

1

John Nash - Javascript

Quyết định có bắn ai hay không thực chất là vấn đề nan giải của tù nhân. Nếu bạn cho rằng đối thủ của bạn đã quyết định, thì lựa chọn tốt nhất là luôn bắn họ. Tuy nhiên, nếu đối thủ của bạn sẽ quyết định những việc cần làm dựa trên những gì họ nghĩ bạn sẽ làm, thì lựa chọn tốt nhất là rời bỏ họ và có lẽ họ cũng sẽ làm như vậy.

John Nash chỉ bắn "khối" - những kẻ thù đã quyết định. Đó là, anh ta bắn những kẻ thù luôn bắn, hoặc những kẻ thù không bao giờ bắn. Anh ta để đối thủ một mình nếu họ có logic phức tạp hơn.

Khi anh ta không bắn, anh ta nhặt rác hoặc đi về phía Nam.

var Constants = Packages.zombie.Constants
var Shoot = Packages.zombie.Shoot
var Move = Packages.zombie.Move
var Player = Packages.zombie.Player
var PlayerRegistry = Packages.zombie.PlayerRegistry

function mkSet() {
    var s = {}
    for (var i = 0; i < arguments.length; i++) {
        s[arguments[i]] = true
    }
    return s
}

var chumps = mkSet(
                "GordonFreeman",
                "HideyTwitchy",
                "Gunner",
                "MoveRandomly",
                "StandStill",
                "ThePriest",
                "Vortigaunt",
                "ZombieHater",
                "ZombieRightsActivist",
                "Bee",
                "Zombie",
                "SuperCoward"
              )

function dist(x, y) {
    return Math.max(Math.abs(x - Constants.CENTRE_OF_VISION), Math.abs(y - Constants.CENTRE_OF_VISION))
}

function range(width, offset) {
    var x = []
    for (var i = -width; i <= width; i++) {
        for (var j = -width; j <= width; j++) {
            if (i != 0 || j != 0) x.push([i + offset,j + offset])
        }
    }
    return x
}

function JohnNash() {
    var looted = {}
    this.doTurn = function(context) {
        var field = context.getPlayField()
        // Save looted bodies
        range(1, Constants.CENTRE_OF_VISION).forEach(function(p) {
            var x = p[0], y = p[1]
            var playerId = field[x][y]
            if (playerId && playerId.getName() == "DeadBody") {
                looted[playerId] = true
            }
        })

        // Shoot any nearby chumps
        if (context.getBullets() > 0) {
            var shootableIterator = context.shootablePlayers().iterator();
            while (shootableIterator.hasNext()) {
                var shootable = shootableIterator.next()
                if (chumps[shootable.getName()]) return new Shoot(shootable)
            }
        }

        // Helper function - everyone loves closures
        function moveTowards(x, y) {
            var tryMove = Move.inDirection(
                    x - Constants.CENTRE_OF_VISION,
                    y - Constants.CENTRE_OF_VISION
            )
            if (!(field[Constants.CENTRE_OF_VISION + tryMove.x][Constants.CENTRE_OF_VISION + tryMove.y])) {
                return tryMove
            } else {
                // If your path is blocked, take a random move
                return Move.randomMove()
            }
        }

        // Loot
        var bestX, bestY, bestDist = Infinity
        range(Constants.VISION_RANGE, Constants.CENTRE_OF_VISION).forEach(function(p) {
            var x = p[0], y = p[1]
            var playerId = field[x][y]
            if (playerId
                    && playerId.getName() == "DeadBody"
                    && !looted[playerId]
                    && dist(x, y) < bestDist) {
                bestDist = dist(x,y)
                bestX = x
                bestY = y
            }
        })

        if (bestDist < Infinity) {
            return moveTowards(bestX, bestY)
        }
        else return Move.SOUTH
    }
}

PlayerRegistry.registerPlayer("JohnNash", new Player(new JohnNash()))

MoveRandomly có làm gì ngoài việc di chuyển ngẫu nhiên không?
Thaylon

@Thaylon Không, nó thực hiện chính xác những gì nó nói trên tin. Moop bao gồm nó trong một yêu cầu kéo anh gửi cho dự án. Mục đích chính của yêu cầu kéo là để cải thiện đầu ra HTML, nhưng cũng bao gồm MoveRandomly và tôi đoán rằng tôi sẽ đưa MoveRandomly vào thử nghiệm để xem điều gì xảy ra trong thử nghiệm.
James_pic

Tôi đã lấy bản mới nhất từ ​​github của bạn và không thể lấy john-nash.js để biên dịch
Moop

@moop Mình thấy cũng thế.
Pureferret

Đã sửa nó. Tôi chỉ thử nghiệm nó với Java 7. Nó cũng sẽ hoạt động trong 8 giờ
James_pic

1

SunTzu cố gắng trở thành chiến thuật và tìm những điểm an toàn trên lưới để di chuyển đến. Nhưng như hiện tại, anh ta chỉ là một công việc đang tiến triển.

Vì vậy, chúng ta có thể biết rằng có năm yếu tố cần thiết để chiến thắng:
1. Anh ta sẽ chiến thắng ai biết khi nào nên chiến đấu và khi nào không nên chiến đấu.
2. Anh ta sẽ chiến thắng ai biết cách xử lý cả lực lượng vượt trội và kém hơn.
3. Anh ta sẽ chiến thắng mà quân đội của họ được hoạt hình bởi cùng một tinh thần trong tất cả các cấp bậc của nó.
4. Anh ta sẽ chiến thắng ai, chuẩn bị sẵn sàng, chờ đợi kẻ thù không chuẩn bị.
5. Anh ta sẽ chiến thắng người có năng lực quân sự và không bị can thiệp bởi chủ quyền.

package player;

import static zombie.Constants.CENTRE_OF_VISION;
import static zombie.Constants.SHOOT_RANGE;
import static zombie.Constants.VISION_RANGE;

import java.awt.Point;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

import zombie.Action;
import zombie.Move;
import zombie.Player;
import zombie.PlayerContext;
import zombie.PlayerId;
import zombie.Shoot;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Table.Cell;
import com.google.common.collect.TreeBasedTable;

    public class SunTzu implements Player {
        private TreeBasedTable<Integer, Integer, Integer> dangerZone;
        private final static int IN_ENEMY_RANGE = 5;
        private static final int IN_LOOTED_RANGE = 4;
        private static final int FULL_MAGAZINE = 10;
        private static final int IN_ZOMBIE_RANGE = 10;
        private static final int NUM_PLAYERS = 40;
        private LinkedHashSet<Point> safeSpots;
        private PlayerId[][] localAreas;
        private Set<PlayerId> looted= new HashSet<>(50*NUM_PLAYERS);
        private int ammo;
        PlayerId biggestThreat;
        private Set<PlayerId> shootable;
        private PlayerId myId;
        @SuppressWarnings("unused")
        @Override
        public Action doTurn(PlayerContext context) {
            ammo = context.getBullets();
            int gameTurn =context.getGameClock();
            int boardSize = context.getBoardSize();
            myId = context.getId();
            localAreas = context.getPlayField();
            dangerZone = TreeBasedTable.create();
            shootable = context.shootablePlayers();
            updateAdjacentBodyState();

            for (int x = CENTRE_OF_VISION - SHOOT_RANGE; x <= CENTRE_OF_VISION + SHOOT_RANGE; x++) {
                for (int y = CENTRE_OF_VISION - SHOOT_RANGE; y <= CENTRE_OF_VISION + SHOOT_RANGE; y++) {
                    PlayerId playerId = localAreas[x][y];
                    if (playerId != null) {
                        calculateDangerZone(x,y,playerId);
                    }
                }
            }
            Action myAction = null;
            Iterator<Point> pIt = safeSpots.iterator();
            if (ammo>0&&!pIt.hasNext()&&getBiggestThreat()!=null) {
                return new Shoot(getBiggestThreat());
            } else if (pIt.hasNext()){
                Point p=pIt.next();
                return Move.inDirection(p.x, p.y);
            }else{
                return Move.randomMove();
            }
        }

        private PlayerId getBiggestThreat() {
            return biggestThreat==null?shootable.iterator().next():biggestThreat;
        }

        public void setBiggestThreat(PlayerId biggestThreat) {
            this.biggestThreat = biggestThreat;
        }
        private void updateAdjacentBodyState() {

            for( int x = -1; x <= 1; x++ ) {
                for( int y = -1; y <= 1; y++ ) {
                    PlayerId adjPlayerId = localAreas[CENTRE_OF_VISION+x][CENTRE_OF_VISION+y];
                    if( adjPlayerId != null && (!looted.contains(adjPlayerId) && adjPlayerId.getName().equals("DeadBody"))) {
                        looted.add(adjPlayerId);
                    }       
                }
            }
        }

        private void calculateDangerZone(int x, int y, PlayerId playerId) {
            deriveDanger(playerId, x, y);
            safeSpots = getSafeSpots();
        }

        @SuppressWarnings("rawtypes")
        private LinkedHashSet<Point> getSafeSpots() {
            LinkedHashSet<Point> safeSpots = new LinkedHashSet<>();
            TreeSet<Cell> spots = new TreeSet<>(cellValueComparator());
            for (Cell<Integer, Integer, Integer> cell : dangerZone.cellSet()) {
                spots.add(cell);
            }
            final Cell safeCell = spots.isEmpty()?null:Collections.min(spots,cellValueComparator());
            Function<Cell,Point> pointFromCell = new Function<Cell,Point>() {
                public Point apply(final Cell arg0) {return new Point((int)arg0.getRowKey(), (int)arg0.getColumnKey());};
            };

            if (safeCell!=null) {
                safeSpots.addAll(Collections2.transform(
                        Collections2.filter(spots, sameCellValuePredicate(safeCell)), pointFromCell));
            }
            return safeSpots;
        }

        @SuppressWarnings("rawtypes")
        private Predicate<Cell> sameCellValuePredicate(final Cell safeCell) {
            return new Predicate<Cell>() {

                @Override
                public boolean apply(Cell arg0) {
                    return (arg0.getValue() == safeCell.getValue());
                }
            };
        }

        @SuppressWarnings("rawtypes")
        private Comparator<Cell> cellValueComparator() {
            return new Comparator<Cell>() {
                @Override
                public int compare(Cell o1, Cell o2) {
                    return (int)o1.getValue()- (int)o2.getValue();
                }
            };
        }

        private void deriveDanger(PlayerId playerId, int x, int y) {
            switch (playerId.getName()) {
            case "Gunner":
            case "Fox":
            case "HideyTwitchy":
            case "Shotguneer":
            case "ZombieRightsActivist":
            case "ZombieHater":
            case "SuperCoward":
            case "Sokie":
                updateDangerZoneWithEnemy(x, y);
                break;
            case "DeadBody":
            case "Zombie":
                updateDangerZoneWithBodies(x,y);
                break;
            default:
                break;
            }
        }

        private void updateDangerZoneWithBodies(int x, int y) {
            int dangerLevel=0;
            if(localAreas[x][y].getName().equalsIgnoreCase("Zombie")){
                dangerLevel = IN_ZOMBIE_RANGE;
            }
            else if(looted.contains(localAreas[x][y])){
                dangerLevel = IN_LOOTED_RANGE;
            }else{
                dangerLevel = Math.min(-1,-FULL_MAGAZINE+ammo);
            }
            for (int i = x-1; i < x+1; i++) {
                for (int j = y-1; j < y+1; j++) {
                    Integer previousDangerLevel = dangerZone.get(i, j) ;
                    int currentDangerLevel = dangerLevel;
                    if (previousDangerLevel != null) {
                        currentDangerLevel = previousDangerLevel+dangerLevel;
                    } 
                    dangerZone.put(x, y, currentDangerLevel);
                }
            }
        }

        private void updateDangerZoneWithEnemy(int x, int y) {
            int dangerLevel = IN_ENEMY_RANGE;
            playerShieldFound:
                for (int i = Math.max(x-SHOOT_RANGE, 0); i < Math.min(SHOOT_RANGE+x,VISION_RANGE); i++) {
                    for (int j = Math.max(y-SHOOT_RANGE, 0); j < Math.min(SHOOT_RANGE+y,VISION_RANGE); j++) {
                        int cardinalityFactor = (i+1)+(j+1);
                        Integer previousDangerLevel = dangerZone.get(i, j);
                        int currentDangerLevel = dangerLevel*cardinalityFactor;
                        PlayerId enemy = localAreas[x][y];
                        PlayerId target = localAreas[i][j];
                        if (target!=null) {
                            if (target != enemy) {
                                break playerShieldFound;
                            } else if (target.equals(myId)) {
                                setBiggestThreat(enemy);
                            }
                        }
                        if (previousDangerLevel != null) {
                            currentDangerLevel = Math.max(previousDangerLevel, dangerLevel);
                        } 
                        dangerZone.put(i, j, currentDangerLevel );
                    }
                }
        }

    }

Các vấn đề hiện tại là khu vực nguy hiểm không được tạo ra đúng cách và tôi không nghĩ lớn nhất. Điều này đang được xác định chính xác.


+1 để sử dụng các lớp từ Guava. Tôi đã quên rằng tôi đã sử dụng nó trong chương trình điều khiển, nhưng nó có rất nhiều lớp hữu ích cho chính xác loại này.
James_pic

1
@james_pic tbh, tôi sẽ bán hết cho tương đương Apache. Cảm thấy như tôi đã tạo ra một hàm băm của nó.
Pureferret

Vì nó được xây dựng với Maven, tôi có thể thêm bất kỳ phụ thuộc hợp lý nào bạn có thể muốn, nếu điều đó làm cho mọi việc dễ dàng hơn. Nếu bạn muốn sử dụng Bộ sưu tập Commons, hãy dùng nó.
James_pic

Vấn đề là, @james_pic Tôi hầu như không có nó để xây dựng với maven vì tôi không thực sự hiểu nó ... Tôi muốn làm việc với những gì người khác có nhưng làm được nhiều việc hơn.
Pureferret

1

Tyzoid - robot hơi ngu ngốc của tôi

package player;

import java.util.ArrayList;

import zombie.Action;
import zombie.Move;
import zombie.Player;
import zombie.PlayerContext;
import zombie.PlayerId;
import zombie.Shoot;

public class Tyzoid implements Player {
    private static final int minPathDistance = 7;
    private static final int pathLength = 10;
    private static final boolean debug = false;
    private static final int max_iterations = 5000;

    private int current_iterations = 0;

    private class Situation {
        public int hostiles = 0;
        public int scores[][] = new int[21][21];
        public ArrayList<Coordinate> path = new ArrayList<Coordinate>();
        public int distanceToHostile = 10;
        public Coordinate nearestHostile = new Coordinate(0,0);
        public boolean seriousHostile = false;

        // Minimum path score allowed to move under normal circumstances
        public int pathScore = -40;

        public int bulletsLeft = 0;

        public Situation(){
            path.add(new Coordinate(10,10));
        }
    }

    public class Coordinate {
        public int x = 0;
        public int y = 0;

        public Coordinate(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    @Override
    public Action doTurn(PlayerContext context) {
        try {
            Situation currentSituation = this.evaluateSituation(context);
            return this.makeDecision(currentSituation, context);
        } catch (Exception e) {
            if (debug) e.printStackTrace();
            return Move.STAY;
        }
    }

    private Situation evaluateSituation(PlayerContext context) {
        Situation situation = new Situation();

        for (int i = 0; i < 21; i++) {
            for (int j = 0; j < 21; j++) {
                situation.scores[i][j] = -3;
            }
        }

        situation.bulletsLeft = context.getBullets();

        PlayerId[][] visibleBoard = context.getPlayField();

        for (int bx = 0; bx < visibleBoard.length; bx++) {
            for (int by = 0; by < visibleBoard[bx].length; by++) {
                if (visibleBoard[bx][by] == null) {
                    continue;
                }

                if (this.isHostile(visibleBoard[bx][by].getName(), false)) {
                    situation.hostiles++;

                    this.hostileDetected(situation, bx, by, context);
                } else if (visibleBoard[bx][by].getName().equals("DeadPlayer")) {
                    this.friendlyDetected(situation, bx, by);
                    // OVER 9000!!! (there's an obstacle)
                    situation.scores[bx + 2][by + 2] = -9001;
                }
            }
        }

        return situation;
    }

    private Action makeDecision(Situation currentSituation, PlayerContext context) {
        if ((currentSituation.distanceToHostile < 3 || currentSituation.seriousHostile) && currentSituation.bulletsLeft > 0){
            // Shoot! (And possibly create opening!)
            PlayerId[][] visibleBoard = context.getPlayField();

            if (debug) System.out.println("Shooting!");

            return new Shoot(visibleBoard[currentSituation.nearestHostile.x-2][currentSituation.nearestHostile.y-2]);
        }

        if (currentSituation.hostiles > 6) {
            // Code red: get out of here! Trample over hostiles if necessary.
            // Guarantee path will generate, without hitting anything dead.
            currentSituation.pathScore = -9000;
        }

        findSafePath(currentSituation);

        Coordinate next = currentSituation.path.get(0);

        if (next.x == 10 && next.y == 10){
            if (debug) System.out.println("Staying Put.");
            return Move.STAY;
        }

        if (debug) System.out.println("Moving!");

        return Move.inDirection(next.x-2, next.y-2);
    }

    private void findSafePath(Situation currentSituation) {
        int x = 10;
        int y = 10;

        // Since we have a finite number of tiles, and we won't consider
        // backtracking, Let's consider every possible path to optimize the
        // safest path.

        current_iterations = 0;

        pathIteration(currentSituation, new ArrayList<Coordinate>(), x, y, 0);
    }

    private void pathIteration(Situation s, ArrayList<Coordinate> currentPath, int x, int y, int steps) {
        // If we've reached an end state,
        // Update situation if the currentPath has a higher (less negative) score than the current path.
        // As well as if we moved the minimum amount

        // Compute Score
        int score = 0;
        for (Coordinate c : currentPath) {
            score += s.scores[c.x][c.y];
        }

        int distanceTraveled = (Math.abs(10 - x) + Math.abs(10 - y));

        // Return if the currentPath has a lower score than the current path.
        if (score < s.pathScore || s.pathScore == 0 || current_iterations > max_iterations) return;

        if (debug) System.out.println("debug: step " + steps + " (" + score + " : " + s.pathScore + ") Distance: " + distanceTraveled);

        // Prevent my algorithm from blowing up the whole works
        current_iterations++;

        if (steps == pathLength) {
            if (distanceTraveled >= minPathDistance) {
                if (score > s.pathScore) {
                    s.path = currentPath;
                    s.pathScore = score;
                }
            }

            return;
        }

        ArrayList<Coordinate> searched = new ArrayList<Coordinate>();
        for (int index = 0; index < 9; index++){
            int minx = 0, miny = 0;
            int minscore = -1000;

            for (int i = -1; i < 2; i++) {
                for (int j = -1; j < 2; j++) {
                    if (searched.contains(new Coordinate(x+i, y+j)) || currentPath.contains(new Coordinate(x+i, y+j))){
                        continue;
                    }

                    if (steps > 1){
                        Coordinate c0 = currentPath.get(steps-2);
                        Coordinate c1 = currentPath.get(steps-1);

                        int dx = c1.x-c0.x;
                        int dy = c1.y-c0.y;

                        // Disable turning more than 45 degrees
                        if (dy != j && dx != i) continue;
                    }

                    if (s.scores[x+i][y+j] > minscore){
                        minx = x+i;
                        miny = y+j;
                        minscore = s.scores[x+i][y+j];
                    }
                }
            }

            if (!currentPath.contains(new Coordinate(minx, miny))) {
                ArrayList<Coordinate> newPath = (ArrayList<Coordinate>) currentPath.clone();
                newPath.add(new Coordinate(minx, miny));
                pathIteration(s, newPath, minx, miny, steps + 1);
            }

            searched.add(new Coordinate(minx, miny));
        }
    }

    private void hostileDetected(Situation seriousSituation, int bx, int by, PlayerContext context) {
        boolean verySerious = false;
        if (this.isHostile(context.getPlayField()[bx][by].getName(), true) && context.shootablePlayers().contains(context.getPlayField()[bx][by])){
            seriousSituation.seriousHostile = true;
            verySerious = true;
        }

        for (int i = -4; i < 5; i++) {
            for (int j = -4; j < 5; j++) {
                // Prevent from overflowing the path matrix.
                if (i + bx + 2 < 0 || i + bx + 2 > 20 || j + by + 2 < 0 || j + by + 2 > 20) continue;

                int separationLevels = Math.max(Math.abs(i), Math.abs(j));
                seriousSituation.scores[bx + i + 2][by + j + 2] += separationLevels*2 - 10;
            }
        }

        int distanceToHostile = Math.abs(10 - (bx + 2)) + Math.abs(10 - (by + 2));
        if ((distanceToHostile < seriousSituation.distanceToHostile && !seriousSituation.seriousHostile) || verySerious){
            seriousSituation.nearestHostile = new Coordinate(bx + 2, by + 2);
            seriousSituation.distanceToHostile = distanceToHostile;
        }
    }

    private void friendlyDetected(Situation lessBleakSituation, int bx, int by) {
        for (int i = -4; i < 5; i++) {
            for (int j = -4; j < 5; j++) {
                // Prevent overflowing the path matrix.
                if (i + bx < 0 || i + bx > 20 || j + by < 0 || j + by > 20) continue;

                int separationLevels = Math.max(Math.abs(i), Math.abs(j));
                lessBleakSituation.scores[bx + i + 2][by + j + 2] += 4 - separationLevels;
            }
        }
    }

    private boolean isHostile(String name, boolean serious){
        // Generated from a list of players who shot me during testing.
        // If anyone adds me as a 'friendly', I'd be happy to reciprocate.
        switch(name){
            case "Bee":
            case "Coward":
            case "Fox":
            case "Gunner":
            case "HideyTwitchy":
            case "Sokie":
            case "ZombieHater":
            case "ZombieRightsActivist":
                return true;
            default:
                return (!serious && name.equals("Zombie")); // Zombies don't shoot
        }
    }
}

Tôi e rằng bạn đã quá muộn để có cơ hội chiến thắng, nhưng nếu tôi có cơ hội sau này, tôi sẽ thực hiện thêm một lần nữa với mục nhập của bạn, để xem giá vé của bạn như thế nào.
James_pic

Vâng, tôi đã đánh giá bài nộp của mình dựa trên thời gian chờ của tiền thưởng: / - Tôi không mong đợi được gần với việc mặc dù ... bot không tốt lắm.
Tyzoid

1
Xin lỗi về điều đó, tiền thưởng đã được thiết lập để hết thời gian vào ngày sau ngày đáo hạn đã nêu vào ngày 3 tháng 8 để tôi có thể trao giải vào ngày hôm nay, ngày 4 tháng 8. (người ta nói rằng bạn bắn tất cả những người bắn một trong hai nhân vật của tôi vì vậy tôi nên root hệ thống Tyzoid.)
kaine
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.