บันทึกสัญลักษณ์แสดงหัวข้อสุดท้ายด้วยตัวคุณเอง


51

การประกวดสิ้นสุดลงแล้ว ขี้ขลาดเป็นผู้ชนะ คุณสามารถรับชมการแข่งขันที่ผ่านมาที่นี่

ทันใดนั้นซอมบี้ก็ปรากฏขึ้น! โอ้โห!

ในการท้าทายที่ท้าทายนี้คุณต้องสร้างบอทเพื่อเอาชีวิตรอดจากซอมบี้วิบัติ หรืออย่างน้อยก็ค้างไว้ให้นานที่สุด

ในช่วงเริ่มต้นของเกม 50 ตัวอย่างของแต่ละรายการจะถูกวางแบบสุ่มในพื้นที่เล่นขนาดใหญ่แบบวงแหวน - นั่นคือดูเหมือนว่าจะเป็นสี่เหลี่ยมจัตุรัส แต่ล้อมรอบ ขนาดของพื้นที่เล่นจะแตกต่างกันไปขึ้นอยู่กับจำนวนของรายการ แต่ในขั้นต้น 6% ของสี่เหลี่ยมจะถูกครอบครอง ผู้แข่งขันแต่ละคนเริ่มด้วยกระสุน 3 นัด

ในตอนต้นของแต่ละตาซอมบี้จะเพิ่มขึ้นจากพื้นดินในตำแหน่งสุ่มทำลายสิ่งที่อยู่เหนือมัน ผู้เล่นที่อยู่ถัดจากซอมบี้ในช่วงเริ่มเทิร์นจะกลายเป็นซอมบี้

สำหรับผู้เล่นที่มีชีวิตแต่ละคนรหัสของพวกเขาจะถูกเรียก จะได้รับวัตถุPlayerContextที่มีข้อมูลเกี่ยวกับสถานะปัจจุบันและสภาพแวดล้อมของพวกเขา ผู้เล่นแต่ละคนสามารถมองเห็น 8 สี่เหลี่ยมในทิศทางใด ๆ

ผู้เล่นจะต้องเลือกที่จะย้าย (เข้าพักยังคงเป็นความเคลื่อนไหวที่ถูกต้อง) โดยกลับหรือยิงคนที่อยู่ใกล้เคียงหรือผีดิบโดยกลับMove Shootปืนของคุณมีช่วงสูงสุด 5 กำลังสอง เมื่อคุณอยู่ในขอบเขตปืนของคุณคุณสามารถยิงตัวเองได้ถ้าคุณมีกระสุนเหลือ หากผู้เล่นสองคนยิงกันพวกเขาทั้งสองตาย

หากผู้เล่นสองคนพยายามที่จะย้ายไปยังจัตุรัสเดียวกันพวกเขาจะล้มเหลวและจะกลับไปที่จัตุรัสที่พวกเขาเริ่มต้นจาก หากยังมีข้อขัดแย้งอยู่จะมีการทำซ้ำจนกว่าจะไม่มีความขัดแย้งซึ่งอาจหมายถึงทุกคนกลับมาสู่จุดเริ่มต้น

หากผู้เล่นเสียชีวิตจากกระสุนปืนร่างกายที่ตายแล้วจะยังคงอยู่และสร้างสิ่งกีดขวางถาวร สัญลักษณ์แสดงหัวข้อย่อยใด ๆ ที่พวกเขาถืออยู่ยังคงอยู่ในคนของพวกเขาและสามารถถูกผู้เล่นในสี่เหลี่ยมที่อยู่ติดกัน หากมีผู้เล่นหลายคนที่ครอบครองพื้นที่สี่เหลี่ยมที่อยู่ติดกับศพแล้วกระสุนจะถูกใช้ร่วมกันระหว่างพวกเขา แต่ส่วนที่เหลือจะหายไป

หากผู้เล่นกลายเป็นซอมบี้แล้วกระสุนของพวกเขาจะหายไป ซอมบี้จะเดินไปหาผู้เล่นที่มีชีวิตอยู่ใกล้ ๆ อย่างไร้เหตุผล

ผลงานจะถูกทำคะแนนว่าผู้เล่นที่รอดชีวิตมานานที่สุดจะอยู่รอดได้นานแค่ไหน

รายการ

โปรแกรมการควบคุมที่มีอยู่ในhttps://github.com/jamespic/zombies mvn compile exec:javaเพียงแค่โคลนมันและทำงาน

จึงจะมีสิทธิ์เข้าร่วมรายการจะต้องเขียนในภาษา JVM จะต้องพกพาได้และจะต้องสามารถสร้างจาก Maven โดยไม่มีการตั้งค่าพิเศษ นี่คือเพื่อให้แน่ใจว่าคู่แข่งไม่จำเป็นต้องติดตั้งสภาพแวดล้อมแบบรันไทม์หลายแห่งเพื่อทดสอบบอทกับคู่แข่ง

รายการตัวอย่างมีให้บริการในภาษาต่อไปนี้:

หากคุณต้องการแข่งขันในภาษาที่ไม่ได้อยู่ในรายการคุณสามารถโพสต์ความคิดเห็นที่ร้องขอและฉันจะตรวจสอบความเป็นไปได้ของการรวมภาษาที่คุณเลือกไว้ในโปรแกรมควบคุม หรือถ้าคุณใจร้อนคุณสามารถส่งคำขอดึงไปยังโปรแกรมควบคุม

หนึ่งอินสแตนซ์เท่านั้น (ในความหมายของคำว่า Java) จะถูกสร้างขึ้นสำหรับแต่ละรายการ อินสแตนซ์ Java นี้จะถูกเรียกหลายครั้งต่อเทิร์น - หนึ่งครั้งสำหรับผู้เล่นที่รอดชีวิตแต่ละคน

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);
}

กฎเพิ่มเติม

แต่ละรายการจะต้องมีชื่อที่ไม่ซ้ำกันเพื่อให้สามารถทำงานได้อย่างถูกต้องกับโปรแกรมควบคุม

คอมเมนต์ไม่ควรพยายามที่จะยุ่งเกี่ยวกับผู้เข้าแข่งขันรายอื่นหรือด้วยโปรแกรมควบคุมหรือใช้ประโยชน์จากสภาพแวดล้อมแบบรันไทม์เพื่อ "ทำลายกำแพงที่สี่" และได้รับผลประโยชน์ที่ไม่สามารถหาได้ในการเปิดเผยซอมบี้ "ของจริง" .

อนุญาตการสื่อสารระหว่างผู้เล่น

ผู้ชนะคือผู้เข้าร่วมที่บอทมีคะแนนสูงสุดในการทดสอบฉันจะลงแข่งในวันที่ 3 สิงหาคม 2014

ผลลัพธ์สุดท้าย

ผลลัพธ์สุดท้ายอยู่ใน! ขี้ขลาดเป็นผู้ชนะ!

ในวันที่ 2 สิงหาคมฉันวิ่งโปรแกรมควบคุม 19 รอบและจัดอันดับผู้เล่นแต่ละคนตามคะแนนเฉลี่ย ผลการวิจัยพบว่า

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

รอบสุดท้ายจะพร้อมใช้งานดูที่นี่

ผลลัพธ์แบบ Run-by-run

ผลการแข่งขันแต่ละรายการใน 19 ครั้งนั้น ได้แก่ :

#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 รหัส Frege ประกอบด้วยไฟล์ Frege ที่มีการเชื่อมที่github.com/jamespic/zombies/blob/master/src/main/frege-bindings/ ......และคลาส Java helper ที่โทรเข้าสู่ Frege ที่github.com/jamespic / ซอมบี้ / หยด / Master / src / main / java / ผีดิบ / ... หากคุณสามารถโคลน repo (หรือดาวน์โหลดเป็น zip จากgithub.com/jamespic/zombies/archive/master.zip ) Maven จะจัดการงานสร้างให้คุณ
James_pic

1
@Pureferret พยายามที่จะตั้งค่าโครงการด้วยตนเองจะเจ็บปวด ยังไม่มีใครใช้จริง ๆ แต่มีคอมไพเลอร์และล่ามภาษาครึ่งโหล อนุญาตให้มีการไตร่ตรอง (แน่นอนว่าภาษาไดนามิกบางภาษาไม่สามารถทำงานได้หากไม่มี) ตราบใดที่มันไม่คุ้นเคยกับเกมหรือคู่แข่งของคุณ ดูการติดตามการปล้นของ Coward สำหรับตัวอย่างของ "การสื่อสาร"
James_pic

1
@sokie ฟังดูดี - มีบางรายการที่ทำสิ่งนี้แล้วและฉันคิดว่าเมื่อฉันตั้งความท้าทายที่ผู้เข้าร่วมบางคนต้องการให้บอทของพวกเขากลายเป็นที่พบปะหรือแลกเปลี่ยนข้อมูลเกี่ยวกับสภาพแวดล้อมของพวกเขา เราจะบอกว่าผู้เล่นมีเครื่องส่งรับวิทยุ
James_pic

2
@James_pic ฉันเพิ่มรหัสนี้ลงในเครื่องของฉัน ( pastebin.com/PutPn9ff ) ใน Game.java ดังนั้นฉันจึงสามารถใช้ปุ่มลูกศรเพื่อเดินหน้าและถอยหลังในเกมได้ คิดว่าอาจเป็นประโยชน์สำหรับคุณที่จะเพิ่ม
Moop

2
ความผิดหวังเล็กน้อยที่ผู้ชนะปล่อยให้ตัวเองต้องเจอกับการเป็นซอมบี้มากกว่าการฆ่าตัวตาย
Sparr

คำตอบ:


15

คนขี้ขลาดตาขาว

กฎของความขี้ขลาด

  1. หากคุณไม่สามารถหนีไปได้ให้ตื่นตกใจและยิงทุกสิ่งที่คุณไม่รู้
  2. วิ่ง!!!
  3. เมื่อวิ่งคุณอาจจะหยิบกระสุนมาด้วย ลึกลงคุณรู้ว่าคุณไม่สามารถทำงานได้ตลอดไป
  4. เมื่อวิ่งไปหาคนขี้ขลาด Misery รัก บริษัท และพวกเขาอาจกินคนอื่นก่อน
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));
    }
}

ฉันตื่นเต้นที่จะลองใช้ รายการทั้งหมดที่ได้เพ่งความสนใจไปที่การต่อสู้ แต่ไม่มีใครพยายามวิ่งหรือซ่อน
James_pic

โอ้และคุณไม่จำเป็นต้องติดตามสิ่งที่คุณฆ่า มันจะปรากฏขึ้นDeadBodyพร้อมกับรหัสที่แตกต่างกันมากกว่าสิ่งที่มันเป็นมาก่อน
James_pic

1
มันไม่ใช่สำหรับการติดตามมันคือการไม่ยิงสิ่งเดียวกันสองครั้งในรอบเดียวกัน
Thaylon

1
ทำการเปลี่ยนแปลงหลายอย่างการรันที่ดีที่สุดด้วยการเปิดไพ่มหากาพย์อยู่ที่ 2681 dl.dropboxusercontent.com/u/13918324/2681.html
Thaylon

1
@Thaylon จัดรูปแบบซอร์สโค้ดล่าสุดให้คุณ pastebin.com/4WDb6s8C
HuddleWolf

44

Emo Wolf ด้วยปืน

เขากลับมาแล้ว เขาเกลียดซอมบี้ เขายังคงเกลียดชัง Java ไม่มีเจตนาละเมิดลิขสิทธิ์

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 ทำให้ผนังมากขึ้นสำหรับ Wallers ...
Moop

13

นักเคลื่อนไหวเพื่อสิทธิซอมบี้

การเคลื่อนไหวของ Zombie Right นั้นได้รับความนิยมอย่างรวดเร็วจากการเปิดเผย ความคิดในการฆ่าซอมบี้ทุกตัวที่ไม่มีการสำนึกผิดนั้นโหดร้ายอย่างยิ่งต่อพวกเขาดังนั้นพวกเขาจึงยิงผู้เล่นคนอื่นที่ไม่เชื่อในสาเหตุ ทำความเข้าใจกับการต่อสู้พวกเขาจะกอดซอมบี้หากไม่มีศัตรูที่มองเห็น

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

กฎข้อที่ 8 : ท่องเที่ยวเป็นกลุ่ม

HuddleWolf ยึดถือกฎข้อที่หกของ Zombieland เป็นหัวใจ มันจะไล่ล่าและเบียดเสียดกับวัตถุที่ไม่เป็นมิตรที่เห็น หาก HuddleWolf ไม่เห็นใครมายุ่งกับเขาเขาจะหันไปทางตะวันออกเฉียงเหนือเพื่อค้นหาพื้นที่ที่มีประชากรมากขึ้น HuddleWolf ยังเกลียดซอมบี้และจะมองเห็น

HuddleWolf ได้ตระหนักถึงความขี้ขลาดคือการใช้ความคิดเริ่มต้นของเขา เขาก้มหัวให้มากที่สุดของ Coward และตอนนี้ชอบ บริษัท Cowards มากกว่าผู้ไม่ประสงค์ดีอื่น ๆ

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: ตอนนี้สังหาร Gunners
HuddleWolf

คุณอาจต้องการเพิ่ม&& !(playerAtLocation.equals(context.getId()))เงื่อนไขการกอดของคุณ ตอนนี้มันเคลื่อนที่ไปหาผู้เล่นที่ใกล้ที่สุด - ยกเว้นผู้เล่นที่ใกล้ที่สุดคือคุณดังนั้นมันจึงยังคงอยู่
James_pic

คุณหมายถึงRule 8 ....
Pureferret

@Pureferret: ถูกต้อง แรงบันดาลใจดั้งเดิมของฉันไม่ใช่ปืนใหญ่ Zombieland
HuddleWolf

FYI ดูที่ ZombieHater ฉันไม่คิดว่าเขาเกลียดซอมบี้จริงๆ เขายิงพวกเราทุกคนเหมือนมือปืน คุณน่าจะเพิ่มเขาเข้าไปในรายการเป้าหมายเป้าหมาย
kaine

11

จิ้งจอก

สุนัขจิ้งจอกต้องการสุนัขจิ้งจอก

ใช้ส่วนที่ดีของคนขี้ขลาด แต่ใช้กลยุทธ์ที่แตกต่าง หากคุณเลือกที่จะยอมรับภารกิจ (ย่อย) ฟ็อกซ์จะเลือกสร้างหลุมสุนัขจิ้งจอก

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));
    }
}

ฉันชอบมัน. ฉันเป็นห่วงฉันจะตั้งค่าแบบอย่างที่เป็นอันตรายโดยอนุญาตให้มีหลายรายการ (บางรายการที่ก้าวร้าวมากขึ้นอาจจะได้รับพื้นด้วยการเพิ่มพัลลภ) แต่รายการนี้ไม่ชัดเจนช่วยคนขี้ขลาด (ถ้ามีคนอื่นเขียนมัน พวกเขาอาจทำสิ่งเดียวกันมากกว่านี้หรือน้อยกว่า) ดังนั้นฉันจะอนุญาต ฉันควรได้รับโอกาสทดสอบในวันพรุ่งนี้
James_pic

เพิ่มการให้คะแนนที่ดีขึ้น (ไม่มีการหยุดนิ่งเนื่องจากความสัมพันธ์) และทำเครื่องหมาย DeadBodys มากกว่าที่ปล้น อยากลองการคำนวณภัยคุกคามที่ดีขึ้น แต่กระบวนการทดสอบใช้เวลานานเกินไปขณะที่คนขี้ขลาดทำงานเป็นครั้งคราวถึง 15,000 รอบ นี่อาจเป็นเพราะสนามเด็กเล่นขนาดใหญ่และโอกาสที่ลดลงจะเกิดจากซอมบี้ ดูเหมือนว่ากลยุทธ์ที่ดีที่สุดคือ: รับผู้เล่นมากถึง 1,000 คนให้มากที่สุดหยุดเคลื่อนไหวแล้วให้โชคตัดสิน
Thaylon

10

Waller - Java

The Waller ชอบกำแพงและพยายามหลบซ่อนจากซอมบี้ โดยอุดมคติแล้วผู้ Waller ชอบที่จะถูกห่อหุ้มด้วยกำแพงและรอการเปิดเผยออกมา

กำแพงในอุดมคติ

กำแพงในอุดมคติคือจุดที่ Waller ล้อมรอบด้วยกำแพง:

   DDD 
   DWD 
   DDD

วิธีเดียวที่จะตายคือการยิงหรือวางไข่ซอมบี้ใต้หรือใกล้เคียงคุณ เป็นอัตราต่อรองที่ดีที่สุดที่เป็นไปได้สำหรับการหลีกเลี่ยงพวกเขา

กำแพงในอุดมคตินั้นหาได้ยาก แต่ Waller จะค้นหาตำแหน่งที่ดีที่สุดเท่าที่จะเป็นไปได้และรอให้ซอมบี้หรือผู้เล่นอื่นเข้ามาหาเขาเพื่อยิงและขยายกำแพงของเขา


อัลกอริทึมนั้นค่อนข้างง่าย

  1. มีซอมบี้กำลังจะกัดไหม? ยิงพวกเขา
  2. ค้นหาตำแหน่งกำแพงที่ดีที่สุด (คะแนน 0 - 8) ในมุมมอง
  3. ค้นหาเส้นทางที่สั้นที่สุดไปยังตำแหน่งนั้นและวิ่งไปหามัน!
  4. ลองเพิ่มกำแพง
  5. รอ...

นี่คืองานที่กำลังดำเนินอยู่อย่าลังเลที่จะนำสิ่งที่ฉันเขียนไปใช้เพื่อตัวคุณเอง ฉันเขียนอัลกอริธึมA *แบบง่าย ๆเพื่อค้นหาเส้นทางที่ดีที่สุดไปยังจุดที่ต้องการโดยคำนึงถึงกำแพงและผู้เล่นอื่น มันได้รับการคำนวณใหม่ในแต่ละรอบเนื่องจากผนังอาจมีการเปลี่ยนแปลงระหว่างกัน


การเปลี่ยนแปลง:

  • พยายามปรับปรุงประสิทธิภาพของเกมตั้งแต่ช่วงต้นโดยรอและหลีกเลี่ยงผู้เล่นที่ดุดันในสองสามรอบแรกก่อนที่จะค้นหา / สร้างกำแพง

  • เพิ่มน้ำหนักให้กับการค้นหาเส้นทางเพื่อใช้เส้นทางที่ดีที่สุดในแง่ของระยะทางและคะแนนตำแหน่ง จะปล้นบ่อยขึ้นและหวังว่าจะไม่หมดกระสุน ปรับปรุงเกมเปิดโดยวิ่งหนีจากผู้เล่นที่ดุดัน

  • แก้ไขปัญหาเกี่ยวกับการค้นหาเส้นทางที่ลงท้ายด้วยจุดที่ถูกครอบครอง

  • รหัสทำความสะอาดเพิ่มเติม เพิ่มกำแพงเพิ่มเพื่อให้ได้คะแนนมากกว่ากำแพงใกล้เคียง ขยายความว่า Waller จะขยายกำแพงของเขาออกไปมากแค่ไหน

  • ทำความสะอาดรหัสขึ้นเล็กน้อย ติดตั้งการยิงรีจีสตรีเพื่อหลีกเลี่ยง Wallers สองคนที่ยิงผู้เล่นเดียวกันในเทิร์นเดียวกัน (ได้รับแรงบันดาลใจจาก Thaylon)

  • เพิ่มการค้นหาเส้นทางระหว่างซอมบี้ที่ใกล้ที่สุดและ Walelr ปัจจุบัน Waller จะยิงซอมบี้ก็ต่อเมื่อมันสามารถไปถึงเขาได้ในระยะเวลาหนึ่ง หวังว่านี้จะช่วยกระสุนบางส่วนเมื่อพวกเขาเป็นกำแพงปิดกั้นเส้นทางของซอมบี้


ประเด็น

  • Waller อาจอยู่ในตำแหน่งที่ดี แต่เห็นตำแหน่งผนังที่ดีกว่า พวกมันจะไม่สนใจวิ่งผ่านดินแดนที่มีซอมบี้เข้ามาถึงที่ตั้งใหม่ (ฉันต้องไม่ย่อท้อ)

  • เกมแรกนั้นหยาบสำหรับ Waller ไม่มีป้อมปราการที่ดีอยู่ใกล้ ๆ และมีผู้เล่นที่ดุดันมากมาย (ฉันต้องปรับปรุงการแสดงก่อนเกม)

  • ไม่มีการสื่อสารระหว่าง Wallers ในสถานที่เดียวกัน จำเป็นต้องให้พวกเขาทำงานร่วมกันเพื่อสร้างกำแพงที่ดีที่สุดเท่าที่จะเป็นไปได้


นี่คือรหัสฉันไม่ใช่โปรแกรมเมอร์ Java (C #) ดังนั้นให้อภัยข้อผิดพลาดของจาวา

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));
    }
}

โอ้นี่เป็นสิ่งที่ดี ฉันหวังว่าบางคนจะทำบางสิ่งบางอย่างด้วยอัลกอริทึมการค้นหาเส้นทางที่แท้จริง - ฉันเล่นกับ Dijkstra นิดหน่อย แต่ดูเหมือนว่ามันจะทำให้งานของฉันล้าสมัย
James_pic

@ James_pic ขอบคุณฉันเล่นกับเขามากในคืนนี้ สิ่งที่น่าสนใจมากมายที่ต้องทำเมื่อคุณมีการค้นหาเส้นทาง การทดสอบครั้งแรกของฉันทำให้เขาอยู่ในอันดับสามรองจาก Coward และ Shotguneer
Moop

ไม่ใช่ว่าใครสามารถทำอะไรเกี่ยวกับมันได้ แต่ fyi ซอมบี้ไม่เพียง แต่จะวางไข่บนสนามที่ว่างเปล่าหรือผู้เล่น แต่ภายใต้ DeadBody
Thaylon

@Thlonlon ฉันสังเกตว่าขณะดูแผนที่ ouput ไม่มีอะไรที่ฉันสามารถเตรียมตัวสำหรับการใด ๆ แต่ขอบคุณที่มองออกไปสำหรับฉัน
Moop

มันอาจเป็นความผิดพลาดในการรักษา StandStill เป็นกำแพง แน่นอนว่ามันไม่ได้เคลื่อนไหว แต่ไม่มีการป้องกันซอมบี้
James_pic

8

กอร์ดอนฟรีแมน

กอร์ดอนฟรีแมนเกลียดซอมบี้ดังนั้นเขาจะไม่มีวันฆ่าตัวตาย แต่เขาไม่มีความมั่นใจเลยว่าจะมีกระสุนมากพอที่จะยิงซอมบี้ได้มากขึ้น

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;
    }
}

ฉันหวังว่าคุณจะไม่รังเกียจ แต่ฉันได้ทำการแก้ไขเล็กน้อยในโค้ดของคุณเพื่อรวบรวมและแก้ไขตัวชี้โมฆะหรือดัชนีข้อผิดพลาดอาร์เรย์สองสามตัวที่ทำให้เกิดข้อผิดพลาดในเวลาทำงาน ฉันไม่ได้เปลี่ยนตรรกะ
James_pic

@James_pic: ฉันขอขอบคุณการแก้ไขฉันไม่ใช่โปรแกรมเมอร์ Java อย่างน้อยถึงแม้ว่าฉันชอบที่จะคิดว่าฉันทำได้ดีพอสำหรับความท้าทายของ KotH: D
Kyle Kanos

คุณอาจต้องการที่จะดูรีเพลย์ของการแข่งขันที่ผ่านมาอย่างjamespic.github.io/zombies/2014-07-21/0.html ดูเหมือนว่าดร. ฟรีแมนจะเดินไปทางตะวันตกเฉียงเหนือเสมอซึ่งอาจอธิบายการทำงานที่ไม่สอดคล้องของเขาได้
James_pic

@James_pic: คนไหนที่เป็นอิสระ? มีสอง G's (สีน้ำเงินหนึ่งสีเหลืองอื่น ๆ ) ถ้าฉันเป็น G สีฟ้าดูเหมือนว่าเขาจะเคลื่อนที่แบบสุ่มและไม่ใช่แค่ NW นอกจากนี้ยังมีวิธีที่จะบอกว่าระหว่างซอมบี้ที่ตายแล้วกับมนุษย์ที่ตายแล้วหรือไม่?
Kyle Kanos

1
ขอบคุณ :) ฉันชอบที่จะใช้รหัสซ้ำเมื่อฉันสามารถ แต่ฉันชอบที่จะยอมรับเมื่อมันไม่ใช่ของฉัน
sokie

7

นักบวช

หากคุณมีศรัทธาคุณไม่จำเป็นต้องวิ่งหรือยิง

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.... ฉันเห็นสิ่งที่คุณทำที่นั่น;)
Kyle Kanos

ฉันกลัวว่าคุณจะต้องตั้งชื่อชั้นเรียนของคุณเป็นอย่างอื่นนอกจากHuddleWolfชื่อนั้นถูกใช้ไปแล้ว
James_pic

6

ZombieHater

สิ่งที่ส่งมานี้เกลียดซอมบี้! มันพยายามยิงซอมบี้ที่ใกล้ที่สุดขณะที่มีกระสุนแล้วรวบรวมกระสุนเพิ่มเพื่อฆ่าซอมบี้มากขึ้น

แก้ไข: ZombieHater ไม่ลังเลที่จะฆ่าคนอื่นเพื่อรับกระสุนเพิ่ม นอกจากนี้ยังตรวจจับสิ่งกีดขวางและพยายามเดินไปรอบ ๆ

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 ในขณะที่การใช้งานที่แตกต่างกันมันก็เหมือนกับ Gordon Freeman ของฉัน ....
Kyle Kanos

2
@KyleKanos มันเป็นความคิดเดียวกัน แต่รายละเอียดการใช้งานนับ การติดตามว่าศพใดมีการปล้นเป็นนวัตกรรมตัวอย่างเช่น
James_pic

โอ้และในเรื่องของการติดตามการปล้นPlayerIdมีการใช้งานที่เหมาะสมequalsและhashCodeและยังคงเหมือนเดิมตลอด "ชีวิต" ของผู้เล่น (มันจะเปลี่ยนเฉพาะเมื่อพวกเขาตายหรือหัน) ดังนั้นคุณอาจพบว่ามันง่ายกว่าที่จะเก็บไว้PlayerIdในemptyDeadBodiesแน่นอน ตำแหน่ง
James_pic

@ KyleKanos ฉันไม่เคยตั้งใจจะคัดลอกตรรกะของคุณ ทั้งหมดที่ฉันทำคือการสร้างบอทของตัวเองในแบบที่ฉันคิดว่ามันจะทำดีที่สุด
CommonGuy

1
Nice mods! ฉันเริ่มกังวลว่ากลยุทธ์ส่วนใหญ่นั้นเหมือนกัน แต่การสุ่มการเคลื่อนไหวนั้นให้คุณเพิ่มมากขึ้น!
James_pic

6

Vortigaunt

จะติดตามหมอกอร์ดอนฟรีแมนเสมอหรือเดินไปรอบ ๆ อย่างไร้จุดหมายถ้าเขาไม่ได้อยู่ในมิติเดียวกัน

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;
    }

}

ดังนั้นคุณไม่เคยยิง ... แต่ติดกับใครสักคนที่ทำ ... ฉันไม่สามารถบอกได้ว่านี่จะฆ่าฟรีแมนได้หรือเปล่า แต่นี่จะน่ากลัวสำหรับประชากรซอมบี้ ...
kaine

6

Cocoon - Frege

น่าละอาย. เลือกภาษาได้ครึ่งโหลและทุกคนก็ใช้จาวา ก็ไม่มีเหตุผลที่จะปล่อยให้พวกเขาเสียเปล่าดังนั้นนี่คือคู่แข่งของ Frege

มันใช้อัลกอริธึมของ Dijkstra เพื่อค้นหาจุดที่เงียบสงบเพื่อรอการเปิดเผยออกไปหากระสุนถ้ามันวิ่งออกมาและยิงซอมบี้ถ้าพวกมันเข้าใกล้เกินไป

Updated

ตอนนี้ Cocoon ไม่สนใจเส้นทางที่จะพามันไปในระยะทางที่โดดเด่นของซอมบี้ในอัลกอริธึมการจัดเส้นทางและยิงซอมบี้เมื่อมันอยู่ในระยะ 2 สแควร์มากกว่า 3 (เพื่อสร้างรังไหมที่แน่นกว่า)

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

Gunner - Java

นี่คือตัวอย่างเพื่อนำคุณออกจากบล็อก เขายิงอะไรก็ได้ที่เขาเห็นหรือเดินอย่างไร้จุดหมายถ้าไม่มีอะไรอยู่รอบตัวหรือเขาไม่มีกระสุน

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();
    }

}

คุณทำได้ดีกว่านี้ไหม


3

HideyTwitchy

Nutjob ที่ซ่อนตัวจากทุกสิ่งทุกอย่างเว้นแต่ผู้เล่นจะไล่ตามเขาไปจนถึงระยะยิงซึ่งในกรณีนั้นเขาตื่นตระหนกและยิง (รวมถึงประเภทของเขาเอง) เพียงแค่ยิงร่างกายออกหากกระสุนหมดจากนั้นให้เอาห่าไปจากศพ

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 ฉันรู้เกี่ยวกับการยอมจำนนสองครั้ง แต่ฉันไม่สามารถต้านทานได้ กรุณาบอกฉันว่าฉันควรลบมัน

คนขี้ขลาดแบบไหนกันที่ยิงและต่อสู้? นำเสนอให้คุณSUPER Coward เขาจะวิ่งบนสนามเพื่อพยายามหลีกเลี่ยงคนที่เขาคิดว่าเป็นศัตรูและซอมบี้ เขาพยายามที่จะอยู่อย่างปลอดภัยและหลีกเลี่ยงอุปสรรค หากเขาไม่พบเส้นทางที่ดีตกใจและอยู่ในสถานที่

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;
         }
    }
}

ความคิดปัจจุบันของฉันคือฉันจะอนุญาตให้ส่งสองครั้งตราบเท่าที่ไม่มีการสมรู้ร่วมคิดระหว่างกันดังนั้นรายการที่ผู้เล่นหลายคนสามารถส่งได้อย่างง่ายดายก็โอเค แต่พัลลภหรือ lapdogs ไม่ได้ ดูเหมือนว่ามันจะโอเค (ยกเว้นบางคนมีวัตถุ) ดังนั้นฉันจะทดสอบเมื่อฉันมีโอกาส
James_pic

3
+1 สำหรับDANGER danger = DANGER.DANGER;
Andreï Kostyrka

3

Shotguneer

ฉันจะยอมรับว่าเป้าหมายหลักของฉันคือการยิงมือปืน

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 คุณจะทำอย่างไรคุณจึงไม่ต้องแก้ไขอีกต่อไป?
kaine

มันไม่ได้รวบรวม ฉันไปแก้ไขมัน แต่มีบางแห่งที่ฉันไม่สามารถเข้าใจได้ว่าเจตนาดั้งเดิมของรหัสคืออะไร (เช่นคอมไพเลอร์บ่นว่าTargetZombieอาจไม่สามารถเริ่มต้นได้และฉันไม่แน่ใจว่าอะไร คุณต้องการทำ) คุณต้องการที่จะแกว่งอีกครั้งหรือไม่
James_pic

ขอบคุณสำหรับความพยายาม ฉันไม่ได้ติดตั้งรหัสของคุณดังนั้นจึงล้มเหลวเพราะไม่รู้จักค่าคงที่ของคุณ ฉันจำไม่ได้ว่ามันจะไม่คอมไพล์ถ้า TargetZombie ไม่มีค่าเริ่มต้น (แม้ว่ามันจะไม่ถูกใช้ถ้ามันไม่ขอบคุณซอมบี้คงที่) ฉันแก้ไขมันแล้วมันจะฆ่าฉันถ้าฉันทำผิดตรงนั้น! อย่าเสียเวลากับการพยายามแก้ไขเว้นแต่คุณจะเบื่อฉันจะเขียนความคิดเห็นใหม่ถ้าฉันสามารถยืนยันได้ว่ามันใช้งานได้กับผู้เล่นคนอื่น ๆ
kaine

ฉันแก้ไขมันแล้วมันจะคอมไพล์และรันโดยไม่มีข้อผิดพลาด - ส่วนใหญ่เป็น "ปิดโดยCENTRE_OF_VISION" ข้อผิดพลาดและ NPE บางตัว คุณจะต้องดูที่การวิ่ง ( jamespic.github.io/zombies/2014-07-23/0.html ) เพื่อดูว่ามันทำในสิ่งที่คุณคาดหวังหรือไม่
James_pic

ดูเหมือนว่าคุณจะมีผลกระทบอย่างมากต่ออายุขัยของ Gunners! ฉันสงสัยว่าสิ่งนี้จะจุดประกายให้คลื่นของคู่แข่งชั้นนำพากันออกไปหรือไม่?
James_pic

2

Sokie - JAVA

Sokie รู้ว่าคุณเก่งกว่าในแพ็คดังนั้นจึงพยายามหาพันธมิตรที่ใกล้ที่สุดที่เขาพบ ในขณะที่เคลื่อนไหวหากเขาตกอยู่ในอันตรายพยายามต่อสู้หรือพยายามวิ่งหนี เมื่อเขาไปถึงเพื่อน ๆ พวกเขาต่อสู้กันจนกว่าพวกเขาจะไม่มีกระสุนแล้วพยายามหาศพที่อยู่ใกล้ที่สุดเพื่อขับไล่

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 ชื่อผู้เล่นของคุณจะเหมือนกับชื่อคลาสของคุณ (ในกรณีนี้คือ "Sokie") ดังนั้นผมจึงสงสัยว่าอาจจะplayerAtLocation.getName().equals("BetterInPacks2") playerAtLocation.getName().equals("Sokie")
James_pic

แดง! นั่นคือรหัสที่เหลือในขณะที่ฉันกำลังทดสอบการใช้งานที่แตกต่างกันฉันจะแก้ไขให้ถูกต้องในเวลาไม่นาน! ขอบคุณ
sokie

2

Bee - Python

รายการที่สอง แต่ฉันคิดว่ามันคงจะสนุกถ้าได้ลองทำอย่างอื่นและใช้ภาษาอื่น

  • ตอนนี้ผึ้งจะหลีกเลี่ยงการย้ายไปที่จุดเดียวกัน
  • เพิ่มเติม 'Pythonic' ในขณะนี้
  • การเคลื่อนไหวพรูที่ได้รับการปรับปรุงเพื่อให้ผึ้งสามารถไปหาราชินีได้เร็วขึ้น (ขอบคุณเจมส์ที่อนุญาตให้เข้าถึงขนาดกระดาน)

ผึ้งชอบที่จะอยู่ด้วยกันดังนั้นพวกมันจึงกำหนดให้ผึ้งที่รอดตายหนึ่งตัวเป็นนางพญาผึ้งและจับกลุ่มเข้าหาเธอ พวกเขาจะต่อยฝ่ายตรงข้ามระหว่างทางไปหาเธอเลือกเนื้อซอมบี้มากกว่ามนุษย์

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
วุ้ย ฉันเริ่มกังวลว่าจะไม่มีอะไรนอกจากจาวาในการแข่งขันครั้งนี้
James_pic

ใช่และรายการแรกที่ค้นหาฟิลด์ทั่วโลกซึ่งฉันคิดว่าเป็นคุณสมบัติที่เรียบร้อย
Moop

สิ่งหนึ่งที่คุณอาจพบว่ามีประโยชน์คือ Jython จะทำให้ getters และ setters สำหรับ JavaBeans พร้อมใช้งานเป็นคุณสมบัติโดยอัตโนมัติ ตัวอย่างเช่นคุณสามารถใช้มากกว่าcontext.gameClock context.getGameClock()
James_pic

@James_pic ขอบคุณสำหรับเคล็ดลับไม่รู้ว่า
Moop

2

นาย Assassin

พ่อแม่ของเขาไม่ใช่คนดีมาก เขาไม่ฆ่าใคร แต่ไม่คิดถ้าเขาคิดว่าคุณจะช่วยเขาให้มีชีวิตยืนยาวขึ้น เขาปฏิบัติต่อทุกคนราวกับว่าพวกเขาเป็นคนพิเศษและไม่สนใจและจัดอันดับให้คุณว่าเขาต้องการให้คุณอยู่ใกล้แค่ไหนเขาต้องการให้คุณตายมากแค่ไหนและที่สำคัญคุณคือสถานการณ์ปัจจุบัน

อย่างที่ฉันรู้ว่าสิ่งนี้ถูกซ่อนอยู่ที่นี่ฉันจะอธิบายบางอย่าง เขามักจะไม่เคยฆ่าคนที่อาจฆ่าภัยคุกคามของเขาก่อนที่เขาจะต้องเพราะพวกเขาไม่ใช่เป้าหมายของเขา เขาจะเลี้ยงคนที่ไม่เคยยิง มีข้อยกเว้นประการหนึ่งเขาจะฆ่าคุณถ้าคุณฆ่าเขาในปัจจุบัน เขาชอบที่จะมีกำแพงล้อมรอบในสถานที่ที่ไม่มีการบังคับให้ใส่รหัส เขาเป็นจิ้งจอกขี้กลัวและขี้ขลาด เขากอดกับฮัดเดิลวูลฟ์และผนังกับวอลเลอร์ ปัจจุบันเขาย้ายไปยังกลุ่ม (เช่น Sokie แม้ว่า Sokie จะยิงเขาอย่างไร้ความปราณี) แนชควรรักเขาในขณะที่ลำดับความสำคัญของเขาทำให้นักทฤษฎีเกมร้องไห้ อย่างไรก็ตามลูกค้าของเขาดูเหมือนจะเป็นคนต่างชาติมากหากเขาฆ่านักบวชมนุษย์ต่างดาวและผู้มาใหม่ (แม้ว่าเขาจะให้อภัยคุณในวันศุกร์หรือวันเสาร์ถ้าคุณไม่ฆ่าเขา ... อาทิตย์สายเกินไป) ขออภัยถ้าฉันลืมคนอื่น

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;
    }
}

ใช่แล้วแจ็คช่วยชีวิตเขาด้วยกระสุนนัดสุดท้ายด้วยตัวเอง หากมีซอมบี้อยู่รอบตัวเขามากกว่าจำนวนที่กำหนดและเขามีกระสุนเหลือนัดเดียวเขาจะฆ่าตัวตายเพื่อป้องกันการแพร่กระจาย เนื่องจากไม่สำคัญว่าฉันจะชนะ (ฉันไม่สามารถให้รางวัลตัวเองได้) ฉันต้องการให้ตัวละครบางตัวมีฟังก์ชั่นนั้น
kaine

@James_pic สิ่งนี้ใช้ได้ในเกม (แม้ว่าจะเป็นรุ่นก่อนหน้านี้ฉันได้โคลนไปหลายวันแล้ว) มันควรจะทำงาน ถ้าไม่แจ้งให้ทราบ หากไม่สามารถลบได้ในวันอาทิตย์
kaine

ดูเหมือนว่าจะทำงานได้ดีในรหัสรุ่นปัจจุบัน ฉันจะรวมไว้ในการทดสอบในวันนี้
James_pic

อีกครั้งฉันไม่รู้ว่ารายการนี้ทำงานอย่างไร ถ้ามีคนอื่นส่งไปฉันจะถือว่ามันไร้สาระ แต่เมื่อ Shotguneer กำลังเต้นดีที่สุดของฉันฉันจึงอยากรู้ว่าจริงๆแล้วมันทำอะไร
James_pic

ค่อนข้างซับซ้อนและฉันถือว่าการจัดการภัยคุกคาม / ระยะทาง / ลำดับความสำคัญได้รับการจัดการด้วยมือ
Thaylon

1

SOS (ยิงเมื่อเห็น)

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

การตัดสินใจว่าจะยิงใครซักคนนั้นเป็นประเด็นสำคัญของนักโทษ หากคุณคิดว่าศัตรูของคุณได้ตัดสินใจแล้วสิ่งที่ดีที่สุดคือการยิงพวกเขา อย่างไรก็ตามหากปฏิปักษ์ของคุณจะตัดสินใจว่าจะทำอย่างไรโดยพิจารณาจากสิ่งที่พวกเขาคิดว่าคุณจะทำดังนั้นตัวเลือกที่ดีที่สุดคือปล่อยพวกเขาไว้และพวกเขาอาจจะทำเช่นเดียวกัน

จอห์นแนชยิงได้แค่ "สับ" - ฝ่ายตรงข้ามที่ทำจิตใจของพวกเขาเรียบร้อยแล้ว นั่นคือเขายิงศัตรูที่มักจะยิงหรือศัตรูที่ไม่เคยยิง เขาทิ้งศัตรูไว้คนเดียวหากพวกเขามีตรรกะที่ซับซ้อนมากขึ้น

เมื่อเขาไม่ได้ถ่ายทำเขากำลังไล่ตามกระสุนหรือมุ่งหน้าไปทางทิศใต้

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 ทำอะไรนอกจากการย้ายแบบสุ่มหรือไม่
Thaylon

@ Thaylon Nope มันทำตามที่พูดไว้ในกระป๋อง Moop รวมไว้ในคำขอดึงที่เขาส่งไปยังโครงการ จุดประสงค์หลักของคำขอดึงคือเพื่อปรับปรุงเอาต์พุต HTML แต่ยังรวมถึง MoveRandomly และฉันคิดว่าฉันจะรวม MoveRandomly ในการทดสอบเพื่อดูว่าเกิดอะไรขึ้นในการทดสอบ
James_pic

ผมดึงล่าสุดจาก GitHub ของคุณและไม่สามารถรับ john-nash.js การรวบรวม
Moop

@ moop ฉันพบเหมือนกัน
Pureferret

ซ่อมมัน. ฉันเพิ่งทดสอบกับ Java 7 มันควรจะทำงานใน 8 เช่นกันในขณะนี้
James_pic

1

SunTzu พยายามเป็นยุทธวิธีและค้นหาจุดที่ปลอดภัยบนกริดเพื่อย้ายไป แต่อย่างที่มันเป็นเขากำลังทำงานอยู่

“ ดังนั้นเราอาจรู้ว่ามีห้าสิ่งจำเป็นสำหรับชัยชนะ:
1. เขาจะเป็นผู้ชนะเมื่อรู้ว่าจะต่อสู้และเมื่อใดที่จะไม่ต่อสู้
2. เขาจะเป็นผู้ชนะซึ่งรู้วิธีจัดการกับกองกำลังที่เหนือกว่าและด้อยกว่า
3. เขาจะเป็นผู้ชนะซึ่งกองทัพจะมีชีวิตชีวาด้วยจิตวิญญาณเดียวกันตลอดทุกระดับ
4. เขาจะชนะใครเตรียมพร้อมตัวเองรอคอยศัตรูที่ไม่ได้เตรียมตัวไว้
5. เขาจะเป็นผู้ชนะซึ่งมีความสามารถทางทหารและไม่ได้แทรกแซงโดยผู้มีอำนาจสูงสุด”

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 );
                    }
                }
        }

    }

ปัญหาปัจจุบันคืออันตรายไม่ได้สร้างขึ้นอย่างถูกต้องและฉันไม่คิดว่าที่ใหญ่ที่สุดภัยคุกคามกำลังถูกบรรจุอย่างถูกต้อง


+1 สำหรับการใช้คลาสจาก Guava ฉันลืมว่าฉันใช้มันในโปรแกรมควบคุม แต่มีคลาสที่มีประโยชน์มากมายสำหรับสิ่งเหล่านี้
James_pic

1
@james_pic tbh ฉันต้องการขาย Apache ให้เทียบเท่า รู้สึกเหมือนฉันได้ทำแฮชของมัน
Pureferret

เนื่องจากมันถูกสร้างขึ้นด้วย Maven ฉันสามารถเพิ่มการพึ่งพาที่สมเหตุสมผลใด ๆ ที่คุณอาจต้องการหากมันทำให้สิ่งต่าง ๆ ง่ายขึ้น หากคุณต้องการใช้ Commons Collections ไปเลย
James_pic

@james_pic ฉันเพิ่งจะสร้างมันด้วย maven เพราะฉันไม่เข้าใจจริงๆ ... ฉันอยากทำงานกับสิ่งที่คนอื่นมี แต่ทำได้ดีกว่า
Pureferret

1

Tyzoid - หุ่นยนต์ที่ค่อนข้างโง่ของฉัน

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

ฉันกลัวว่าคุณจะสายเกินไปที่จะมีโอกาสชนะ แต่ถ้าฉันได้รับโอกาสในภายหลังฉันจะทำอีกหนึ่งรายการของคุณรวมอยู่ด้วยเพื่อดูว่าคุณเป็นอย่างไร
James_pic

ใช่ฉันตัดสินการเสนอผลงานของฉันตามการหมดเวลาของเงินรางวัล: / - ฉันไม่คาดหวังว่าจะได้ใกล้ชิดกับการดื่มไวน์แม้ว่า ... บอทไม่ดีมาก
Tyzoid

1
ขออภัยเกี่ยวกับเรื่องนั้นค่าหัวถูกตั้งค่าให้หมดเวลาในวันถัดจากวันที่ครบกำหนดที่ระบุไว้ในวันที่ 3 สิงหาคมเพื่อที่ฉันจะได้รับรางวัลในวันนี้วันที่ 4 สิงหาคม (ที่ถูกกล่าวว่าคุณยิงทุกคนที่ยิงตัวละครของฉันอย่างใดอย่างหนึ่งดังนั้นฉันควรจะหยั่งรากสำหรับ Tyzoid.)
kaine
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.