Compare commits

285 Commits
GUI ... master

Author SHA1 Message Date
93cb385aaa added class diagram 2018-06-26 11:27:36 +02:00
80d6ce748c small changes 2018-05-25 05:34:51 +02:00
cc277a045f fixed annotations 2018-05-25 04:25:05 +02:00
Leen Dereu
4cf6e67a78 Documentatie Worm 2018-05-25 00:28:29 +02:00
Leen Dereu
e416911ae0 Documentatie Worm 2018-05-24 17:33:11 +02:00
Leen Dereu
6f60a4d06d Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-05-24 16:44:05 +02:00
Leen Dereu
4b4667296e Verwijderen overbodige exceptions 2018-05-24 16:43:57 +02:00
ecd65207ac update 2018-05-24 16:42:54 +02:00
Leen Dereu
91899be62c Documentatie util 2018-05-24 12:52:43 +02:00
Leen Dereu
ec12d20967 Documentatie model 2018-05-24 12:49:05 +02:00
Leen Dereu
8ab759026f Documentatie TeamComparator 2018-05-24 12:46:14 +02:00
Leen Dereu
e4c938dbcd Documentatie Tuple 2018-05-24 12:33:35 +02:00
Leen Dereu
f6c6399d6a Documentatie TeamComparator 2018-05-24 12:19:24 +02:00
Leen Dereu
94a76c2aca Documentatie IllegalNameException 2018-05-24 12:17:33 +02:00
Leen Dereu
5c64518c41 Documentatie Coordinate 2018-05-24 12:14:45 +02:00
Leen Dereu
552ed3ac94 Documentatie Porjectile 2018-05-24 12:01:09 +02:00
Leen Dereu
47ae1f58c1 Documentatie GameObject 2018-05-24 11:15:11 +02:00
Leen Dereu
f21a01e1d3 Documentatie GameObject 2018-05-23 22:27:13 +02:00
Leen Dereu
9f8a250f71 Documentatie Rifle 2018-05-23 22:22:16 +02:00
Leen Dereu
7f82c3e334 Documentatie Bazooka 2018-05-23 22:15:01 +02:00
Leen Dereu
b4425849b9 Documentatie Team 2018-05-23 21:52:10 +02:00
b0b94ab5d6 small refactoring 2018-05-23 21:51:14 +02:00
98de279626 refactoring jeej 2018-05-23 21:38:44 +02:00
f3d6d971b9 meer refactoring 2018-05-23 21:03:10 +02:00
ffcc27104c Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-23 17:25:55 +02:00
21c9aea4fe refactoring 2018-05-23 17:22:15 +02:00
Leen Dereu
49bd7e5950 Documentatie Team (niet klaar) 2018-05-23 17:18:15 +02:00
Leen Dereu
9e0d87ccbc Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-05-23 16:01:33 +02:00
Leen Dereu
8b4e147d9e Documentatie Team 2018-05-23 16:01:10 +02:00
0fd761e611 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-23 15:59:38 +02:00
8aa2699d69 fix projectile, refactoring 2018-05-23 15:59:29 +02:00
Leen Dereu
0fbf371d79 Documentatie Food 2018-05-23 15:33:36 +02:00
Leen Dereu
38446cabb6 Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-05-23 13:19:51 +02:00
Leen Dereu
be9e8ae8f9 Documentatie World 2018-05-23 13:19:46 +02:00
562e83ccfc refactoring worm 2018-05-23 11:59:59 +02:00
Leen Dereu
c5f55f29fb error OutsideWorld 2018-05-22 23:23:19 +02:00
Leen Dereu
817e63251a Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-05-22 22:15:59 +02:00
Leen Dereu
d30f39509f Projectile 2018-05-22 22:15:54 +02:00
4d2a957995 small refactoring 2018-05-22 22:13:50 +02:00
Leen Dereu
12defdc769 Errors projectile 2018-05-22 22:08:19 +02:00
5e9c6b25d9 fixes 2018-05-22 21:29:56 +02:00
36bf17b689 small fixes 2018-05-22 17:48:33 +02:00
Leen Dereu
9f2e91836c Errors oplossen 2018-05-22 16:01:14 +02:00
119a112555 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-22 15:42:15 +02:00
20bc7330f6 fixes 2018-05-22 15:39:22 +02:00
Leen Dereu
ed6be5d2b8 errors fixen 2018-05-22 15:38:40 +02:00
63cabe27fc Merge branch 'master' of github.com:KUL-ogp/ogp1718-gui 2018-05-22 14:07:57 +02:00
facabe5723 small change 2018-05-22 14:03:31 +02:00
Koen Yskout
d1559206d0 Release v3.6
small updates to test suite
2018-05-22 13:41:21 +02:00
0457f135e4 small fixes 2018-05-22 12:55:19 +02:00
902fb3b89d small change 2018-05-21 15:21:50 +02:00
aae6e2ce58 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-20 17:19:51 +02:00
c684158ba9 small fixes 2018-05-20 17:19:03 +02:00
Leen Dereu
909d972654 Projectile: fix errors 2018-05-20 14:43:15 +02:00
Leen Dereu
6313adaf4c fire bijwerken 2018-05-20 14:22:47 +02:00
Leen Dereu
72cd481583 aanpassen Projectile 2018-05-20 13:18:28 +02:00
5236d4f0d6 80% :D 2018-05-20 04:23:22 +02:00
4a1a48e1fe refactoring program 2018-05-19 21:27:29 +02:00
fa65975994 improved program 2018-05-19 19:43:06 +02:00
Leen Dereu
d80fb7d284 Jump methods in projectile 2018-05-19 13:45:37 +02:00
84a308dc59 small change 2018-05-19 10:56:41 +02:00
945e5bad83 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-18 19:56:31 +02:00
9f99e6f4e1 small changes 2018-05-18 19:56:28 +02:00
d3a9475494 small update 2018-05-18 16:38:16 +02:00
4761ae72c2 update 2018-05-16 17:49:35 +02:00
2cd0d3af7a fixes 2018-05-16 16:25:06 +02:00
e0be7248ed Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-16 12:08:22 +02:00
bc05aee249 update 2018-05-16 12:08:06 +02:00
Koen Yskout
2e15a29a4d Release v3.5
Updated test suite
2018-05-15 09:33:46 +02:00
Leen Dereu
43b2bce9ee hit 2018-05-11 14:59:46 +02:00
Leen Dereu
99450efe5f Jump in Projectile 2018-05-11 14:49:33 +02:00
Leen Dereu
688bcd037a Projectile 2018-05-11 12:07:07 +02:00
Koen Yskout
cc27abd957 Release v3.4
Updated test suite
2018-05-08 09:41:13 +02:00
2d8de28928 update program 2018-05-07 21:11:51 +02:00
903ad34c64 added everything to program factory 2018-05-07 17:18:13 +02:00
518dcaf3fc improved Program 2018-05-07 15:29:19 +02:00
dcaf7f0775 added binary expressions 2018-05-07 11:42:25 +02:00
3ce0505f4e starting to implement program 2018-05-06 21:34:49 +02:00
fb690e38f9 update 2018-05-06 13:30:11 +02:00
a3f608f593 added projectile 2018-05-05 19:43:16 +02:00
ac937eb563 added castSpell 2018-05-05 17:31:08 +02:00
d1d52783a5 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-05-04 15:39:14 +02:00
5ba8b7f3cd improved world 2018-05-04 15:39:10 +02:00
Leen Dereu
faf5866aa5 Class Projectile 2018-05-04 15:31:49 +02:00
Leen Dereu
8c7a078aa1 Worm: projectile 2018-05-04 15:15:50 +02:00
Leen Dereu
383bf84152 Worm 2018-05-04 14:28:28 +02:00
d5bb4d4c51 implement facade 2018-05-04 14:27:48 +02:00
Leen Dereu
18b326281c Functies Worm 2018-05-04 14:27:00 +02:00
Leen Dereu
52e461de7b Class Projectile 2018-05-04 14:23:22 +02:00
8d0d8630cf added underscore name 2018-05-04 13:08:59 +02:00
Leen Dereu
ae1924df51 opgave 2018-05-04 12:55:22 +02:00
78b40fd634 added samenvatting 2018-05-04 12:53:45 +02:00
0da66764cf update GUI 2018-05-02 13:24:13 +02:00
Koen Yskout
492299b18d Release v3.3 2018-04-30 16:12:49 +02:00
Koen Yskout
9f9e2dc71e Release v3.2 2018-04-23 12:54:38 +02:00
Koen Yskout
afac62772e Release v3.1
Added full test suite
2018-04-17 13:56:25 +02:00
Koen Yskout
d5cbb646ed Release v3.0 2018-04-17 13:54:17 +02:00
Leen Dereu
4eacc246c5 Documentatie 2018-04-16 23:51:23 +02:00
Leen Dereu
5899928b34 Documentatie Worm 2018-04-16 22:50:06 +02:00
Leen Dereu
af1ecdbf9f Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-04-16 21:29:24 +02:00
Leen Dereu
183caf85b4 Documentatie move methodes 2018-04-16 21:29:13 +02:00
0c68e1fa49 fixes 2018-04-16 21:28:02 +02:00
b7354dfbb1 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-04-16 21:04:41 +02:00
Leen Dereu
76bc41cba3 Documentatie move methode 2018-04-16 21:04:28 +02:00
fdc6517f9d Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-04-16 21:02:34 +02:00
e7490de309 fix eat 2018-04-16 21:02:31 +02:00
Leen Dereu
dc5c5f361f Documentatie tot move (part 1 verbeteren) 2018-04-16 19:44:28 +02:00
35fb734030 fixed jump 2018-04-16 15:42:53 +02:00
8c2cb68d22 fixes 2018-04-13 23:54:18 +02:00
a6c127ee3b fixes 2018-04-13 21:41:31 +02:00
68aae2be6e mass update 2018-04-13 21:00:41 +02:00
Leen Dereu
1fff8ee8b9 Jump methods 2018-04-13 20:22:15 +02:00
Leen Dereu
5171f36916 fall 2018-04-13 18:35:43 +02:00
Leen Dereu
ebb59b589c Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-04-13 18:33:09 +02:00
Leen Dereu
c069051001 fallé 2018-04-13 18:33:04 +02:00
48c05010f6 fixes 2018-04-13 18:29:39 +02:00
c0be2de7c1 fix ispassable 2018-04-13 16:12:45 +02:00
262e652dee fix isPassable 2018-04-12 23:41:50 +02:00
Leen Dereu
f9a13b9cfd canFall in Worm en Facade 2018-04-12 17:34:18 +02:00
afbdd5a88e Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-04-12 17:25:09 +02:00
dd2190910b improved passable 2018-04-12 17:24:08 +02:00
Leen Dereu
a71ee1fb00 Fall method 2018-04-12 17:12:52 +02:00
Leen Dereu
51dbd29285 Fall methode (nog niet klaar) 2018-04-12 13:31:44 +02:00
17ce8566a3 mass update 2018-04-11 21:05:45 +02:00
016a2e2bbb massive improvement to Team 2018-04-11 16:39:58 +02:00
14d67eb323 small improvements 2018-04-08 15:25:07 +02:00
12d6d85325 overall improvements 2018-04-08 15:15:13 +02:00
Leen Dereu
6d56d86e74 Documentatie nieuwe methodes 2018-04-08 14:30:41 +02:00
Leen Dereu
81d3b31213 in Team isAlive veranderd in isTerminated 2018-04-08 14:15:23 +02:00
ed3843fc1e finished abstract class 2018-04-07 21:35:09 +02:00
d2fac7e27b added abstract class 2018-04-07 20:47:32 +02:00
7ffe8803c2 improved world class 2018-04-03 17:05:02 +02:00
Leen Dereu
adb06f032e Documentatie Team 2018-04-03 16:07:22 +02:00
ea150144ba Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-04-03 15:35:59 +02:00
c4a4bd9c2e updated facade and world 2018-04-03 15:35:56 +02:00
Leen Dereu
a18d586388 Worm class: fight, hitPoints, fall, collision 2018-04-03 15:12:02 +02:00
Leen Dereu
8166920c94 Food class 2018-04-03 12:48:49 +02:00
Leen Dereu
6cd76282c0 Team class 2018-04-03 12:31:22 +02:00
Leen Dereu
dac6936895 Team class 2018-04-03 12:19:16 +02:00
dd0b0017d4 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-04-03 11:21:18 +02:00
aa00b97ef0 Added world and updated facade 2018-04-03 11:21:15 +02:00
Leen Dereu
144a46f810 Team class 2018-04-03 11:18:28 +02:00
9ad5255561 fixed facade for update 2018-03-30 16:46:04 +02:00
682a63cca1 merge GUI 2018-03-30 16:44:22 +02:00
049d3ba14b fixes 2018-03-30 16:40:00 +02:00
Koen Yskout
295c510d73 Release v2.3
eat() method
2018-03-28 14:11:41 +02:00
Koen Yskout
bfe9b06404 Release v2.2
Fixes an error with the display of hitpoints
2018-03-23 18:19:55 +01:00
Leen Dereu
b613303b29 Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-03-23 13:50:06 +01:00
Leen Dereu
3807eb5d0f collision 2018-03-23 13:50:00 +01:00
c89b7f2a5e fixed facade 2018-03-23 13:49:36 +01:00
Leen Dereu
0111516595 Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-03-23 13:31:51 +01:00
Leen Dereu
036a194fb3 hit points 2018-03-23 13:31:43 +01:00
c631e315bd Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-23 13:30:43 +01:00
2c517b0cf8 added coordinate type 2018-03-23 13:29:05 +01:00
Leen Dereu
b61378e423 methodes ivm hit points 2018-03-23 13:19:20 +01:00
Leen Dereu
311ecfd9ce nieuwe classes 2018-03-23 13:01:03 +01:00
Leen Dereu
06ac444ba2 schrijffouten verbeteren 2018-03-23 12:46:27 +01:00
73b72c4902 changes docs 2018-03-23 12:32:04 +01:00
f058452320 merge gui 2018-03-23 10:43:00 +01:00
Leen Dereu
2442e41453 Samenvatting 2018-03-22 20:44:15 +01:00
Leen Dereu
1ee2f05a60 opgave part 2 worms + samenvatting part 2 2018-03-22 19:56:47 +01:00
Koen Yskout
f45fa3fa96 Release v2.1
Fixed a bug related to the radius of a newly created worm
2018-03-22 19:18:38 +01:00
Koen Yskout
5f5948795f Release v2.0
GUI updates for part 2 of the project
2018-03-13 10:27:15 +01:00
f4610de323 removed eclipse config files 2018-03-11 23:23:51 +01:00
0fe3dc1a41 small changes 2018-03-11 23:06:30 +01:00
e55d7b2c67 small changes 2018-03-11 22:55:37 +01:00
f836afbcdb small changes 2018-03-11 22:51:58 +01:00
a40b6125c7 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-11 21:41:15 +01:00
6a329e4533 fixes 2018-03-11 21:41:12 +01:00
Leen Dereu
d3bee9510b jar-file 2018-03-11 21:39:33 +01:00
Leen Dereu
916342be71 aanpassen commentaar 2018-03-11 21:25:36 +01:00
Leen Dereu
d5873fd766 commentaar aanpassen 2018-03-11 21:20:57 +01:00
Leen Dereu
6e32d5f053 aanpassen commentaar shape 2018-03-11 21:17:06 +01:00
Leen Dereu
6288d46945 commentaar isValidOrientation() 2018-03-11 21:15:25 +01:00
Leen Dereu
598abe6e63 Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-03-11 21:10:09 +01:00
Leen Dereu
5b2dc5ee0a aanpassen commentaar isValidLocation() 2018-03-11 21:09:50 +01:00
e99123fb7c comments 2018-03-11 21:06:34 +01:00
fe410b0643 small change to tuple 2018-03-11 21:02:06 +01:00
e19a379ab6 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-11 21:00:29 +01:00
711d8b69c3 added comments 2018-03-11 21:00:26 +01:00
Leen Dereu
78f195cccc @-statements 2018-03-11 20:53:05 +01:00
23a6fcd4b9 small changes 2018-03-11 20:03:04 +01:00
8e5e976c00 added isValidOrientation 2018-03-11 19:58:10 +01:00
157bd87ca9 improved wormtest 2018-03-11 19:51:26 +01:00
9334d1e75d Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-11 19:50:34 +01:00
021cba609b fixes and improved tests 2018-03-11 19:50:28 +01:00
Leen Dereu
ffb53f85da commentaar Facade 2018-03-11 19:03:31 +01:00
Leen Dereu
4f76b7305a commentaar createWorm 2018-03-11 18:01:43 +01:00
ba22d855a8 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-11 17:48:49 +01:00
e1416589b6 removed test 2018-03-11 17:48:45 +01:00
865c3c6429 changed test 2018-03-11 17:48:07 +01:00
Leen Dereu
c2951feb14 commentaar Facade 2018-03-11 17:41:35 +01:00
Leen Dereu
f0fb4a6cef TODO aanpassen 2018-03-11 16:55:02 +01:00
Leen Dereu
87946a1c20 commentaar jumpStep 2018-03-11 16:36:17 +01:00
Leen Dereu
b15ccb5cca commentaar canTurn 2018-03-11 16:23:14 +01:00
Leen Dereu
40e6a88c10 commentaar methodes ivm action points 2018-03-11 16:14:28 +01:00
Leen Dereu
a361b4abba TODO aanpassen 2018-03-11 16:05:54 +01:00
Leen Dereu
6374a40469 commentaar Worm methodes 2018-03-11 16:04:41 +01:00
Leen Dereu
2f73e0f684 TODO lijst toegevoegd (moet misschien nog uitgebreid worden) 2018-03-10 16:02:00 +01:00
Leen Dereu
c324656fc2 invarianten toevoegen 2018-03-10 15:49:30 +01:00
5e032793cb fix 2018-03-09 23:54:03 +01:00
d8981def95 lots of changes 2018-03-09 23:46:57 +01:00
d1617e9cf3 small improvements 2018-03-09 22:30:42 +01:00
d86e5d542a Fixes and improvements... 2018-03-09 22:24:06 +01:00
Leen Dereu
919cb871e3 worm.png laten werken 2018-03-09 13:28:55 +01:00
Leen Dereu
8c5a2ddb9b testen name methoden 2018-03-08 20:02:00 +01:00
Leen Dereu
4da6bf97f3 commentaar variabelen 2018-03-08 19:14:31 +01:00
Leen Dereu
1a5d4d66f2 Test functies action points, alles werkt 2018-03-08 19:10:13 +01:00
Leen Dereu
d15ed2e073 Testen geschreven + getest, 1 ding aangepast in code (setMass) 2018-03-08 19:04:15 +01:00
Leen Dereu
71282e480f aanvullen testfuncties 2018-03-08 18:51:43 +01:00
652a34e309 improved test 2018-03-08 17:50:53 +01:00
5ce16f8793 changed facade 2018-03-08 16:52:17 +01:00
8d28f1f214 Fixed setMass 2018-03-08 16:52:04 +01:00
d82212f23e added test 2018-03-08 16:37:35 +01:00
a4e9834ab0 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-08 16:14:55 +01:00
0df8b044ef improved facade 2018-03-08 16:06:09 +01:00
Leen Dereu
2add5e583a commentaar substractPoints(double angle) 2018-03-08 12:39:55 +01:00
Leen Dereu
8aefb0c492 commentaar points 2018-03-08 12:15:15 +01:00
Leen Dereu
b2aef5ff19 commentaar shape 2018-03-08 11:21:31 +01:00
Leen Dereu
42300e5b5c commentaar isValidLocation 2018-03-08 10:55:44 +01:00
Leen Dereu
14603fa5ca commentaar variabelen 2018-03-08 10:51:07 +01:00
1aa5892d3b improved Tuple and Facade 2018-03-07 22:54:53 +01:00
ecbf7a1f4c added Facade class 2018-03-07 22:41:45 +01:00
8195a30ace improvements to jumpTime / jumpStep and... 2018-03-07 22:40:57 +01:00
3c8da5825f overall improvements 2018-03-07 22:06:59 +01:00
d51de2eea5 moved files 2018-03-07 21:53:31 +01:00
4a6cc78999 Merge branch 'master' of github.com:KUL-ogp/ogp1718-gui 2018-03-07 21:49:56 +01:00
e0ac1d1958 small changes 2018-03-07 21:48:28 +01:00
Leen Dereu
1136a8ddf9 commentaar methods ivm jump 2018-03-07 20:39:28 +01:00
Leen Dereu
3f87802dd6 aanpassing commentaar turn 2018-03-07 20:11:30 +01:00
Leen Dereu
e9e6d14f0c commentaart turn 2018-03-07 20:07:46 +01:00
Leen Dereu
2bcda45bb6 commentaar move 2018-03-07 19:59:52 +01:00
Leen Dereu
9a5c68f032 Commentaar ivm name 2018-03-07 19:43:53 +01:00
Leen Dereu
6a33cab348 commentaar ivm methodes over shape 2018-03-07 19:12:06 +01:00
Leen Dereu
681804af55 commentaar set en getLocation 2018-03-07 18:49:35 +01:00
480719aa7e Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-07 18:36:23 +01:00
83e2ff1638 improved jump 2018-03-07 18:36:21 +01:00
Leen Dereu
553d41172d Commentaar methodes ivm orientation 2018-03-07 18:28:16 +01:00
Leen Dereu
5cb39b9c06 commentaar setLocation 2018-03-07 18:23:28 +01:00
d7426ca4f8 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-03-07 17:28:21 +01:00
baa10deb5d added Tuple 2018-03-07 17:28:12 +01:00
Leen Dereu
2821945d7f commentaar hoofding en orientation 2018-03-07 16:50:49 +01:00
Leen Dereu
faba6f0f11 Basis commentaar locatie 2018-03-07 16:21:44 +01:00
Leen Dereu
4429f2dc0f commentaar variabelen 2018-03-07 16:15:44 +01:00
Leen Dereu
00e082400f Classes in juiste map zetten 2018-03-07 16:01:24 +01:00
51840ceee5 implemented jump and small changes 2018-03-07 15:38:00 +01:00
Koen Yskout
6aa12c7a1e Release v1.1 2018-03-07 15:25:58 +01:00
50f8424f1f many changes 2018-03-07 05:21:19 +01:00
d594d7981b created tuple class 2018-03-07 02:40:30 +01:00
39d628f9d4 cleanup 2018-03-07 01:02:24 +01:00
Leen Dereu
f41d6c8ede overbodig document (had dit zelf aangemaakt) 2018-03-06 20:45:40 +01:00
Leen Dereu
de2d40396e Hulp bij implementatie, zie extra papier 2018-03-06 20:41:27 +01:00
Leen Dereu
94357661af Error import wegwerken 2018-03-06 20:03:06 +01:00
41128b67a4 changed constructor location and points 2018-03-01 17:14:01 +01:00
Leen Dereu
a5d8b12cdd merge 2018-02-27 12:43:36 +01:00
Leen Dereu
200e8e338a move function 2018-02-27 12:41:04 +01:00
439752a856 Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-02-27 12:39:54 +01:00
79360637f6 fixed typo 2018-02-27 12:39:51 +01:00
Leen Dereu
05a795b493 turn function 2018-02-27 12:39:04 +01:00
Leen Dereu
4d1c5ad2e3 move function 2018-02-27 12:31:33 +01:00
Leen Dereu
4a370d2d90 turn function 2018-02-27 12:27:47 +01:00
Leen Dereu
82e1cfa8d4 added turn 2018-02-27 12:26:43 +01:00
e58c4a2656 changed move 2018-02-27 12:24:44 +01:00
Leen Dereu
3545ff3894 Merge branch 'master' of https://gitlab.principis.be/OGP/worms 2018-02-27 11:37:32 +01:00
Leen Dereu
da56d42f23 added move 2018-02-27 11:37:24 +01:00
91d6a080d8 small changes 2018-02-27 11:36:47 +01:00
83ae8d18fb small changes 2018-02-27 10:47:06 +01:00
ada39c72b6 removed unnecessary revisions file 2018-02-27 08:33:45 +01:00
Leen Dereu
cb9a585e71 Openen file 2018-02-26 20:24:20 +01:00
Leen Dereu
850a721a3b Samenvatting deel 1 2018-02-26 20:23:46 +01:00
8088bfece9 some changes to worm 2018-02-26 17:57:37 +01:00
517168ef49 added getters and setters 2018-02-26 17:44:09 +01:00
3d2e56e093 Added worm constructors and name checking 2018-02-26 17:27:02 +01:00
a26b768b94 begin of worm class 2018-02-26 15:54:01 +01:00
a3d89d553e moved pdf 2018-02-26 14:56:15 +01:00
cff052bb9f updated samenvatting 2018-02-26 14:54:16 +01:00
dbbc1cfdde Merge branch 'master' of gitlab.principis.be:OGP/worms 2018-02-26 14:34:14 +01:00
b653e843e1 Merge branch 'master' of github.com:KUL-ogp/ogp1718-gui 2018-02-26 14:33:34 +01:00
Leen Dereu
d22b1f9cbb added worm class 2018-02-26 13:54:53 +01:00
47a13dac92 updated gitignore and added docs 2018-02-26 13:54:02 +01:00
9804345a83 updated gitignore 2018-02-26 13:53:09 +01:00
Leen Dereu
9b8b05f788 Opgave 2018-02-26 13:14:52 +01:00
bcf9f8d7bd initial commit 2018-02-26 13:12:44 +01:00
ca7eff1be7 added gitignore 2018-02-25 15:42:20 +01:00
26dbfd4666 add README 2018-02-25 15:32:56 +01:00
129 changed files with 18106 additions and 395 deletions

125
.gitignore vendored Normal file
View File

@@ -0,0 +1,125 @@
# Created by https://www.gitignore.io/api/eclipse,intellij+all
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
META-INF/
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### Eclipse Patch ###
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Intellij+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Ruby plugin and RubyMine
/.rakeTasks
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Intellij+all Patch ###
# Ignores the whole idea folder
# See https://github.com/joeblau/gitignore.io/issues/186 and
https://github.com/joeblau/gitignore.io/issues/360
.idea/
*.iml
# End of https://www.gitignore.io/api/eclipse,intellij+all
out/

BIN
Class Diagram3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 KiB

BIN
Class Diagram4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="src-provided"/>
<classpathentry kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="lib/AnnotationsDoclets.jar">
<attributes>
<attribute name="javadoc_location" value="http://www.cs.kuleuven.be/books/OOPWithJava/doc/"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="src" path="resources"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>1718-Worms</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<linkedResources>
<link>
<name>resources/images</name>
<type>2</type>
<locationURI>PROJECT_LOC/images</locationURI>
</link>
</linkedResources>
</projectDescription>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,3 @@
# A map with blocks
map:Blocks.png
height:20

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

View File

@@ -0,0 +1,3 @@
# A simple map
map:Simple.png
height:20

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,4 @@
# A smaller version of the skulls map,
# which may improve performance
map:Skulls-lowres.png
height:20

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

View File

@@ -0,0 +1,3 @@
# A large and complex map
map:Skulls.png
height:20

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 KiB

View File

@@ -0,0 +1,4 @@
Blocks.lvl
Simple.lvl
Skulls-lowres.lvl
Skulls.lvl

Binary file not shown.

View File

@@ -0,0 +1,35 @@
// Worm that turns towards nearest worm, fires, and moves; or turns and tries to jump if no worm is in sight.
def updateNearestWorm: {
delta := 0;
nearestWorm := null;
turnToNearest := 0;
while delta < 6.28: {
obj := searchobj delta;
if (obj != null && isworm obj):
if !sameteam obj:
if (nearestWorm == null) || (distance obj < distance nearestWorm): {
nearestWorm := obj;
turnToNearest := delta;
}
delta := delta + 0.2;
}
}
// main program
while true: {
invoke updateNearestWorm;
if nearestWorm != null: {
print nearestWorm;
print distance nearestWorm;
turn turnToNearest;
fire;
move;
}
else {
turn 0.2;
jump;
}
}

View File

@@ -0,0 +1,20 @@
def controlled_move:
if getap self > 100.0:
{ jump;
print getx self;
print gety self; }
else move;
max_distance := 10.0;
while true: {
w := searchobj 0.0;
if isworm w: {
if sameteam w:
invoke controlled_move;
else if distance w < max_distance:
fire;
else
{ turn d;
max_distance := max_distance + 0.1; }
}
}

View File

@@ -0,0 +1,3 @@
turn 0.2;
fire;
move;

View File

@@ -0,0 +1,54 @@
// don't execute this :-)
def test_proc: {
x := +1;
while true:
print false;
if x == 1: {
print x * x;
} else: {}
invoke test_proc;
break;
if 0-x/y*z - y * z - 2*x + 3 == 2 && true != false: {}
move;
jump;
eat;
fire;
}
def secondProc: {
invoke test_proc;
if getx self > 0:
invoke secondProc;
}
x := ( 3 * 4 ); // comment
// comment
y := (-33.5 * (+55 / 1.22));
jump;
turn 5;
turn 0.2;
turn -0.2;
fire;
if (x >= 5):
{ }
else
fire;
while y:
{ turn (0.01);
y := (y - 1); }
while y:
{ move;
y := (y - 1);
if (true): { turn y; }
else {
while (false):
{print y;}
}
}
if (true): { } else { invoke test_proc; }

3
OGP1718-Worms/src-provided/worms/Worms.java Normal file → Executable file
View File

@@ -22,6 +22,9 @@ public class Worms {
options.randomSeed = randomSeed;
} else if ("-clickselect".equals(arg)) {
options.enableClickToSelect = true;
} else if ("-program".equals(arg)) {
String program = args[++i];
options.programFile = program;
}
}

598
OGP1718-Worms/src-provided/worms/facade/IFacade.java Normal file → Executable file
View File

@@ -1,7 +1,13 @@
package worms.facade;
import worms.model.Worm;
import java.math.BigInteger;
import java.util.*;
import worms.internal.gui.game.IActionHandler;
import worms.model.*;
import worms.programs.IProgramFactory;
import worms.util.ModelException;
import worms.util.MustNotImplementException;
/**
* Implement this interface to connect your code to the graphical user interface
@@ -18,6 +24,12 @@ import worms.util.ModelException;
* <ul>
* <li>a class <code>Worm</code> in the package <code>worms.model</code> for
* representing a worm</li>
* <li>a class <code>World</code> in the package <code>worms.model</code> for
* representing a world</li>
* <li>a class <code>Food</code> in the package <code>worms.model</code> for
* representing a food ration</li>
* <li>a class <code>Team</code> in the package <code>worms.model</code> for
* representing a team (only for teams of 2 students)</li>
* <li>a class <code>Facade</code> in the package <code>worms.facade</code> that
* implements this interface (<code>IFacade</code>).</li>
* </ul>
@@ -31,8 +43,8 @@ import worms.util.ModelException;
*
* <li>Each method defined in the interface <code>IFacade</code> must be
* implemented by the class <code>Facade</code>. For example, the implementation
* of <code>getX</code> should call a method of the given <code>worm</code> to
* retrieve its x-coordinate.</li>
* of <code>getMass</code> should call a method of the given <code>worm</code> to
* retrieve its mass.</li>
*
* <li>Your <code>Facade</code> class should offer a default constructor.</li>
*
@@ -63,106 +75,586 @@ import worms.util.ModelException;
*/
public interface IFacade {
/**
* Create and return a new worm that is positioned at the given location, looks
* in the given direction, has the given radius and the given name.
*
* @param coordinates
* An array containing the x-coordinate of the position of the new
* worm followed by the y-coordinate of the position of the new worm
* (in meter)
* @param direction
* The direction of the new worm (in radians)
* @param radius
* The radius of the new worm (in meter)
* @param name
* The name of the new worm
*/
Worm createWorm(double[] location, double direction, double radius, String name) throws ModelException;
/************
* WORLD
************/
/**
* Moves the given worm by the given number of steps.
* Create a new world with given width and given height.
* The passable map is a rectangular matrix indicating which parts of the terrain
* are passable and which parts are impassable.
* This matrix is derived from the transparency of the pixels in the image file
* of the terrain. passableMap[r][c] is true if the location at row r and column c
* is passable, and false if that location is impassable.
* The elements in the first row (row 0) represent the pixels at the top of the
* terrain (i.e., largest y-coordinates).
* The elements in the last row (row passableMap.length-1) represent pixels at the
* bottom of the terrain (smallest y-coordinates).
* The elements in the first column (column 0) represent the pixels at the left
* of the terrain (i.e., smallest x-coordinates).
* The elements in the last column (column passableMap[0].length-1) represent the
* pixels at the right of the terrain (i.e., largest x-coordinates).
*/
void move(Worm worm, int nbSteps) throws ModelException;
public World createWorld(double width, double height,
boolean[][] passableMap) throws ModelException;
/**
* Turns the given worm by the given angle.
* Terminate the given world.
*/
void turn(Worm worm, double angle) throws ModelException;
void terminate(World world) throws ModelException;
/**
* Makes the given worm jump.
* Check whether the given worls is terminated.
*/
void jump(Worm worm) throws ModelException;
boolean isTerminated(World world) throws ModelException;
/**
* Returns the total amount of time (in seconds) that a jump of the given worm
* would take.
* Return the width of the given world.
*/
double getJumpTime(Worm worm) throws ModelException;
public double getWorldWidth(World world) throws ModelException;
/**
* Returns the location on the jump trajectory of the given worm after a time t.
*
* @return An array with two elements, with the first element being the
* x-coordinate and the second element the y-coordinate.
* Return the height of the given world.
*/
double[] getJumpStep(Worm worm, double t) throws ModelException;
public double getWorldHeight(World world) throws ModelException;
/**
* Returns the x-coordinate of the current location of the given worm.
* Check whether the given world is passable at the given location.
* - The location is an array containing the x-coordinate of the location to
* check followed by the y-coordinate of that location.
* - Locations outside the boundaries of the world are always passable.
*/
double getX(Worm worm) throws ModelException;
boolean isPassable(World world, double[] location) throws ModelException;
/**
* Returns the y-coordinate of the current location of the given worm.
* Check whether the circular area with given center and given radius
* is passable in the given world.
* - The circular area must not lie completely within the given world.
*/
double getY(Worm worm) throws ModelException;
boolean isPassable(World world, double[] center, double radius);
/**
* Returns the current orientation of the given worm (in radians).
* Check whether the circular area with given center and given radius
* is adjacent to impassable terrain in the given world.
* - The circular area must not lie completely within the given world.
*/
boolean isAdjacent(World world, double[] center, double radius);
/**
* Check whether the given world contains the given worm.
*/
boolean hasAsWorm(World world, Worm worm) throws ModelException;
/**
* Add the given worm to the given world.
*/
void addWorm(World world, Worm worm) throws ModelException;
/**
* Remove the given worm from the given world.
*/
void removeWorm(World world, Worm worm) throws ModelException;
/**
* Return a list filled with all the worms in the given world.
*/
List<Worm> getAllWorms(World world) throws ModelException;
/**
* Check whether the given world contains the given food.
*/
boolean hasAsFood(World world, Food food) throws ModelException;
/**
* Add the given portion of food to the given world.
*/
void addFood(World world, Food food) throws ModelException;
/**
* Remove the given portion of food from the given world.
*/
void removeFood(World world, Food food) throws ModelException;
/**
* Return a collection filled with all the worms and all the
* portions of food in the given world.
*/
Collection<Object> getAllItems(World world) throws ModelException;
/**
* Return a set of all the team in the given world.
*/
Set<Team> getAllTeams(World world) throws ModelException;
/**
* Check whether the given world has an active game.
*/
boolean hasActiveGame(World world) throws ModelException;
/**
* Return the active worm in the given world.
* - The active worm is the worm whose turn it is to perform
* player-controlled actions.
*/
Worm getActiveWorm(World world) throws ModelException;
/**
* Start a new game in the given world.
*/
void startGame(World world) throws ModelException;
/**
* Finish the current game, if any, in the given world.
*/
void finishGame(World world) throws ModelException;
/**
* Activate the next worm in the given world.
*/
void activateNextWorm(World world) throws ModelException;
/**
* Return the name of a single worm if that worm is the winner, or the name
* of a team if that team is the winner and the team still has several members.
*/
String getWinner(World world);
/************
* WORM
************/
/**
* Create and return a new worm that is positioned at the given location in
* the given world, that looks in the given direction, that has the given radius
* and the given name, and that is a member of the given team.
* - If the given world is not effective, the new worm is simply positioned
* at the given location.
* - If the given team is not effective, the new worm is not part of any team.
* The location is an array containing the x-coordinate of the location of
* the new worm followed by the y-coordinate of that location.
*/
Worm createWorm(World world, double[] location, double direction, double radius,
String name, Team team) throws ModelException;
/**
* Terminate the given worm.
*/
void terminate(Worm worm) throws ModelException;
/**
* Check whether the given worm is terminated.
*/
boolean isTerminated(Worm worm) throws ModelException;
/**
* Return the current location of the given worm.
* - The resulting array contains the the x-coordinate of the given worm
* followed by its y-coordinate.
*/
double[] getLocation(Worm worm) throws ModelException;
/**
* Return the current orientation of the given worm (in radians).
*/
double getOrientation(Worm worm) throws ModelException;
/**
* Returns the radius of the given worm.
* Return the radius of the given worm.
*/
double getRadius(Worm worm) throws ModelException;
/**
* Sets the radius of the given worm to the given value.
* Set the radius of the given worm to the given value.
*/
void setRadius(Worm worm, double newRadius) throws ModelException;
/**
* Returns the current number of action points of the given worm.
* Return the mass of the given worm.
*/
long getNbActionPoints(Worm worm) throws ModelException;
double getMass(Worm worm) throws ModelException;
/**
* Decreases the current number of action points of the given worm with the
* given delta.
*/
void decreaseNbActionPoints(Worm worm, long delta) throws ModelException;
/**
* Returns the maximum number of action points of the given worm.
* Return the maximum number of action points of the given worm.
*/
long getMaxNbActionPoints(Worm worm) throws ModelException;
/**
* Returns the name the given worm.
* Return the current number of action points of the given worm.
*/
long getNbActionPoints(Worm worm) throws ModelException;
/**
* Decrease the current number of action points of the given worm
* with the given delta.
* - The given delta may be negative.
*/
void decreaseNbActionPoints(Worm worm, long delta) throws ModelException;
/**
* Return the current number of hit points of the given worm.
*/
BigInteger getNbHitPoints(Worm worm) throws ModelException;
/**
* Increment the current number of hit points of the given worm
* with the given delta.
* - The given delta may be negative.
*/
void incrementNbHitPoints(Worm worm, long delta) throws ModelException;
/**
* Return the name the given worm.
*/
String getName(Worm worm) throws ModelException;
/**
* Renames the given worm.
* Rename the given worm.
*/
void rename(Worm worm, String newName) throws ModelException;
/**
* Returns the mass of the given worm.
* Return the world to which this worm belongs
*/
double getMass(Worm worm) throws ModelException;
World getWorld(Worm worm) throws ModelException;
/**
* Turn the given worm by the given angle.
*/
void turn(Worm worm, double angle);
/**
* Return the location the farthest away from its current location to which the given
* worm can move in the world in which that worm is positioned, if any, following
* the given direction and not exceeding the given maximum distance.
* - The maximum distance must be finite and may not be negative.
* - The given direction must be in the range [0.0 .. PI[.
* - On its road to the resulting location, the given worm will always be
* positioned on passable terrain.
* - The resulting position may be outside the boundaries of the world, if any, in
* which the given worm is located.
*/
double[] getFurthestLocationInDirection(Worm worm, double direction, double maxDistance) throws ModelException;
/**
* Move the given worm according to the rules in the assignment.
*/
void move(Worm worm) throws ModelException;
/**
* Returns whether the given worm can fall.
* - Students working alone on the project must not override this method.
*/
default public boolean canFall(Worm worm) throws MustNotImplementException {
return false;
}
/**
* Makes the given worm fall down until it rests on impassable terrain again,
* or until it leaves the world in which it is in.
* - Students working alone on the project must not override this method.
*/
default void fall(Worm worm) throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Return the time needed by the given worm to jump to the nearest position
* adjacent to impassable terrain.
* - deltaT determines the resolution to be used in successive steps of the jump.
*/
double getJumpTime(Worm worm, double deltaT) throws ModelException;
/**
* Returns the location on the jump trajectory of the given worm
* after a time t.
* - The resulting location is an array with two elements,
* with the first element being the x-coordinate and the
* second element the y-coordinate.
*/
double[] getJumpStep(Worm worm, double t) throws ModelException;
/**
* Make the given worm jump using the given time step.
* - The given time step determines a time interval during which
* you may assume that the worm will not move through a piece
* of impassable terrain.
*/
void jump(Worm worm, double timeStep) throws ModelException;
/**
* Make the given worm eat a portion of food.
*/
void eat(Worm worm);
/**
* Have the give worm fire a projectile.
* - The method must return the projectile that has been fired.
*/
Projectile fire(Worm worm) throws ModelException;
/************
* FOOD
************/
/**
* Create and return a new portion of food that is positioned at the given
* location in the given world.
* = If the given world is not effective, the new food is simply positioned
* at the given location.
*/
Food createFood(World world, double[] location) throws ModelException;
/**
* Terminate the given portion of food.
*/
void terminate(Food food) throws ModelException;
/**
* Check whether the given portion of food is terminated.
*/
boolean isTerminated(Food food) throws ModelException;
/**
* Return the current location of the given portion of food.
* - The resulting array contains the the x-coordinate of the given worm
* followed by its y-coordinate.
*/
double[] getLocation(Food food) throws ModelException;
/**
* Return the radius of the given portion of food.
*/
double getRadius(Food food) throws ModelException;
/**
* Return the mass of the given portion of food.
*/
double getMass(Food food) throws ModelException;
/**
* Return the world to which this portion of food belongs.
*/
World getWorld(Food food) throws ModelException;
/**
* Return whether or not the given portion of food is poisonous.
*/
boolean isPoisonous(Food food) throws ModelException;
/**
* Poison the given portion of food.
*/
void poison(Food food) throws ModelException;
/*************
* PROJECTILE
*************/
/**
* Check whether the given projectile is terminated.
*/
boolean isTerminated(Projectile projectile) throws ModelException;
/**
* Return the current orientation of the given projectile (in radians).
*/
double getOrientation(Projectile projectile) throws ModelException;
/**
* Return the current location of the given projectile.
* - The resulting array contains the the x-coordinate of the given projectile
* followed by its y-coordinate.
*/
double[] getLocation(Projectile projectile) throws ModelException;
/**
* Return the radius of the given projectile.
*/
double getRadius(Projectile projectile);
/**
* Return the number of hit points of the given projectile.
*/
int getNbHitPoints(Projectile projectile) throws ModelException;
/**
* Returns the location on the jump trajectory of the given projectile
* after a time t.
* - The resulting location is an array with two elements,
* with the first element being the x-coordinate and the
* second element the y-coordinate.
*/
double[] getJumpStep(Projectile projectile, double elapsedTime);
/**
* Return the time needed by the given projectile to jump to the nearest
* location at which the projectile hits impassable terrain or a worm.
* - deltaT determines the resolution to be used in successive steps of the jump.
*/
double getJumpTime(Projectile projectile, double jumpTimeStep) throws ModelException;
/**
* Make the given projectile jump using the given time step.
* - The given time step determines a time interval during which
* you may assume that the projectile will not hit impassable
* terrain nor a worm.
*/
void jump(Projectile projectile, double jumpTimeStep) throws ModelException;
/********
* TEAM
********/
/**
* Create a new team for the given world with given name and with no members yet.
* - Students working alone on the project must not override this method.
*/
default Team createTeam(World world, String name)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Terminate the given team.
*/
default void terminate(Team team) throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Check whether the given portion of food is terminated.
*/
default boolean isTerminated(Team team) throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Return the name of the given team.
* - Students working alone on the project must not override this method.
*/
default String getName(Team team) throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Return the team to which this worm belongs.
* - Students working alone on the project must not override this method.
*/
default Team getTeam(Worm worm) throws ModelException {
return null;
}
/**
* Return the number of worms in the given team.
* - Students working alone on the project must not override this method.
*/
default int getNbWormsOfTeam(Team team)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Return a list of all the worms in the given team, sorted alphabetically.
* This method must run in linear time.
* - Students working alone on the project must not override this method.
*/
default List<Worm> getAllWormsOfTeam(Team team)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
};
/**
* Add the given worms to the given team.
* - Students working alone on the project must not override this method.
*/
default void addWormsToTeam(Team team, Worm... worms)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Remove the given worms from the given team.
* - Students working alone on the project must not override this method.
*/
default void removeWormsFromTeam(Team team, Worm... worms)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Merge the given teams.
* - All the worms of the supplying team are transferred to the receiving team.
* - Students working alone on the project must not override this method.
*/
default void mergeTeams(Team recevingTeam, Team supplyingTeam)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**********
* PROGRAMS
**********/
/**
* Return the program loaded on the given worm.
*/
Program getWormProgram(Worm worm) throws ModelException;
/**
* Load the given program on the given worm.
*
* While executing the program, the worm must invoke the methods corresponding
* to actions through the provided ActionHandler object (e.g., actionHandler.jump(this),
* actionHandler.turn(this, 0.2), etc.) rather than invoking them directly (e.g., this.jump()).
* This executes the action as if a human player has initiated it, so the GUI can update itself.
* The GUI will also invoke the corresponding method on the worm through the facade.
*/
public void loadProgramOnWorm(Worm worm, Program program, IActionHandler actionHandler) throws ModelException;
/**
* Execute the program loaded on the given worm.
* The worm is positioned in some world. Returns null if the program
* is not completely executed. Otherwise, returns the objects that have been
* printed.
*
* This method is only used in the tests. The GUI never calls this method;
* you should execute the program when the worm is activated.
*/
public List<Object> executeProgram(Worm worm) throws ModelException;
/**
* Creates a new program factory.
*/
public IProgramFactory<?, ?, ?, ? extends Program> createProgramFactory() throws ModelException;
/*********
* WIZARD
*********/
/**
* Have the wizard cast a spell over two randomly slected game objects in the given
* world.
*/
void castSpell(World world) throws ModelException;
}

View File

View File

View File

View File

@@ -26,4 +26,11 @@ public class GUIOptions {
*/
public boolean enableClickToSelect = false;
/**
* The program that is executed by computer-controlled worms.
* Default: "programs/program.txt"
*
* Can also be set from the command line with the -program argument
*/
public String programFile = "programs/program.txt";
}

View File

@@ -12,6 +12,11 @@ import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collections;
import java.util.Random;
import worms.facade.IFacade;
import worms.model.World;
public class GUIUtils {
@@ -89,4 +94,47 @@ public class GUIUtils {
}
return url;
}
// ideally, this constant would only exist once in the code, but we cannot refer to the constant from worms.model
private static final double ADJACENCY_RADIUS_FRACTION = 0.1;
public static double[] findFreeAdjacentSpot(IFacade facade, World world, double radius, Random random) {
double worldWidth = facade.getWorldWidth(world);
double worldHeight = facade.getWorldHeight(world);
// start at random location
double x = random.nextDouble() * worldWidth;
double y = random.nextDouble() * worldHeight;
int n = 0;
// move towards center
double angle = Math.atan((worldHeight / 2 - y) / (worldWidth / 2 - x));
while (!isValidLocation(facade, world, x, y, radius)) {
// at some point, give up and start somewhere else
if (!liesInWorld(worldWidth, worldHeight, x, y) || n % 1000 == 0) {
x = random.nextDouble() * worldWidth;
y = random.nextDouble() * worldHeight;
angle = Math.atan((worldHeight / 2 - y) / (worldWidth / 2 - x));
n = 0;
}
double d = ADJACENCY_RADIUS_FRACTION / 2 * radius;
x += d * Math.cos(angle);
y += d * Math.sin(angle);
n += 1;
}
return new double[] { x, y };
}
private static boolean isValidLocation(IFacade facade, World world, double x, double y, double radius) {
double[] center = { x, y };
return facade.isPassable(world, center, radius) &&
facade.isAdjacent(world, center , radius);
}
private static boolean liesInWorld(double width, double height, double x, double y) {
return 0 <= x && x <= width && 0 <= y && y <= height;
}
public static String numberToName(int n) {
return String.join("", Collections.nCopies(n / 26, "Z")) + (char)('A' + (n % 26));
}
}

View File

@@ -1,11 +1,6 @@
package worms.internal.gui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@@ -13,59 +8,39 @@ import java.util.concurrent.TimeUnit;
import worms.facade.IFacade;
import worms.internal.gui.game.commands.Command;
import worms.model.World;
import worms.model.Worm;
public class GameState {
private final Random random;
private final IFacade facade;
private final Collection<Worm> worms = new ArrayList<Worm>();
private final BlockingQueue<Double> timeDelta = new LinkedBlockingQueue<Double>(
1);
private final int width;
private final int height;
private World world;
public GameState(IFacade facade, long randomSeed, int width, int height) {
private final Level level;
public GameState(IFacade facade, long randomSeed, Level level) {
this.random = new Random(randomSeed);
this.facade = facade;
this.width = width;
this.height = height;
this.level = level;
}
private List<String> wormNames = Arrays.asList("Shari", "Shannon",
"Willard", "Jodi", "Santos", "Ross", "Cora", "Jacob", "Homer",
"Kara");
private int nameIndex = 0;
private Iterator<Worm> selection;
private Worm selectedWorm;
public synchronized void createWorld() {
level.load();
world = facade.createWorld(level.getWorldWidth(),
level.getWorldHeight(), level.getPassableMap());
}
public IFacade getFacade() {
return facade;
}
private void createRandomWorms() {
double worldWidth = width * GUIConstants.DISPLAY_SCALE;
double worldHeight = height * GUIConstants.DISPLAY_SCALE;
for (int i = 0; i < wormNames.size(); i++) {
String name = wormNames.get(nameIndex++);
double radius = 0.25 + random.nextDouble() / 4;
double x = -worldWidth / 2 + radius + random.nextDouble()
* (worldWidth - 2 * radius);
double y = -worldHeight / 2 + radius + random.nextDouble()
* (worldHeight - 2 * radius);
double direction = random.nextDouble() * 2 * Math.PI;
Worm worm = facade.createWorm(new double[] {x, y}, direction, radius, name);
if (worm != null) {
worms.add(worm);
} else {
throw new NullPointerException("Created worm must not be null");
}
}
public Collection<Worm> getWorms() {
return getFacade().getAllWorms(getWorld());
}
public void evolve(double dt) {
@@ -93,32 +68,12 @@ public class GameState {
return cmd.isExecutionCompleted();
}
public void startGame() {
createRandomWorms();
selectNextWorm();
public Level getLevel() {
return level;
}
public Worm getSelectedWorm() {
return selectedWorm;
}
public void selectNextWorm() {
if (selection == null || !selection.hasNext()) {
selection = worms.iterator();
}
if (selection.hasNext()) {
selectWorm(selection.next());
} else {
selectWorm(null);
}
}
public void selectWorm(Worm worm) {
selectedWorm = worm;
}
public Collection<Worm> getWorms() {
return Collections.unmodifiableCollection(worms);
public synchronized World getWorld() {
return world;
}
public Random getRandom() {

View File

View File

@@ -0,0 +1,228 @@
package worms.internal.gui;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
public class Level {
private static final String LEVELS_DIRECTORY = "levels";
private static class LoadException extends RuntimeException {
private static final long serialVersionUID = 1L;
public LoadException(String message, Exception cause) {
super(message, cause);
}
}
private static class LevelFile implements Comparable<LevelFile> {
private final URL url;
private final String name;
public LevelFile(String name, URL url) {
this.name = name;
this.url = url;
}
public String getName() {
return name;
}
public URL getURL() {
return url;
}
public InputStream getInputStream() {
try {
return getURL().openStream();
} catch (IOException e) {
return null;
}
}
@Override
public int compareTo(LevelFile o) {
return getName().compareTo(o.getName());
}
}
public static Level[] getAvailableLevels() {
LevelFile[] files = getLevelFiles();
Level[] levels = new Level[files.length];
for (int i = 0; i < files.length; i++) {
levels[i] = new Level(files[i]);
}
return levels;
}
private static LevelFile[] getLevelFiles() {
InputStream levelsListFile;
try {
levelsListFile = GUIUtils.openResource(LEVELS_DIRECTORY
+ "/levels.txt");
} catch (IOException e1) {
e1.printStackTrace();
return new LevelFile[0];
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
levelsListFile));
List<LevelFile> levelURLs = new ArrayList<LevelFile>();
try {
String line = reader.readLine();
while (line != null) {
line = line.trim();
if (!line.isEmpty() && line.toLowerCase().endsWith(".lvl")) {
URL url = GUIUtils.toURL(LEVELS_DIRECTORY + "/" + line);
levelURLs.add(new LevelFile(line, url));
}
line = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
return new LevelFile[0];
} finally {
try {
reader.close();
} catch (IOException e) {
// don't care
}
}
LevelFile[] levelFiles = levelURLs.toArray(new LevelFile[levelURLs
.size()]);
Arrays.sort(levelFiles);
return levelFiles;
}
private final LevelFile file;
private BufferedImage mapImage;
private double scale;
public Level(LevelFile file) {
this.file = file;
}
public String getName() {
return file.getName().substring(0, file.getName().length() - 4);
}
public void load() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
file.getInputStream()));
readFile(reader);
reader.close();
} catch (Exception e) {
throw new LoadException("Could not load world from file "
+ file.getName(), e);
}
}
protected void readFile(BufferedReader reader) throws IOException {
this.mapImage = ImageIO.read(GUIUtils.openResource(LEVELS_DIRECTORY
+ "/" + readAsKeyVal(reader, "map")));
try {
double height = Double.parseDouble(readAsKeyVal(reader, "height"));
this.scale = height / mapImage.getHeight();
} catch (IllegalArgumentException e) {
double width = Double.parseDouble(readAsKeyVal(reader, "width"));
this.scale = width / mapImage.getWidth();
}
}
protected String readAsKeyVal(BufferedReader reader, String expectedKey)
throws IOException {
String line = reader.readLine();
while (line.isEmpty() || line.indexOf("#") == 0) {
line = reader.readLine();
}
if (line.indexOf("#") > 0) {
line = line.substring(0, line.indexOf("#")).trim();
}
int split = line.indexOf(":");
String key = line.substring(0, split);
String value = line.substring(split + 1);
if (!expectedKey.equals(key)) {
throw new IllegalArgumentException("Expected key " + expectedKey
+ ", got " + key);
}
return value;
}
public BufferedImage getMapImage() {
return mapImage;
}
public int getMapHeight() {
return mapImage.getHeight();
}
public int getMapWidth() {
return mapImage.getWidth();
}
/**
* Scale of the world (in worm-meter per map pixel)
*
* @return
*/
public double getScale() {
return scale;
}
public double getWorldWidth() {
return scale * mapImage.getWidth();
}
public double getWorldHeight() {
return scale * mapImage.getHeight();
}
public boolean[][] getPassableMap() {
final boolean[][] result = new boolean[getMapHeight()][getMapWidth()];
final byte[] bytes = ((DataBufferByte) mapImage.getRaster()
.getDataBuffer()).getData();
final int w = getMapWidth();
final int h = getMapHeight();
for (int row = 0; row < h; row++) {
final int offset = w * row;
for (int col = 0; col < w; col++) {
final byte alpha = bytes[4 * (offset + col)];
// alpha < 128 ((alpha & 0xf) == 0) => passable
// alpha >= 128 ((alpha & 0xf) != 0) => impassable
if (((int) alpha & 0xf0) == 0) {
result[row][col] = true;
}
}
}
return result;
}
/**
* map width / map height
*/
public double getMapAspectRatio() {
return (double) getMapWidth() / getMapHeight();
}
/**
* world width / world height
*/
public double getWorldAspectRatio() {
return getWorldWidth() / getWorldHeight();
}
}

View File

View File

View File

@@ -5,11 +5,17 @@ import java.util.concurrent.Executors;
import worms.facade.IFacade;
import worms.internal.gui.GameState;
import worms.internal.gui.game.commands.ActivateWizard;
import worms.internal.gui.game.commands.AddNewFood;
import worms.internal.gui.game.commands.AddNewTeam;
import worms.internal.gui.game.commands.AddNewWorm;
import worms.internal.gui.game.commands.Command;
import worms.internal.gui.game.commands.Eat;
import worms.internal.gui.game.commands.Fire;
import worms.internal.gui.game.commands.Jump;
import worms.internal.gui.game.commands.Move;
import worms.internal.gui.game.commands.Rename;
import worms.internal.gui.game.commands.Resize;
import worms.internal.gui.game.commands.SelectNextWorm;
import worms.internal.gui.game.commands.StartGame;
import worms.internal.gui.game.commands.Turn;
import worms.internal.gui.messages.MessageType;
@@ -84,11 +90,38 @@ class DefaultActionHandler implements IActionHandler {
executeCommand(new Rename(getFacade(), worm, newName, getScreen()));
}
@Override
public boolean eat(Worm worm) {
return executeCommand(new Eat(getFacade(), worm, getScreen()));
}
@Override
public boolean fire(Worm worm) {
return executeCommand(new Fire(getFacade(), worm, getScreen()));
}
public void selectNextWorm() {
executeCommand(new SelectNextWorm(getFacade(), getScreen()));
}
public void startGame() {
executeCommand(new StartGame(getFacade(), getScreen()));
}
public void resizeWorm(Worm worm, int sign) {
executeCommand(new Resize(getFacade(), worm, 1 + sign * 0.2, getScreen()));
public void addNewWorm(boolean withProgram) {
executeCommand(new AddNewWorm(getFacade(), withProgram, getScreen()));
}
public void addEmptyTeam(String name) {
executeCommand(new AddNewTeam(getFacade(), name, getScreen()));
}
public void addNewFood() {
executeCommand(new AddNewFood(getFacade(), getScreen()));
}
public void activateWizard() {
executeCommand(new ActivateWizard(getFacade(), getScreen()));
}
}

View File

@@ -14,6 +14,7 @@ import worms.model.Worm;
* <li>shows periodic updates on the GUI (such as jump animations)
* <li>eventually calls the corresponding facade methods, exactly like what
* happens with a human player
* <li>makes sure a worm will fall after moving
* <li>returns true if the action has been completed successfully; false
* otherwise
* </ul>
@@ -30,6 +31,10 @@ public interface IActionHandler {
public boolean jump(Worm worm);
public boolean eat(Worm worm);
public boolean fire(Worm worm);
/**
* Print a message on the screen for a short amount of time.
*

View File

View File

@@ -1,23 +1,33 @@
package worms.internal.gui.game;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import worms.facade.IFacade;
import worms.internal.gui.GUIConstants;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.GameState;
import worms.internal.gui.InputMode;
import worms.internal.gui.Level;
import worms.internal.gui.Screen;
import worms.internal.gui.WormsGUI;
import worms.internal.gui.game.modes.DefaultInputMode;
import worms.internal.gui.game.modes.EnteringNameMode;
import worms.internal.gui.game.modes.GameOverMode;
import worms.internal.gui.game.modes.SetupInputMode;
import worms.internal.gui.game.sprites.FoodSprite;
import worms.internal.gui.game.sprites.WormSprite;
import worms.internal.gui.messages.MessageType;
import worms.model.Food;
import worms.model.Team;
import worms.model.World;
import worms.model.Worm;
public class PlayGameScreen extends Screen {
@@ -47,13 +57,12 @@ public class PlayGameScreen extends Screen {
@Override
protected InputMode<PlayGameScreen> createDefaultInputMode() {
return new DefaultInputMode(this, null);
return new SetupInputMode(this, null);
}
@Override
public void screenStarted() {
runGameLoop();
userActionHandler.startGame();
}
final AtomicLong lastUpdateTimestamp = new AtomicLong();
@@ -69,6 +78,7 @@ public class PlayGameScreen extends Screen {
repaint();
}
};
private Worm currentWorm;
private void runGameLoop() {
Timer timer = new Timer();
@@ -77,27 +87,44 @@ public class PlayGameScreen extends Screen {
public void uncaughtException(Thread t, Throwable e) {
gameLoop.cancel();
e.printStackTrace();
getGUI().showError(
e.getClass().getName() + ": " + e.getMessage());
getGUI().showError(e.getClass().getName() + ": " + e.getMessage());
}
});
lastUpdateTimestamp.set(System.currentTimeMillis());
timer.scheduleAtFixedRate(gameLoop, 0, 1000 / GUIConstants.FRAMERATE);
}
public void gameFinished() {
addMessage("Game over! The winner is " + getFacade().getWinner(getWorld())
+ "\n\nPress 'R' to start another game, or 'ESC' to quit.", MessageType.NORMAL);
gameLoop.cancel();
switchInputMode(new GameOverMode(this, getCurrentInputMode()));
}
public synchronized void update() {
removeInactiveSprites();
addNewSprites();
for (Sprite<?> sprite : sprites) {
sprite.update();
}
currentWorm = getFacade().getActiveWorm(getWorld());
}
protected void removeInactiveSprites() {
for (Sprite<?> sprite : new ArrayList<Sprite<?>>(sprites)) {
if (!sprite.isObjectAlive()) {
removeSprite(sprite);
}
}
}
protected void addNewSprites() {
addNewWormSprites();
addNewFoodSprites();
}
private void addNewWormSprites() {
Collection<Worm> worms = getGameState().getWorms();
Collection<Worm> worms = getFacade().getAllWorms(getWorld());
if (worms != null) {
for (Worm worm : worms) {
WormSprite sprite = getWormSprite(worm);
@@ -108,6 +135,28 @@ public class PlayGameScreen extends Screen {
}
}
private void addNewFoodSprites() {
Collection<Food> foods = getAll(Food.class);
if (foods != null) {
for (Food food : foods) {
FoodSprite sprite = getSpriteOfTypeFor(FoodSprite.class, food);
if (sprite == null) {
createFoodSprite(food);
}
}
}
}
private <T> Collection<T> getAll(Class<T> type) {
return getFacade().getAllItems(getWorld()).stream().filter(type::isInstance).map(type::cast)
.collect(Collectors.toSet());
}
private void createFoodSprite(Food food) {
FoodSprite sprite = new FoodSprite(this, food);
addSprite(sprite);
}
private void createWormSprite(Worm worm) {
WormSprite sprite = new WormSprite(this, worm);
addSprite(sprite);
@@ -168,6 +217,22 @@ public class PlayGameScreen extends Screen {
}
public void eat() {
Worm worm = getSelectedWorm();
if (worm != null) {
userActionHandler.eat(worm);
}
}
public void fire() {
Worm worm = getSelectedWorm();
if (worm != null) {
userActionHandler.fire(worm);
}
}
public void turn(double angle) {
Worm worm = getSelectedWorm();
angle = GUIUtils.restrictAngle(angle, -Math.PI);
@@ -186,7 +251,7 @@ public class PlayGameScreen extends Screen {
}
public synchronized Worm getSelectedWorm() {
return getGameState().getSelectedWorm();
return currentWorm;
}
@Override
@@ -194,8 +259,7 @@ public class PlayGameScreen extends Screen {
painter.paint(g);
}
public static PlayGameScreen create(WormsGUI gui, GameState gameState,
boolean debugMode) {
public static PlayGameScreen create(WormsGUI gui, GameState gameState, boolean debugMode) {
if (!debugMode) {
return new PlayGameScreen(gui, gameState);
} else {
@@ -208,6 +272,14 @@ public class PlayGameScreen extends Screen {
}
}
protected Level getLevel() {
return getGameState().getLevel();
}
public World getWorld() {
return getGameState().getWorld();
}
public void addSprite(Sprite<?> sprite) {
sprites.add(sprite);
}
@@ -216,11 +288,40 @@ public class PlayGameScreen extends Screen {
sprites.remove(sprite);
}
/**
* Aspect ratio of the screen
*/
private double getScreenAspectRatio() {
return (double) getScreenWidth() / getScreenHeight();
}
/**
* Width of the world when displayed (in pixels)
*/
private double getWorldDisplayWidth() {
if (getLevel().getMapAspectRatio() >= getScreenAspectRatio()) {
return getScreenWidth();
} else {
return getScreenHeight() * getLevel().getMapAspectRatio();
}
}
/**
* Height of the world when displayed (in pixels)
*/
private double getWorldDisplayHeight() {
if (getLevel().getMapAspectRatio() <= getScreenAspectRatio()) {
return getScreenHeight();
} else {
return getScreenWidth() / getLevel().getMapAspectRatio();
}
}
/**
* Scale of the displayed world (in worm-meter per pixel)
*/
private double getDisplayScale() {
return GUIConstants.DISPLAY_SCALE;
return getLevel().getWorldWidth() / getWorldDisplayWidth();
}
/**
@@ -241,36 +342,39 @@ public class PlayGameScreen extends Screen {
* World x coordinate to screen x coordinate
*/
public double getScreenX(double x) {
return getScreenWidth()/2.0 + worldToScreenDistance(x);
double offset = (getScreenWidth() - getWorldDisplayWidth()) / 2.0;
return offset + worldToScreenDistance(x);
}
/**
* Screen x coordinate to world x coordinate
*/
public double getLogicalX(double screenX) {
return screenToWorldDistance(screenX - getScreenWidth()/2.0);
double offset = (getScreenWidth() - getWorldDisplayWidth()) / 2.0;
return screenToWorldDistance(screenX - offset);
}
/**
* World y coordinate to screen y coordinate
*/
public double getScreenY(double y) {
return getScreenHeight()/2.0 - worldToScreenDistance(y);
double offset = (getScreenHeight() - getWorldDisplayHeight()) / 2.0;
return offset + getWorldDisplayHeight() - worldToScreenDistance(y);
}
/**
* Screen y coordinate to world y coordinate
*/
public double getLogicalY(double screenY) {
return screenToWorldDistance(getScreenHeight()/2.0 - screenY);
double offset = (getScreenHeight() - getWorldDisplayHeight()) / 2.0;
return screenToWorldDistance(-screenY + offset + getWorldDisplayHeight());
}
public void paintTextEntry(Graphics2D g, String message, String enteredName) {
painter.paintTextEntry(g, message, enteredName);
}
public void drawTurnAngleIndicator(Graphics2D g, WormSprite wormSprite,
double currentAngle) {
public void drawTurnAngleIndicator(Graphics2D g, WormSprite wormSprite, double currentAngle) {
painter.drawTurnAngleIndicator(g, wormSprite, currentAngle);
}
@@ -285,13 +389,45 @@ public class PlayGameScreen extends Screen {
return (InputMode<PlayGameScreen>) super.getCurrentInputMode();
}
public void addEmptyTeam() {
switchInputMode(
new EnteringNameMode("Enter team name: ", this, getCurrentInputMode(), newName -> userActionHandler.addEmptyTeam(newName)));
}
private Team lastTeam;
public void setLastCreatedTeam(Team team) {
this.lastTeam = team;
}
public Team getLastCreatedTeam() {
return lastTeam;
}
public void addPlayerControlledWorm() {
userActionHandler.addNewWorm(false);
}
public void addComputerControlledWorm() {
userActionHandler.addNewWorm(true);
}
public void addFood() {
userActionHandler.addNewFood();
}
public void startGame() {
lastTeam = null;
userActionHandler.startGame();
}
public void gameStarted() {
switchInputMode(new DefaultInputMode(this, getCurrentInputMode()));
}
public void renameWorm() {
switchInputMode(new EnteringNameMode("Enter new name for worm: ", this,
getCurrentInputMode(), new EnteringNameMode.Callback() {
switchInputMode(new EnteringNameMode("Enter new name for worm: ", this, getCurrentInputMode(),
new EnteringNameMode.Callback() {
@Override
public void onNameEntered(String newName) {
changeName(newName);
@@ -308,11 +444,7 @@ public class PlayGameScreen extends Screen {
}
public void selectNextWorm() {
getGameState().selectNextWorm();
}
public IActionHandler getProgramActionHandler() {
return programActionHandler;
userActionHandler.selectNextWorm();
}
public void selectWorm(Worm worm) {
@@ -321,12 +453,12 @@ public class PlayGameScreen extends Screen {
}
}
public void resizeWorm(int sign) {
Worm worm = getSelectedWorm();
public IActionHandler getProgramActionHandler() {
return programActionHandler;
}
if (worm != null) {
userActionHandler.resizeWorm(worm, sign);
}
public void activateWizard() {
userActionHandler.activateWizard();
}
}

View File

@@ -1,25 +1,126 @@
package worms.internal.gui.game;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D.Double;
import java.awt.image.BufferedImage;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.Level;
import worms.internal.gui.game.sprites.FoodSprite;
import worms.internal.gui.game.sprites.WormSprite;
import worms.model.World;
public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
private static final int LOCATION_MARKER_SIZE = 4;
private static final double MAX_DIVERSION = 0.7875;
private static final boolean PAINT_PASSABLE = true;
/**
* Step size for sampling; lower = more details (but takes longer)
*/
private static final double PASSABLE_STEP_SIZE = 3; // screen pixels
/**
* Radius for sampling; lower = more details (but takes longer)
*/
private static final double PASSABLE_TEST_RADIUS = 10 ; // screen pixels
private Image passableImage;
public PlayGameScreenDebugPainter(PlayGameScreen screen) {
super(screen);
}
@Override
public void paint(Graphics2D g) {
super.paint(g);
}
@Override
protected void paintLevel() {
super.paintLevel();
if (passableImage == null) {
BufferedImage image = createPassableImage();
this.passableImage = image;
}
currentGraphics.drawImage(passableImage, 0, 0, null);
drawCrossMarker(getScreenX(0), getScreenY(0), 10, Color.BLUE);
drawCrossMarker(getScreenX(0), getScreenY(getLevel().getWorldHeight()),
10, Color.BLUE);
drawCrossMarker(getScreenX(getLevel().getWorldWidth()), getScreenY(0),
10, Color.BLUE);
drawCrossMarker(getScreenX(getLevel().getWorldWidth()),
getScreenY(getLevel().getWorldHeight()), 10, Color.BLUE);
}
protected BufferedImage createPassableImage() {
Level level = getState().getLevel();
World world = getState().getWorld();
BufferedImage image = new BufferedImage(getScreen().getScreenWidth(),
getScreen().getScreenHeight(), BufferedImage.TYPE_4BYTE_ABGR);
BufferedImage adjacencyImage = new BufferedImage(getScreen()
.getScreenWidth(), getScreen().getScreenHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D imGfx = image.createGraphics();
imGfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Graphics2D imAdjacencyGfx = adjacencyImage.createGraphics();
imAdjacencyGfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
double testRadius = getScreen().screenToWorldDistance(PASSABLE_TEST_RADIUS);
double stepSize = getScreen().screenToWorldDistance(PASSABLE_STEP_SIZE);
for (double x = testRadius; x <= level.getWorldWidth() - testRadius; x += stepSize) {
for (double y = testRadius; y <= level.getWorldHeight()
- testRadius; y += stepSize) {
double randomizedX = x + (-0.5 + Math.random()) * stepSize * 2;
double randomizedY = y + (-0.5 + Math.random()) * stepSize * 2;
Graphics2D targetGraphics = imGfx;
boolean isPassable = false;
if (!getState().getFacade().isPassable(world, new double[] {randomizedX,
randomizedY}, testRadius)) {
targetGraphics.setColor(new Color(255, 0, 0, 4));
} else if (getState().getFacade().isAdjacent(world,
new double[] { randomizedX, randomizedY} , testRadius)) {
targetGraphics = imAdjacencyGfx;
targetGraphics.setColor(new Color(0, 255, 0, 64));
} else {
isPassable = true;
targetGraphics.setColor(new Color(0, 0, 255, 4));
}
if (!isPassable || PAINT_PASSABLE) {
Double circle = GUIUtils.circleAt(getScreenX(randomizedX),
getScreenY(randomizedY), getScreen()
.worldToScreenDistance(testRadius));
targetGraphics.fill(circle);
}
}
}
imGfx.drawImage(adjacencyImage, 0, 0, null);
imAdjacencyGfx.dispose();
imGfx.dispose();
return image;
}
@Override
protected void paintWorm(WormSprite sprite) {
drawName(sprite);
drawActionBar(sprite);
drawHitpointsBar(sprite);
drawOutline(sprite);
drawJumpMarkers(sprite); // also draw for other worms
@@ -30,11 +131,6 @@ public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
}
@Override
protected void paintLevel() {
drawCrossMarker(getScreenX(0), getScreenY(0), 10, Color.BLUE);
}
@Override
protected void drawJumpMarkers(WormSprite sprite) {
@@ -70,6 +166,21 @@ public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
Color.YELLOW);
}
@Override
protected void paintFood(FoodSprite sprite) {
super.paintFood(sprite);
double r = sprite.getRadius();
double x = sprite.getCenterX();
double y = sprite.getCenterY();
currentGraphics.setColor(Color.CYAN);
Shape circle = GUIUtils.circleAt(x, y, getScreen()
.worldToScreenDistance(r));
currentGraphics.fill(circle);
currentGraphics.setColor(Color.DARK_GRAY);
currentGraphics.draw(circle);
}
protected void drawOutline(WormSprite sprite) {
double r = sprite.getRadius();
double x = sprite.getCenterX();
@@ -92,6 +203,18 @@ public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
currentGraphics.drawLine((int) x, (int) y,
(int) (x + dist * Math.cos(direction)),
(int) (y - dist * Math.sin(direction)));
// draw move tolerance
direction = direction - MAX_DIVERSION;
currentGraphics.drawLine((int) x, (int) y,
(int) (x + dist * Math.cos(direction)),
(int) (y - dist * Math.sin(direction)));
direction = direction + 2 * MAX_DIVERSION;
currentGraphics.drawLine((int) x, (int) y,
(int) (x + dist * Math.cos(direction)),
(int) (y - dist * Math.sin(direction)));
}
}

View File

@@ -3,6 +3,7 @@ package worms.internal.gui.game;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
@@ -14,17 +15,28 @@ import java.util.StringTokenizer;
import worms.internal.gui.AbstractPainter;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.GameState;
import worms.internal.gui.Level;
import worms.internal.gui.game.sprites.FoodSprite;
import worms.internal.gui.game.sprites.ProjectileSprite;
import worms.internal.gui.game.sprites.WormSprite;
import worms.model.World;
import worms.util.ModelException;
public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
protected static final Color SELECTION_FILL_COLOR = new Color(0xaa84b6cc, true);
protected static final Color SELECTION_IMPASSABLE_FILL_COLOR = new Color(0xaacc8484, true);
protected static final Color SELECTION_OUTLINE_COLOR = new Color(0xaaffffff, true);
protected static final Color DIRECTION_MARKER_COLOR = new Color(0xcc84b6cc, true);
protected static final Color TURN_ANGLE_MARKER_COLOR = new Color(0xcccc84b6, true);
protected static final Color SELECTION_FILL_COLOR = new Color(0xaa84b6cc,
true);
protected static final Color SELECTION_IMPASSABLE_FILL_COLOR = new Color(
0xaacc8484, true);
protected static final Color SELECTION_OUTLINE_COLOR = new Color(
0xaaffffff, true);
protected static final Color DIRECTION_MARKER_COLOR = new Color(0xcc84b6cc,
true);
protected static final Color TURN_ANGLE_MARKER_COLOR = new Color(
0xcccc84b6, true);
protected static final Color INVALID_TURN_ANGLE_MARKER_COLOR = Color.RED;
protected static final Color ACTION_POINTS_COLOR = new Color(0xcc00cc00, true);
protected static final Color ACTION_POINTS_COLOR = new Color(0xcc00cc00,
true);
protected static final double ACTION_BAR_WIDTH = 30;
protected static final double ACTION_BAR_HEIGHT = 5;
@@ -32,15 +44,16 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
protected static final Color HIT_POINTS_COLOR = new Color(0xccff6a00, true);
protected static final Color BAR_OUTLINE_COLOR = Color.WHITE;
protected static final Color NAME_BAR_BACKGROUND = new Color(0x40ffffff, true);
protected static final Color WEAPON_BAR_BACKGROUND = new Color(0x806666ff, true);
protected static final Color NAME_BAR_BACKGROUND = new Color(0x40ffffff,
true);
protected static final Color NAME_BAR_TEXT = Color.WHITE;
protected static final double TEXT_BAR_H_MARGIN = 4;
protected static final double TEXT_BAR_V_MARGIN = 3;
protected static final double TEXT_BAR_V_OFFSET = 2;
protected static final Color RENAME_BACKGROUND_COLOR = new Color(0x600e53a7, true);
protected static final Color RENAME_BACKGROUND_COLOR = new Color(
0x600e53a7, true);
protected static final Color RENAME_TEXT_COLOR = Color.WHITE;
protected static final Color JUMP_MARKER_COLOR = Color.GRAY;
@@ -48,20 +61,41 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
protected static final double DIRECTION_INDICATOR_SIZE = 10;
protected Graphics2D currentGraphics;
private Image scaledImage;
public PlayGameScreenPainter(PlayGameScreen screen) {
super(screen);
}
private void createBackgroundImage() {
if (scaledImage == null) {
scaledImage = GUIUtils.scaleTo(getState().getLevel().getMapImage(),
getScreen().getScreenWidth(),
getScreen().getScreenHeight(), Image.SCALE_SMOOTH);
}
}
protected GameState getState() {
return getScreen().getGameState();
}
protected World getWorld() {
return getState().getWorld();
}
protected Level getLevel() {
return getState().getLevel();
}
public void paint(Graphics2D g) {
this.currentGraphics = g;
paintLevel();
for (FoodSprite sprite : getScreen().getSpritesOfType(FoodSprite.class)) {
paintFood(sprite);
}
for (WormSprite sprite : getScreen().getSpritesOfType(WormSprite.class)) {
if (sprite.getWorm() == getScreen().getSelectedWorm()) {
drawSelection(sprite);
@@ -69,11 +103,28 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
paintWorm(sprite);
}
for (ProjectileSprite sprite : getScreen().getSpritesOfType(
ProjectileSprite.class)) {
paintProjectile(sprite);
}
this.currentGraphics = null;
}
protected void paintLevel() {
protected void paintProjectile(ProjectileSprite sprite) {
sprite.draw(currentGraphics);
}
protected void paintFood(FoodSprite sprite) {
sprite.draw(currentGraphics);
}
protected void paintLevel() {
createBackgroundImage();
int x = (int) getScreenX(0);
int y = (int) getScreenY(getLevel().getWorldHeight());
currentGraphics.drawImage(scaledImage, x, y, null);
}
protected double getScreenX(double x) {
@@ -91,6 +142,7 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
drawName(sprite);
drawActionBar(sprite);
drawHitpointsBar(sprite);
if (getScreen().getSelectedWorm() == sprite.getWorm()) {
drawDirectionIndicator(sprite);
@@ -106,16 +158,29 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
name = "(null)";
}
Rectangle2D bounds = currentGraphics.getFontMetrics().getStringBounds(name, currentGraphics);
String teamName = null;
try {
teamName = sprite.getTeamName();
} catch (ModelException e) {
// no team
}
if (teamName != null) {
name += " (" + teamName + ")";
}
Rectangle2D bounds = currentGraphics.getFontMetrics().getStringBounds(
name, currentGraphics);
final double stringWidth = bounds.getWidth();
final double stringHeight = bounds.getHeight();
final double x = sprite.getCenterX() - stringWidth / 2;
final double y = sprite.getCenterY() - voffset - TEXT_BAR_V_OFFSET;
RoundRectangle2D nameBarFill = new RoundRectangle2D.Double(x - TEXT_BAR_H_MARGIN,
y - stringHeight - TEXT_BAR_V_MARGIN, stringWidth + 2 * TEXT_BAR_H_MARGIN,
stringHeight + 2 * TEXT_BAR_V_MARGIN, 5, 5);
RoundRectangle2D nameBarFill = new RoundRectangle2D.Double(x
- TEXT_BAR_H_MARGIN, y - stringHeight - TEXT_BAR_V_MARGIN,
stringWidth + 2 * TEXT_BAR_H_MARGIN, stringHeight + 2
* TEXT_BAR_V_MARGIN, 5, 5);
currentGraphics.setColor(NAME_BAR_BACKGROUND);
currentGraphics.fill(nameBarFill);
@@ -132,23 +197,53 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
double actionPoints = sprite.getActionPoints();
double maxActionPoints = sprite.getMaxActionPoints();
RoundRectangle2D actionBarFill = new RoundRectangle2D.Double(x - ACTION_BAR_WIDTH / 2, y + spriteHeight / 2,
actionPoints * ACTION_BAR_WIDTH / maxActionPoints, ACTION_BAR_HEIGHT, 5, 5);
RoundRectangle2D actionBarFill = new RoundRectangle2D.Double(x
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2, actionPoints
* ACTION_BAR_WIDTH / maxActionPoints, ACTION_BAR_HEIGHT, 5, 5);
currentGraphics.setColor(ACTION_POINTS_COLOR);
currentGraphics.fill(actionBarFill);
RoundRectangle2D actionBar = new RoundRectangle2D.Double(x - ACTION_BAR_WIDTH / 2, y + spriteHeight / 2,
ACTION_BAR_WIDTH, ACTION_BAR_HEIGHT, 5, 5);
RoundRectangle2D actionBar = new RoundRectangle2D.Double(x
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2, ACTION_BAR_WIDTH,
ACTION_BAR_HEIGHT, 5, 5);
currentGraphics.setColor(BAR_OUTLINE_COLOR);
currentGraphics.draw(actionBar);
}
protected void drawHitpointsBar(WormSprite sprite) {
double x = sprite.getCenterX();
double y = sprite.getCenterY();
double spriteHeight = sprite.getHeight(currentGraphics);
double hitPoints = sprite.getHitPoints().doubleValue();
double maxHitPoints = 2000;
hitPoints = Math.min(hitPoints, maxHitPoints);
RoundRectangle2D hitpointsBarFill = new RoundRectangle2D.Double(x
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2
+ ACTION_BAR_HEIGHT, hitPoints * ACTION_BAR_WIDTH
/ maxHitPoints, ACTION_BAR_HEIGHT, 5, 5);
currentGraphics.setColor(HIT_POINTS_COLOR);
currentGraphics.fill(hitpointsBarFill);
RoundRectangle2D hitpointsBar = new RoundRectangle2D.Double(x
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2
+ ACTION_BAR_HEIGHT, ACTION_BAR_WIDTH, ACTION_BAR_HEIGHT, 5, 5);
currentGraphics.setColor(BAR_OUTLINE_COLOR);
currentGraphics.draw(hitpointsBar);
}
protected void drawSelection(WormSprite sprite) {
double x = sprite.getCenterX();
double y = sprite.getCenterY();
double spriteHeight = Math.max(sprite.getWidth(currentGraphics), sprite.getHeight(currentGraphics));
double spriteHeight = Math.max(sprite.getWidth(currentGraphics),
sprite.getHeight(currentGraphics));
currentGraphics.setColor(SELECTION_FILL_COLOR);
if (sprite.isAtImpassableTerrain()) {
currentGraphics.setColor(SELECTION_IMPASSABLE_FILL_COLOR);
} else {
currentGraphics.setColor(SELECTION_FILL_COLOR);
}
Shape circle = GUIUtils.circleAt(x, y, spriteHeight / 2);
currentGraphics.fill(circle);
@@ -157,41 +252,47 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
protected void drawDirectionIndicator(WormSprite sprite) {
double x = sprite.getCenterX();
double y = sprite.getCenterY();
double distance = Math.max(sprite.getWidth(currentGraphics), sprite.getHeight(currentGraphics)) / 2;
double distance = Math.max(sprite.getWidth(currentGraphics),
sprite.getHeight(currentGraphics)) / 2;
distance += DIRECTION_INDICATOR_SIZE / 2;
double direction = GUIUtils.restrictDirection(sprite.getOrientation());
currentGraphics.setColor(DIRECTION_MARKER_COLOR);
Shape directionIndicator = new Ellipse2D.Double(
x + distance * Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE / 2, DIRECTION_INDICATOR_SIZE,
DIRECTION_INDICATOR_SIZE);
Shape directionIndicator = new Ellipse2D.Double(x + distance
* Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE
/ 2, DIRECTION_INDICATOR_SIZE, DIRECTION_INDICATOR_SIZE);
currentGraphics.fill(directionIndicator);
}
void drawTurnAngleIndicator(Graphics2D graphics, WormSprite sprite, double angle) {
void drawTurnAngleIndicator(Graphics2D graphics, WormSprite sprite,
double angle) {
if (sprite == null) {
return;
}
double x = sprite.getCenterX();
double y = sprite.getCenterY();
double distance = Math.max(sprite.getWidth(graphics), sprite.getHeight(graphics)) / 2;
double distance = Math.max(sprite.getWidth(graphics),
sprite.getHeight(graphics)) / 2;
distance += DIRECTION_INDICATOR_SIZE / 2;
double direction = GUIUtils.restrictDirection(sprite.getOrientation() + angle);
double direction = GUIUtils.restrictDirection(sprite.getOrientation()
+ angle);
/*
* can't do this when getting information from sprite if
* (getFacade().canTurn(sprite.getWorm(), angle)) {
* graphics.setColor(TURN_ANGLE_MARKER_COLOR); } else {
* graphics.setColor(INVALID_TURN_ANGLE_MARKER_COLOR); }
*/
can't do this when getting information from sprite
if (getFacade().canTurn(sprite.getWorm(), angle)) {
graphics.setColor(TURN_ANGLE_MARKER_COLOR);
} else {
graphics.setColor(INVALID_TURN_ANGLE_MARKER_COLOR);
}
*/
graphics.setColor(TURN_ANGLE_MARKER_COLOR);
Shape directionIndicator = new Ellipse2D.Double(
x + distance * Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE / 2, DIRECTION_INDICATOR_SIZE,
DIRECTION_INDICATOR_SIZE);
Shape directionIndicator = new Ellipse2D.Double(x + distance
* Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE
/ 2, DIRECTION_INDICATOR_SIZE, DIRECTION_INDICATOR_SIZE);
graphics.fill(directionIndicator);
}
@@ -202,7 +303,8 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
if (xy != null) {
double jumpX = getScreenX(xy[0]);
double jumpY = getScreenY(xy[1]);
drawCrossMarker(jumpX, jumpY, JUMP_MARKER_SIZE, JUMP_MARKER_COLOR);
drawCrossMarker(jumpX, jumpY, JUMP_MARKER_SIZE,
JUMP_MARKER_COLOR);
}
}
}
@@ -210,8 +312,10 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
protected void drawCrossMarker(double x, double y, int size, Color color) {
currentGraphics.setColor(color);
currentGraphics.drawLine((int) (x - size), (int) y, (int) (x + size), (int) y);
currentGraphics.drawLine((int) x, (int) (y - size), (int) x, (int) (y + size));
currentGraphics.drawLine((int) (x - size), (int) y, (int) (x + size),
(int) y);
currentGraphics.drawLine((int) x, (int) (y - size), (int) x,
(int) (y + size));
}
void paintTextEntry(Graphics2D g, String message, String enteredText) {
@@ -219,7 +323,8 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
g.fillRect(0, 0, getScreen().getScreenWidth(), 120);
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));
g.setColor(RENAME_TEXT_COLOR);
GUIUtils.drawCenteredString(g, message + enteredText + "\u2502", getScreen().getScreenWidth(), 100);
GUIUtils.drawCenteredString(g, message + enteredText + "\u2502",
getScreen().getScreenWidth(), 100);
}
public void paintInstructions(Graphics2D g, String message) {

View File

@@ -20,6 +20,8 @@ public abstract class Sprite<T> {
public abstract T getObject();
public abstract boolean isObjectAlive();
protected IFacade getFacade() {
return getScreen().getFacade();
}

View File

@@ -0,0 +1,29 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.util.ModelException;
public class ActivateWizard extends InstantaneousCommand {
public ActivateWizard(IFacade facade,
PlayGameScreen screen) {
super(facade, screen);
}
@Override
protected boolean canStart() {
return true;
}
@Override
protected void doStartExecution() {
try {
getFacade().castSpell(getWorld());
getScreen().addMessage("The wizard has done wizardry things!", MessageType.INFO);
} catch (ModelException e) {
getScreen().addMessage("The wizard could not cast its spell :(", MessageType.ERROR);
}
}
}

View File

@@ -0,0 +1,38 @@
package worms.internal.gui.game.commands;
import java.util.Random;
import worms.facade.IFacade;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.util.ModelException;
public class AddNewFood extends InstantaneousCommand {
private static final double FOOD_RADIUS = 0.20;
public AddNewFood(IFacade facade, PlayGameScreen screen) {
super(facade, screen);
}
@Override
protected boolean canStart() {
return true;
}
@Override
protected void doStartExecution() {
try {
Random random = getScreen().getGameState().getRandom();
double[] p = GUIUtils.findFreeAdjacentSpot(getFacade(), getWorld(), FOOD_RADIUS, random);
getFacade().createFood(getWorld(), p);
} catch (ModelException e) {
e.printStackTrace();
getScreen().addMessage("Error while adding new food", MessageType.ERROR);
}
}
}

View File

@@ -0,0 +1,41 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.model.Team;
import worms.util.ModelException;
public class AddNewTeam extends InstantaneousCommand {
private final String name;
public AddNewTeam(IFacade facade, String name, PlayGameScreen screen) {
super(facade, screen);
this.name = name;
}
@Override
protected boolean canStart() {
return true;
}
@Override
protected void doStartExecution() {
try {
Team team = getFacade().createTeam(getWorld(), name);
getScreen().addMessage("Team " + name + " created.", MessageType.NORMAL);
getScreen().setLastCreatedTeam(team);
} catch (ModelException e) {
e.printStackTrace();
getScreen().addMessage(
"Could not create team " + name + ": " + e.getMessage(),
MessageType.ERROR);
}
}
@Override
protected void afterExecutionCompleted() {
}
}

View File

@@ -0,0 +1,130 @@
package worms.internal.gui.game.commands;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Random;
import worms.facade.IFacade;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.WormsGUI;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.model.Program;
import worms.model.Team;
import worms.model.Worm;
import worms.programs.IProgramFactory;
import worms.programs.ParseOutcome;
import worms.programs.ProgramParser;
import worms.util.ModelException;
public class AddNewWorm extends InstantaneousCommand {
private static final double MIN_RADIUS = 0.25;
private static final double MAX_RADIUS = Math.pow(2, 1.0 / 3.0) * MIN_RADIUS;
private boolean withProgram;
public AddNewWorm(IFacade facade, boolean withProgram, PlayGameScreen screen) {
super(facade, screen);
this.withProgram = withProgram;
}
@Override
protected boolean canStart() {
return true;
}
@Override
protected void doStartExecution() {
try {
Random random = getScreen().getGameState().getRandom();
int nbWorms = getFacade().getAllWorms(getWorld()).size();
String name = "Worm " + GUIUtils.numberToName(nbWorms++);
// ensures minimum radius and team size conditions are always fulfilled
double radius = MIN_RADIUS + (MAX_RADIUS - MIN_RADIUS) * random.nextDouble();
double[] p = GUIUtils.findFreeAdjacentSpot(getFacade(), getWorld(), radius, random);
double direction = random.nextDouble() * 2 * Math.PI;
Team team = getScreen().getLastCreatedTeam();
Worm worm = getFacade().createWorm(getWorld(), p, direction, radius, name, team);
if (withProgram) {
loadProgram(worm);
}
} catch (ModelException e) {
e.printStackTrace();
getScreen().addMessage("Could not create worm", MessageType.ERROR);
}
}
private void loadProgram(Worm worm) {
String programText = readProgramText();
if (programText != null) {
IProgramFactory<?, ?, ?, ? extends Program> factory = getFacade().createProgramFactory();
ProgramParser<?, ?, ?, ? extends Program> parser = ProgramParser.create(factory);
ParseOutcome<? extends Program> outcome = parser.parseString(programText);
if (outcome != null) {
if (outcome.isSuccess()) {
Program program = outcome.getSuccessValue();
getFacade().loadProgramOnWorm(worm, program, getScreen().getProgramActionHandler());
} else {
List<String> errors = outcome.getFailValue();
String msg = "Parsing failed\nwith the following errors:\n";
for (String error : errors) {
msg += error + "\n";
}
cancelExecution();
getGUI().showError(msg);
return;
}
}
} else {
cancelExecution();
getGUI().showError("Could not parse program");
}
}
private WormsGUI getGUI() {
return getScreen().getGUI();
}
protected String readProgramText() {
InputStream stream;
try {
stream = GUIUtils.openResource(getGUI().getOptions().programFile);
} catch (IOException e) {
e.printStackTrace();
getGUI().showError(e.getMessage());
return null;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder programText = new StringBuilder();
String line;
try {
line = reader.readLine();
while (line != null) {
programText.append(line);
programText.append("\n");
line = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
cancelExecution(e);
return null;
} finally {
try {
reader.close();
} catch (IOException e) {
// I don't care
}
}
return programText.toString();
}
}

View File

@@ -2,6 +2,7 @@ package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.model.World;
public abstract class Command {
@@ -26,6 +27,10 @@ public abstract class Command {
return facade;
}
protected World getWorld() {
return getScreen().getWorld();
}
public final void startExecution() {
if (canStart()) {
started = true;
@@ -37,8 +42,12 @@ public abstract class Command {
}
protected final void cancelExecution() {
cancelExecution(null);
}
protected final void cancelExecution(Throwable e) {
cancelled = true;
afterExecutionCancelled();
afterExecutionCancelled(e);
}
protected final void completeExecution() {
@@ -52,6 +61,9 @@ public abstract class Command {
doUpdate(dt);
if (isTerminated()) {
getScreen().update();
if (!getFacade().hasActiveGame(getWorld())) {
getScreen().gameFinished();
}
}
}
}
@@ -71,12 +83,11 @@ public abstract class Command {
}
/**
* Returns whether or not the execution of this command is terminated,
* either by cancellation or by successful completion.
* Returns whether or not the execution of this command is terminated, either by
* cancellation or by successful completion.
*/
public final boolean isTerminated() {
return isExecutionCancelled()
|| (hasBeenStarted() && isExecutionCompleted());
return isExecutionCancelled() || (hasBeenStarted() && isExecutionCompleted());
}
/**
@@ -111,9 +122,10 @@ public abstract class Command {
}
/**
* Called when the execution of the command has been cancelled.
* Called when the execution of the command has been cancelled, with an optional
* throwable that indicates the cause of the cancellation.
*/
protected void afterExecutionCancelled() {
protected void afterExecutionCancelled(Throwable e) {
}
/**
@@ -131,11 +143,8 @@ public abstract class Command {
@Override
public String toString() {
return this.getClass().getSimpleName()
+ " ("
+ (hasBeenStarted() ? "elapsed: "
+ String.format("%.2f", getElapsedTime()) + "s)"
: "queued)");
return this.getClass().getSimpleName() + " ("
+ (hasBeenStarted() ? "elapsed: " + String.format("%.2f", getElapsedTime()) + "s)" : "queued)");
}
}

View File

@@ -0,0 +1,37 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.model.Food;
import worms.model.Worm;
import worms.util.ModelException;
public class Eat extends InstantaneousCommand {
private final Worm worm;
public Eat(IFacade facade, Worm worm,
PlayGameScreen screen) {
super(facade, screen);
this.worm = worm;
}
@Override
protected boolean canStart() {
return worm != null;
}
@Override
protected void doStartExecution() {
try {
long nbFoodBefore = getFacade().getAllItems(getWorld()).stream().filter(Food.class::isInstance).count();
getFacade().eat(worm);
long nbFoodAfter = getFacade().getAllItems(getWorld()).stream().filter(Food.class::isInstance).count();
if (nbFoodAfter < nbFoodBefore) {
getScreen().addMessage("Yummie!", MessageType.INFO);
}
} catch (ModelException e) {
getScreen().addMessage("This worm cannot eat.", MessageType.ERROR);
}
}
}

View File

@@ -0,0 +1,83 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.GUIConstants;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.game.sprites.ProjectileSprite;
import worms.internal.gui.messages.MessageType;
import worms.model.Projectile;
import worms.model.Worm;
import worms.util.ModelException;
public class Fire extends Command {
private final Worm worm;
private Projectile projectile;
private double totalDuration;
private boolean hasJumped;
public Fire(IFacade facade, Worm worm, PlayGameScreen screen) {
super(facade, screen);
this.worm = worm;
}
@Override
protected boolean canStart() {
return worm != null;
}
@Override
protected void doStartExecution() {
try {
projectile = getFacade().fire(worm);
if (projectile != null) {
totalDuration = getFacade().getJumpTime(projectile, GUIConstants.JUMP_TIME_STEP);
ProjectileSprite sprite = new ProjectileSprite(getScreen(), projectile);
sprite.update();
getScreen().addSprite(sprite);
} else {
cancelExecution();
}
} catch (ModelException e) {
e.printStackTrace();
cancelExecution();
}
}
@Override
protected void afterExecutionCompleted() {
super.afterExecutionCompleted();
ProjectileSprite sprite = getScreen().getSpriteOfTypeFor(ProjectileSprite.class, projectile);
if (sprite != null) {
sprite.setDoneMoving();
}
}
@Override
protected void afterExecutionCancelled(Throwable e) {
getScreen().addMessage("This worm cannot shoot :(" + (e != null ? "\n" + e.getMessage() : ""),
MessageType.ERROR);
}
@Override
protected void doUpdate(double dt) {
try {
if (getElapsedTime() >= totalDuration) {
if (!hasJumped) {
hasJumped = true;
getFacade().jump(projectile, GUIConstants.JUMP_TIME_STEP);
completeExecution();
}
} else {
ProjectileSprite sprite = getScreen().getSpriteOfTypeFor(ProjectileSprite.class, projectile);
double[] xy = getFacade().getJumpStep(projectile, getElapsedTime());
sprite.setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
}
} catch (ModelException e) {
e.printStackTrace();
cancelExecution();
}
}
}

View File

@@ -1,6 +1,7 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.GUIConstants;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.game.sprites.WormSprite;
import worms.internal.gui.messages.MessageType;
@@ -21,7 +22,6 @@ public class Jump extends Command {
return worm;
}
@Override
protected boolean canStart() {
return getWorm() != null;
@@ -30,19 +30,21 @@ public class Jump extends Command {
@Override
protected void doStartExecution() {
try {
this.jumpDuration = getFacade().getJumpTime(worm);
this.jumpDuration = getFacade().getJumpTime(worm, GUIConstants.JUMP_TIME_STEP);
} catch (ModelException e) {
cancelExecution();
e.printStackTrace();
cancelExecution(e);
}
}
@Override
protected void afterExecutionCancelled() {
protected void afterExecutionCancelled(Throwable e) {
WormSprite sprite = getScreen().getWormSprite(getWorm());
if (sprite != null) {
sprite.setIsJumping(false);
}
getScreen().addMessage("This worm cannot jump :(", MessageType.ERROR);
getScreen().addMessage("This worm cannot jump :(" + (e != null ? "\n" + e.getMessage() : ""),
MessageType.ERROR);
}
@Override
@@ -62,19 +64,16 @@ public class Jump extends Command {
if (getElapsedTime() >= jumpDuration) {
if (!hasJumped) {
hasJumped = true;
getFacade()
.jump(getWorm());
double x = getFacade().getX(getWorm());
double y = getFacade().getY(getWorm());
sprite.setCenterLocation(getScreen().getScreenX(x),
getScreen().getScreenY(y));
getFacade().jump(getWorm(), GUIConstants.JUMP_TIME_STEP);
if (!getFacade().isTerminated(getWorm())) {
double[] xy = getFacade().getLocation(getWorm());
sprite.setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
}
completeExecution();
}
} else {
double[] xy = getFacade().getJumpStep(getWorm(),
getElapsedTime());
sprite.setCenterLocation(getScreen().getScreenX(xy[0]),
getScreen().getScreenY(xy[1]));
double[] xy = getFacade().getJumpStep(getWorm(), getElapsedTime());
sprite.setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
}
} catch (ModelException e) {
e.printStackTrace();

View File

@@ -7,6 +7,7 @@ import worms.internal.gui.game.sprites.WormSprite;
import worms.internal.gui.messages.MessageType;
import worms.model.Worm;
import worms.util.ModelException;
import worms.util.MustNotImplementException;
public class Move extends Command {
@@ -16,6 +17,9 @@ public class Move extends Command {
private double finalX;
private double finalY;
private boolean isFalling;
private double fallingStartTime = -1;
private final Worm worm;
public Move(IFacade facade, Worm worm, PlayGameScreen screen) {
@@ -36,6 +40,14 @@ public class Move extends Command {
return GUIConstants.MOVE_DURATION;
}
protected boolean canFall() {
try {
return getFacade().canFall(getWorm());
} catch (MustNotImplementException e) {
return false;
}
}
@Override
protected void doUpdate(double dt) {
WormSprite sprite = getScreen().getWormSprite(getWorm());
@@ -48,6 +60,45 @@ public class Move extends Command {
double y = (1.0 - t) * startY + t * finalY;
sprite.setCenterLocation(x, y);
} else {
fall(dt);
}
} else {
cancelExecution();
}
}
protected boolean isFalling() {
return isFalling;
}
protected void ensureFalling() {
if (fallingStartTime == -1) {
fallingStartTime = getElapsedTime();
}
isFalling = true;
}
protected void fall(double dt) {
if (!isFalling) {
startFalling();
} else {
updateFalling();
}
}
protected void updateFalling() {
WormSprite sprite = getScreen().getWormSprite(worm);
if (sprite != null) {
double duration = getScreen().screenToWorldDistance(Math.abs(finalY - startY)) / GUIConstants.FALL_VELOCITY;
double timeElapsedFalling = getElapsedTime() - fallingStartTime;
if (timeElapsedFalling <= duration) {
double t = timeElapsedFalling / duration;
t = t * t;
double x = (1.0 - t) * startX + t * finalX;
double y = (1.0 - t) * startY + t * finalY;
sprite.setCenterLocation(x, y);
} else {
sprite.setCenterLocation(finalX, finalY);
completeExecution();
}
} else {
@@ -55,6 +106,35 @@ public class Move extends Command {
}
}
protected void startFalling() {
this.startX = getScreen().getScreenX(getObjectX());
this.startY = getScreen().getScreenY(getObjectY());
if (canFall()) {
ensureFalling();
getFacade().fall(getWorm());
if (isObjectStillActive()) {
this.finalX = getScreen().getScreenX(getObjectX());
this.finalY = getScreen().getScreenY(getObjectY());
} else {
this.finalX = startX;
try {
this.finalY = getScreen().getScreenY(getObjectY());
} catch (ModelException e) {
this.finalY = getScreen().getScreenY(0);
}
}
} else {
completeExecution();
}
WormSprite sprite = getScreen().getWormSprite(worm);
if (sprite != null) {
sprite.setCenterLocation(startX, startY);
} else {
cancelExecution();
}
}
@Override
protected void afterExecutionCompleted() {
WormSprite sprite = getScreen().getWormSprite(getWorm());
@@ -64,34 +144,39 @@ public class Move extends Command {
}
@Override
protected void afterExecutionCancelled() {
protected void afterExecutionCancelled(Throwable e) {
WormSprite sprite = getScreen().getWormSprite(getWorm());
if (sprite != null) {
sprite.setIsMoving(false);
}
getScreen().addMessage("This worm cannot move like that :(",
getScreen().addMessage("This worm cannot move like that :(" + (e != null ? "\n" + e.getMessage() : ""),
MessageType.ERROR);
}
@Override
protected void doStartExecution() {
try {
this.startX = getScreen().getScreenX(getObjectX());
this.startY = getScreen().getScreenY(getObjectY());
getFacade().move(getWorm(), 1);
this.finalX = getScreen().getScreenX(getObjectX());
this.finalY = getScreen().getScreenY(getObjectY());
double[] xy = getFacade().getLocation(getWorm());
this.startX = getScreen().getScreenX(xy[0]);
this.startY = getScreen().getScreenY(xy[1]);
getFacade().move(getWorm());
xy = getFacade().getLocation(getWorm());
this.finalX = getScreen().getScreenX(xy[0]);
this.finalY = getScreen().getScreenY(xy[1]);
} catch (ModelException e) {
e.printStackTrace();
cancelExecution();
cancelExecution(e);
}
}
protected boolean isObjectStillActive() {
return !getFacade().isTerminated(getWorm());
}
protected double getObjectX() {
return getFacade().getX(getWorm());
return getFacade().getLocation(getWorm())[0];
}
protected double getObjectY() {
return getFacade().getY(getWorm());
return getFacade().getLocation(getWorm())[1];
}
}

View File

@@ -1,40 +0,0 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.game.sprites.WormSprite;
import worms.internal.gui.messages.MessageType;
import worms.model.Worm;
import worms.util.ModelException;
public class Resize extends InstantaneousCommand {
private final Worm worm;
private final double factor;
public Resize(IFacade facade, Worm worm, double factor,
PlayGameScreen screen) {
super(facade, screen);
this.worm = worm;
this.factor = factor;
}
@Override
protected boolean canStart() {
return worm != null;
}
@Override
protected void doStartExecution() {
try {
double newRadius = factor * getFacade().getRadius(worm);
getFacade().setRadius(worm, newRadius);
} catch (ModelException e) {
// an invalid radius
getScreen().addMessage(
"Cannot " + (factor > 1.0 ? "grow" : "shrink")
+ " that worm anymore :(", MessageType.ERROR);
}
WormSprite sprite = getScreen().getWormSprite(worm);
sprite.update();
}
}

View File

@@ -0,0 +1,34 @@
package worms.internal.gui.game.commands;
import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.util.ModelException;
public class SelectNextWorm extends InstantaneousCommand {
public SelectNextWorm(IFacade facade, PlayGameScreen screen) {
super(facade, screen);
}
@Override
protected boolean canStart() {
return true;
}
@Override
protected void afterExecutionCancelled(Throwable e) {
getScreen().addMessage("Cannot activate next worm :(" + (e != null ? "\n" + e.getMessage() : ""), MessageType.ERROR);
}
@Override
protected void doStartExecution() {
try {
getFacade().activateNextWorm(getWorld());
} catch (ModelException e) {
cancelExecution(e);
}
}
}

View File

@@ -6,6 +6,7 @@ import worms.facade.IFacade;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.model.Worm;
import worms.util.ModelException;
public class StartGame extends InstantaneousCommand {
@@ -15,18 +16,31 @@ public class StartGame extends InstantaneousCommand {
@Override
protected boolean canStart() {
Collection<Worm> worms = getScreen().getGameState().getWorms();
Collection<Worm> worms = getFacade().getAllWorms(getWorld());
return worms != null && !worms.isEmpty();
}
@Override
protected void afterExecutionCancelled() {
getScreen().addMessage("Cannot start the game without worms", MessageType.ERROR);
protected void afterExecutionCancelled(Throwable e) {
if (e != null) {
getScreen().addMessage("Cannot start the game: " + e.getMessage(), MessageType.ERROR);
e.printStackTrace();
} else {
getScreen().addMessage("Cannot start the game without worms", MessageType.ERROR);
}
}
@Override
protected void doStartExecution() {
getScreen().gameStarted();
try {
getScreen().gameStarted();
getFacade().startGame(getWorld());
if (!getFacade().hasActiveGame(getWorld())) {
getScreen().gameFinished();
}
} catch (ModelException e) {
cancelExecution(e);
}
}
}

View File

@@ -5,6 +5,7 @@ import worms.internal.gui.GUIUtils;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
import worms.model.Worm;
import worms.util.ModelException;
public class Turn extends InstantaneousCommand {
private final Worm worm;
@@ -22,15 +23,18 @@ public class Turn extends InstantaneousCommand {
}
@Override
protected void afterExecutionCancelled() {
getScreen().addMessage("This worm cannot perform that turn :(",
MessageType.ERROR);
protected void afterExecutionCancelled(Throwable e) {
getScreen().addMessage("This worm cannot perform that turn :(" + (e != null ? "\n" + e.getMessage() : ""), MessageType.ERROR);
}
@Override
protected void doStartExecution() {
double direction = getFacade().getOrientation(worm);
double angleToTurn = GUIUtils.restrictDirection(direction + angle) - direction;
getFacade().turn(worm, angleToTurn);
try {
double direction = getFacade().getOrientation(worm);
double angleToTurn = GUIUtils.restrictDirection(direction + angle) - direction;
getFacade().turn(worm, angleToTurn);
} catch (ModelException e) {
cancelExecution(e);
}
}
}

View File

@@ -51,11 +51,17 @@ public class DefaultInputMode extends InputMode<PlayGameScreen> {
case 'N':
getScreen().renameWorm();
break;
case '+':
getScreen().resizeWorm(+1);
case 'e':
case 'E':
getScreen().eat();
break;
case '-':
getScreen().resizeWorm(-1);
case 'f':
case 'F':
getScreen().fire();
break;
case 's':
case 'S':
getScreen().activateWizard();
break;
}
}

View File

@@ -8,6 +8,7 @@ import worms.internal.gui.game.PlayGameScreen;
public class EnteringNameMode extends InputMode<PlayGameScreen> {
@FunctionalInterface
public static interface Callback {
public void onNameEntered(String newName);
}

View File

@@ -0,0 +1,46 @@
package worms.internal.gui.game.modes;
import java.awt.event.KeyEvent;
import worms.internal.gui.InputMode;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.menu.MainMenuScreen;
public class GameOverMode extends InputMode<PlayGameScreen> {
/**
* @param playGameScreen
*/
public GameOverMode(PlayGameScreen playGameScreen,
InputMode<PlayGameScreen> previous) {
super(playGameScreen, previous);
}
@Override
public void keyTyped(KeyEvent e) {
switch (e.getKeyChar()) {
case 'r':
case 'R':
// need to do this on a new thread, because otherwise the GUI will be blocked on the main menu
new Thread(new Runnable() {
@Override
public void run() {
getScreen().getGUI().switchToScreen(
new MainMenuScreen(getScreen().getGUI()));
}
}).start();
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
getScreen().getGUI().exit();
break;
}
}
}

View File

@@ -0,0 +1,64 @@
package worms.internal.gui.game.modes;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import worms.internal.gui.InputMode;
import worms.internal.gui.game.PlayGameScreen;
public class SetupInputMode extends InputMode<PlayGameScreen> {
public SetupInputMode(PlayGameScreen screen,
InputMode<PlayGameScreen> previous) {
super(screen, previous);
}
@Override
public void keyTyped(KeyEvent e) {
switch (e.getKeyChar()) {
case 't':
case 'T':
getScreen().addEmptyTeam();
break;
case 'w':
case 'W':
getScreen().addPlayerControlledWorm();
break;
case 'c':
case 'C':
getScreen().addComputerControlledWorm();
break;
case 'f':
case 'F':
getScreen().addFood();
break;
case 's':
case 'S':
getScreen().startGame();
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
getScreen().getGUI().exit();
break;
}
}
@Override
public void paintOverlay(Graphics2D g) {
getScreen()
.showInstructions(
g,
"Press\n"
+ "'T' to create a new team\n"
+ "'W' to add a new player-controlled worm\n"
+ "'C' to add a new computer-controlled worm\n"
+ "'F' to add food\n"
+ "'S' to start the game");
}
}

View File

@@ -0,0 +1,129 @@
package worms.internal.gui.game.sprites;
import java.awt.Image;
import java.awt.image.BufferedImage;
import worms.internal.gui.game.ImageSprite;
import worms.internal.gui.game.PlayGameScreen;
import worms.model.Food;
public class FoodSprite extends ImageSprite<Food> {
private static final double MAX_SCALE = 100;
private static final double MIN_SCALE = 0.05;
private final Food food;
private double radius;
private boolean poisonous = false;
// original image, at original scale
private final BufferedImage originalPoisonousImage;
// only created when scale != 1.0
private BufferedImage scaledPoisonousImage;
public FoodSprite(PlayGameScreen screen, Food food) {
super(screen, "images/burger.png");
this.food = food;
// constraint: must have same dimensions as original image
// constraint: does not respect hflipping
this.originalPoisonousImage = loadImage("images/burger-poisonous.png");
this.scaledPoisonousImage = this.originalPoisonousImage;
update();
}
/**
* @param radius
* (in worm-meter)
*/
public synchronized void setRadius(double radius) {
this.radius = radius;
/*
* Height of the image (when drawn at native size) in worm-meters, given
* the scale at which the world is drawn to screen
*/
double imageHeightInMeters = getScreen().screenToWorldDistance(
getImageHeight());
/*
* scale factor to nicely fit the image in a circle with diameter equal
* to the image height (value determined experimentally)
*/
double fitFactor = 1.2;
double scaleFactor = fitFactor * 2 * radius / imageHeightInMeters;
scaleFactor = Math.max(MIN_SCALE, Math.min(scaleFactor, MAX_SCALE));
setScale(scaleFactor);
}
@Override
public void setScale(double newScale) {
double oldScale = getScale();
super.setScale(newScale);
if (newScale == oldScale) {
return;
}
if (newScale != 1.0) {
this.scaledPoisonousImage = toBufferedImage(originalPoisonousImage.getScaledInstance(
(int) (newScale * originalPoisonousImage.getWidth()),
(int) (newScale * originalPoisonousImage.getHeight()),
Image.SCALE_SMOOTH));
} else {
this.scaledPoisonousImage = originalPoisonousImage;
}
}
@Override
protected Image getImageToDraw() {
if (isPoisonous()) {
return scaledPoisonousImage;
} else {
return super.getImageToDraw();
}
}
public synchronized double getRadius() {
return radius;
}
public synchronized boolean isPoisonous() {
return poisonous;
}
public void setPoisonous(boolean poisonous) {
this.poisonous = poisonous;
}
@Override
public synchronized void update() {
setPoisonous(getFacade().isPoisonous(getFood()));
setRadius(getFacade().getRadius(getFood()));
double[] xy = getFacade().getLocation(getFood());
setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
}
@Override
public Food getObject() {
return getFood();
}
public Food getFood() {
return food;
}
@Override
public boolean isObjectAlive() {
return !getFacade().isTerminated(food);
}
}

View File

@@ -0,0 +1,143 @@
package worms.internal.gui.game.sprites;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.game.Sprite;
import worms.model.Projectile;
public class ProjectileSprite extends Sprite<Projectile> {
private static final int MIN_DISPLAY_SIZE = 3; // pixels
private static final int MAX_DISPLAY_SIZE = 10; // pixels
private static final int DISPLAY_SCALE = 10;
private static final int NB_HISTORY = 15;
private static final Color[] colors = new Color[NB_HISTORY];
static {
for (int i = 0; i < colors.length; i++) {
float t = (float) i / colors.length;
colors[i] = new Color(1.0F, (1 - t), 0, 0.8F);
}
}
private final Projectile projectile;
private double sizeInPixels;
@SuppressWarnings("serial")
private static class LimitedQueue<E> extends LinkedList<E> {
private int limit;
public LimitedQueue(int limit) {
this.limit = limit;
}
@Override
public boolean add(E o) {
boolean result = super.add(o);
while (size() > limit) {
super.remove();
}
return result;
}
}
private final List<double[]> lastLocations = Collections.synchronizedList(new LimitedQueue<double[]>(
NB_HISTORY));
private boolean moving;
public ProjectileSprite(PlayGameScreen screen, Projectile projectile) {
super(screen);
this.projectile = projectile;
this.moving = true;
}
@Override
public synchronized void draw(Graphics2D g) {
if (moving) {
for (int i = 0; i < lastLocations.size(); i++) {
double[] loc = lastLocations.get(i);
g.setColor(colors[i]);
double t = (double) (i + 1) / lastLocations.size();
double size = sizeInPixels * t * t * t;
g.fill(GUIUtils.circleAt(loc[0], loc[1], size));
}
} else {
g.setColor(colors[NB_HISTORY-1]);
g.fill(GUIUtils.circleAt(getCenterX(), getCenterY(), sizeInPixels));
}
}
@Override
public Projectile getObject() {
return getProjectile();
}
public Projectile getProjectile() {
return projectile;
}
public synchronized void setSize(double sizeInPixels) {
this.sizeInPixels = Math.min(MAX_DISPLAY_SIZE,
Math.max(MIN_DISPLAY_SIZE, DISPLAY_SCALE * sizeInPixels));
}
@Override
public double getHeight(Graphics2D g) {
return sizeInPixels;
}
@Override
public double getWidth(Graphics2D g) {
return sizeInPixels;
}
@Override
public boolean isObjectAlive() {
return !getFacade().isTerminated(getProjectile());
}
@Override
public synchronized void update() {
setSize(getScreen().worldToScreenDistance(getFacade().getRadius(getProjectile())));
double[] loc = getFacade().getLocation(getProjectile());
setCenterLocation(getScreen().getScreenX(loc[0]), getScreen().getScreenY(loc[1]));
}
@Override
public synchronized void setCenterLocation(double x, double y) {
super.setCenterLocation(x, y);
if (moving && !lastLocations.isEmpty()) {
// do some averaving to show some intermediate positions for
// fast-moving object (rifle projectiles)
if (lastLocations.size() > 1) {
double[] c1 = lastLocations.get(lastLocations.size() - 1);
double[] c2 = lastLocations.get(0);
lastLocations.add(new double[] { (c1[0] + c2[0]) / 2,
(c1[1] + c2[1]) / 2 });
}
double[] prev = lastLocations.get(lastLocations.size() - 1);
lastLocations.remove(prev);
for (int i = 0; i < NB_HISTORY; i++) {
if (prev != null) {
double t = (double) i / (NB_HISTORY);
lastLocations.add(new double[] { t * x + (1 - t) * prev[0],
t * y + (1 - t) * prev[1] });
}
}
}
lastLocations.add(new double[] { x, y });
}
public synchronized void setDoneMoving() {
this.moving = false;
}
}

View File

@@ -1,10 +1,15 @@
package worms.internal.gui.game.sprites;
import java.math.BigInteger;
import worms.internal.gui.GUIConstants;
import worms.internal.gui.GUIUtils;
import worms.internal.gui.game.ImageSprite;
import worms.internal.gui.game.PlayGameScreen;
import worms.model.Team;
import worms.model.Worm;
import worms.util.ModelException;
import worms.util.MustNotImplementException;
public class WormSprite extends ImageSprite<Worm> {
@@ -17,8 +22,11 @@ public class WormSprite extends ImageSprite<Worm> {
private double[][] xys;
private double orientation;
private String name;
private String teamName;
private boolean atImpassableTerrain;
private long actionPoints;
private long maxActionPoints;
private BigInteger hitPoints;
private double actualX;
private double actualY;
private double radius;
@@ -82,23 +90,43 @@ public class WormSprite extends ImageSprite<Worm> {
return dx * dx + dy * dy <= radius * radius;
}
@Override
public boolean isObjectAlive() {
return !getFacade().isTerminated(getWorm());
}
@Override
public synchronized void update() {
double[] xy = getFacade().getLocation(getWorm());
if (isJumping || isMoving) {
// don't update the location here, because it may differ from the
// location in the model
// location in the model (interpolation)
} else {
setCenterLocation(getScreen().getScreenX(getFacade().getX(getWorm())),
getScreen().getScreenY(getFacade().getY(worm)));
setCenterLocation(
getScreen().getScreenX(xy[0]),
getScreen().getScreenY(xy[1]));
}
this.actualX = getFacade().getX(getWorm());
this.actualY = getFacade().getY(getWorm());
this.actualX = xy[0];
this.actualY = xy[1];
setRadius(getFacade().getRadius(getWorm()));
setDirection(getFacade().getOrientation(getWorm()));
updateJumpTime();
setName(getFacade().getName(getWorm()));
try {
Team team = getFacade().getTeam(getWorm());
if (team != null) {
setTeamName(getFacade().getName(team));
} else {
setTeamName("_teamless_");
}
} catch (MustNotImplementException e) {
setTeamName("No Teams");
}
this.atImpassableTerrain = !getFacade().isPassable(getScreen().getWorld(),
xy, getFacade().getRadius(getWorm()));
this.actionPoints = getFacade().getNbActionPoints(getWorm());
this.maxActionPoints = getFacade().getMaxNbActionPoints(getWorm());
this.hitPoints = getFacade().getNbHitPoints(getWorm());
}
public void setIsJumping(boolean isJumping) {
@@ -113,7 +141,7 @@ public class WormSprite extends ImageSprite<Worm> {
private void updateJumpTime() {
try {
double time = getFacade().getJumpTime(getWorm());
double time = getFacade().getJumpTime(getWorm(), GUIConstants.JUMP_TIME_STEP);
if (time > 0) {
int n = 1 + (int) (time / JUMP_MARKER_TIME_DISTANCE);
xys = new double[n][];
@@ -146,6 +174,18 @@ public class WormSprite extends ImageSprite<Worm> {
this.name = name;
}
public synchronized String getTeamName() {
return teamName;
}
private void setTeamName(String teamName) {
this.teamName = teamName;
}
public synchronized boolean isAtImpassableTerrain() {
return atImpassableTerrain;
}
public synchronized long getActionPoints() {
return actionPoints;
}
@@ -154,6 +194,10 @@ public class WormSprite extends ImageSprite<Worm> {
return maxActionPoints;
}
public synchronized BigInteger getHitPoints() {
return hitPoints;
}
public synchronized double getActualX() {
return actualX;
}

View File

@@ -0,0 +1,30 @@
package worms.internal.gui.menu;
import worms.internal.gui.Level;
import worms.internal.gui.WormsGUI;
class ChooseLevelScreen extends AbstractMenuScreen<Level> {
public ChooseLevelScreen(WormsGUI gui) {
super(gui);
}
@Override
protected Level[] getChoices() {
return Level.getAvailableLevels();
}
@Override
protected String getDisplayName(Level level) {
return level.getName();
}
@Override
protected String getInstructions() {
return "Choose the level you want to play";
}
@Override
public void screenStarted() {
}
}

View File

@@ -1,8 +1,10 @@
package worms.internal.gui.menu;
import worms.internal.gui.GameState;
import worms.internal.gui.Level;
import worms.internal.gui.WormsGUI;
import worms.internal.gui.game.PlayGameScreen;
import worms.internal.gui.messages.MessageType;
enum MainMenuOption {
Play("Play worms"), PlayDebug("Play worms (debug mode)"), Exit("Exit");
@@ -56,13 +58,28 @@ public class MainMenuScreen extends AbstractMenuScreen<MainMenuOption> {
private void startGame(boolean debugMode) {
WormsGUI gui = getGUI();
ChooseLevelScreen chooseLevel = new ChooseLevelScreen(gui);
getGUI().switchToScreen(chooseLevel);
Level level = chooseLevel.select();
if (debugMode) {
chooseLevel
.addMessage(
"Loading level, please wait...\n\n(This can take a while in debug mode)",
MessageType.NORMAL);
} else {
chooseLevel.addMessage("Loading level, please wait...",
MessageType.NORMAL);
}
GameState gameState = new GameState(gui.getFacade(),
gui.getOptions().randomSeed, gui.getWidth(), gui.getHeight());
gui.getOptions().randomSeed, level);
PlayGameScreen playGameScreen = PlayGameScreen.create(gui, gameState,
debugMode);
gameState.startGame();
gameState.createWorld();
getGUI().switchToScreen(playGameScreen);
}

View File

View File

View File

@@ -0,0 +1,446 @@
package worms.programs;
import java.util.ArrayList;
import java.util.List;
import worms.util.ModelException;
import worms.util.MustNotImplementException;
/**
* A program factory is used by the parser ({@link ProgramParser}) to construct
* an in-memory representation of your program. For example, when reading the
* program source code
*
* <pre>
* print 2.0
* </pre>
*
* the parser will create a Program object by (conceptually) executing the
* following code:
*
* <pre>
* factory.createProgram(Collections.emptyList(),
* factory.createPrintStatement(factory.createDoubleLiteral(2.0)));
* </pre>
*
* on the returned factory object.
*
* <p>
* For testing, you may use the methods from {@link ProgramParser} yourself.
* </p>
*
* <p>
* You should declare your class as follows:<code><pre>
* public class ProgramFactory implements IProgramFactory&lt;MyExpression, MyStatement, MyProc, Program&gt;
* </pre></code> where MyExpression, MyStatement and MyProc are your classes
* for representing expressions, statements and procedure definitions,
* respectively.
*
* <p>
* The SourceLocation object in the methods defined by this factory refers to
* the location (line and column) in the text file where the statement or
* expression begins.
*
* @param <E>
* Your class for representing an expression.
* @param <S>
* Your class for representing a statement.
* @param <P>
* Your class for representing a procedure.
* @param <Program>
* Your class for representing a program (should be Program).
*
*
*/
public interface IProgramFactory<E, S, P, Program> {
/* PROGRAM */
/**
* Create a program from the given arguments.
*
* @param procs
* The procedure definitions for the program.
* @param main
* The main statement of the program. Most likely this is a
* sequence statement.
* @return A new program.
*/
public Program createProgram(List<P> procs, S main) throws ModelException;
/**
* Create a program from the given argument.
*
* @param main
* The main statement of the program. Most likely this is a
* sequence statement.
* @return A new program without procedure definitions.
*/
public default Program createProgram(S main) throws ModelException {
return createProgram(new ArrayList<P>(), main);
}
/* PROCEDURE DEFINITIONS */
/**
* Create a procedure definition with the given name and body.
*
* @param procedureName
* The name of the procedure
* @param body
* The body of the procedure.
*/
public default P createProcedureDefinition(String procedureName, S body, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/* STATEMENTS */
/**
* Create a statement that assigns the value obtained by evaluating the
* given expression to a variable with the given name.
*/
public S createAssignmentStatement(String variableName, E value, SourceLocation sourceLocation)
throws ModelException;
/**
* Create a print statement that prints the value obtained by evaluating the
* given expression.
*/
public S createPrintStatement(E value, SourceLocation sourceLocation) throws ModelException;
/**
* Create a turn statement that makes the worm that is executing the program
* turn by the amount obtained by evaluating the given expression.
*/
public S createTurnStatement(E angle, SourceLocation location) throws ModelException;
/**
* Create a statement that makes the worm that is executing the program move
* one step.
*/
public S createMoveStatement(SourceLocation location) throws ModelException;
/**
* Returns a statement that makes the worm that is executing the program jump.
*/
public S createJumpStatement(SourceLocation location) throws ModelException;
/**
* Returns a statement that makes the worm that is executing the program eat.
*/
public S createEatStatement(SourceLocation location);
/**
* Returns a statement that makes the worm that is executing the program fire
* a weapon.
*/
public S createFireStatement(SourceLocation location) throws ModelException;
/**
* Create a sequence of statements involving the given list of statements.
*/
public S createSequenceStatement(List<S> statements, SourceLocation sourceLocation) throws ModelException;
/**
* Create an if-then-else statement involving the given condition and the
* given then-part and else-part.
* The else-part may be null.
*/
public S createIfStatement(E condition, S ifBody, S elseBody, SourceLocation sourceLocation) throws ModelException;
/**
* Create a while statement involving the given condition and given body.
*/
public S createWhileStatement(E condition, S body, SourceLocation sourceLocation) throws ModelException;
/**
* Create a break statement.
*/
public default S createBreakStatement(SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
// Individual students must not work out this method.
throw new MustNotImplementException();
}
/**
* Create an invoke statement that invokes the procedure with the given name.
*/
public default S createInvokeStatement(String procedureName, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
// Individual students must not work out this method.
throw new MustNotImplementException();
}
/* EXPRESSIONS */
/**
* Create an expression that evaluates to the current value of the given
* variable.
*/
public E createReadVariableExpression(String variableName, SourceLocation sourceLocation) throws ModelException;
/**
* Creates an expression that represents a literal double value.
*/
public E createDoubleLiteralExpression(double value, SourceLocation location) throws ModelException;
/**
* Creates an expression that represents a literal boolean value.
*/
public E createBooleanLiteralExpression(boolean value, SourceLocation location) throws ModelException;
/**
* Creates an expression that represents the null value.
*/
public E createNullExpression(SourceLocation location) throws ModelException;
/**
* Creates an expression that represents the self value, evaluating to the
* worm that executes the program.
*/
public E createSelfExpression(SourceLocation location) throws ModelException;
/**
* Returns an expression that evaluates to the addition of the values
* obtained by evaluating the given left and second expressions.
*/
public E createAdditionExpression(E left, E right, SourceLocation location) throws ModelException;
/**
* Returns an expression that evaluates to the subtraction of the values
* obtained by evaluating the first and second given expressions.
*/
public default E createSubtractionExpression(E left, E right, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the multiplication of the values
* obtained by evaluating the first and second given expressions.
*/
public default E createMultiplicationExpression(E left, E right, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the division of the values
* obtained by evaluating the first and second given expressions.
*/
public default E createDivisionExpression(E left, E right, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the square root of the value
* obtained by evaluating the given expression.
*/
public default E createSqrtExpression(E e, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the sine of the value
* obtained by evaluating the given expression.
*/
public default E createSinExpression(E e, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the cosine of the value
* obtained by evaluating the given expression.
*/
public default E createCosExpression(E e, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the conjunction of the values
* obtained by evaluating the given left and right expressions.
*/
public E createAndExpression(E left, E right, SourceLocation sourceLocation) throws ModelException;
/**
* Returns an expression that evaluates to the disjunction of the values
* obtained by evaluating the given left and right expressions.
*/
public default E createOrExpression(E left, E right, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to true when the given expression
* evaluates to false, and vice versa.
*/
public E createNotExpression(E expression, SourceLocation sourceLocation) throws ModelException;
/**
* Returns an expression that evaluates to true if the evaluation of the
* left expression yields a value that is equal to the value obtained by
* evaluating the right expression.
*/
public E createEqualityExpression(E left, E right, SourceLocation location) throws ModelException;
/**
* Returns an expression that evaluates to true if the evaluation of the
* left expression yields a value that is different from the value obtained by
* evaluating the right expression.
*/
public default E createInequalityExpression(E left, E right, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to true if the evaluation of the
* left expression yields a value that is less than the value obtained by
* evaluating the right expression.
*/
public E createLessThanExpression(E left, E right, SourceLocation location);
/**
* Returns an expression that evaluates to true if the evaluation of the
* left expression yields a value that is less than or equal to the value obtained by
* evaluating the right expression.
*/
public default E createLessThanOrEqualExpression(E left, E right, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to true if the evaluation of the
* left expression yields a value that is greater than the value obtained by
* evaluating the right expression.
*/
public default E createGreaterThanExpression(E left, E right, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to true if the evaluation of the
* left expression yields a value that is greater than or equal to the value obtained by
* evaluating the right expression.
*/
public default E createGreaterThanOrEqualExpression(E left, E right, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the position along the x-axis of
* the game object to which the given expression evaluates.
*/
public default E createGetXExpression(E e, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the position along the y-axis of
* the game object to which the given expression evaluates.
*/
public default E createGetYExpression(E e, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the radius of the game object to which
* the given expression evaluates.
*/
public default E createGetRadiusExpression(E e, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the direction of the game object to which
* the given expression evaluates.
*/
public default E createGetDirectionExpression(E entity, SourceLocation location)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the number of action points of the worm to which
* the given expression evaluates.
*/
public default E createGetActionPointsExpression(E entity, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the maximum number of action points of the worm to which
* the given expression evaluates.
*/
public default E createGetMaxActionPointsExpression(E entity, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the number of hit points of the game object to which
* the given expression evaluates.
*/
public default E createHitPointsExpression(E entity, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
public E createSearchObjectExpression(E angleDelta, SourceLocation sourceLocation) throws ModelException;
/**
* Returns an expression that evaluates to a boolean reflecting whether or not
* the executing worm belongs to the same team as the worm to which the given
* expression evaluates.
*/
public default E createSameTeamExpression(E entity, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
// Individual students must not work out this method.
throw new MustNotImplementException();
}
/**
* Returns an expression that evaluates to the distance between the executing worm
* and the game object to which the given expression evaluates.
*/
public E createDistanceExpression(E entity, SourceLocation sourceLocation) throws ModelException;
/**
* Returns a boolean indicating whether or not the object to which the given
* expression evaluates is a worm.
*/
public E createIsWormExpression(E entity, SourceLocation sourceLocation) throws ModelException;
/**
* Returns a boolean indicating whether or not the object to which the given
* expression evaluates is a portion of food.
*/
public default E createIsFoodExpression(E entity, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
/**
* Returns a boolean indicating whether or not the object to which the given
* expression evaluates is a projectile.
*/
public default E createIsProjectileExpression(E entity, SourceLocation sourceLocation)
throws ModelException, MustNotImplementException {
throw new MustNotImplementException();
}
}

View File

@@ -0,0 +1,20 @@
package worms.programs;
import java.util.List;
import worms.programs.SuccessOrFail.WrappedSuccessOrFail;
public class ParseOutcome<P> extends WrappedSuccessOrFail<P, List<String>> {
private ParseOutcome(SuccessOrFail<P, List<String>> outcome) {
super(outcome);
}
public static <P> ParseOutcome<P> success(P p) {
return new ParseOutcome<>(DefaultSuccessOrFail.success(p));
}
public static <P> ParseOutcome<P> failure(List<String> errors) {
return new ParseOutcome<>(DefaultSuccessOrFail.failure(errors));
}
}

View File

@@ -0,0 +1,248 @@
package worms.programs;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import worms.programs.IProgramFactory;
import worms.programs.internal.parser.ParserVisitor;
import worms.programs.internal.parser.generated.WormsProgramLexer;
import worms.programs.internal.parser.generated.WormsProgramParser;
import worms.util.MustNotImplementException;
import worms.internal.gui.GUIUtils;
import worms.model.Program;
/**
* Parser for Worms programs.
*
* To use this class, first create an implementation of {@link IProgramFactory}:
*
* <pre>
* <code>
* IProgramFactory&lt;MyExpression, MyStatement, MyProcedure, Program&gt; factory = new ProgramFactory();
* </code>
* </pre>
*
* The easiest way to use this class for parsing a Program given as a String is
* via the {@link #parseProgramFromString(String, IProgramFactory)} method:
*
* <pre>
* <code>
* Program program = ProgramParser.parseProgram(text, factory);
* </code>
* </pre>
*
* For more control, create an instance of this class:
*
* <pre>
* <code>
* ProgramParser&lt;MyExpression, MyStatement, Task&gt; parser = new ProgramParser<>(factory);
* </code>
* </pre>
*
* Finally, parse a string or file: <code><pre>
* ParseOurcome&lt;Program&gt; parseResult = parser.parse(textToParse);
* </pre></code>
*
* If parsing is successful, <code>parseResult.isSuccess()</code> returns true
* and <code>parseResult.getSuccessValue()</code> returns the created program.
*
* If parsing was not successful, <code>parseResult.ifSuccess()</code> returns
* false and <code>parseResult.getFailValue()</code> returns the list of errors
* during parsing.
*
*
* @param E
* The type of expressions
* @param S
* The type of statements
* @param P
* The type of procedures
* @param Prg
* The type of program that is created; should be your
* worms.model.Program class
*/
public class ProgramParser<E, S, P, Prg> {
private final IProgramFactory<E, S, P, Prg> factory;
private final List<String> errors = new ArrayList<>();
protected ProgramParser(IProgramFactory<E, S, P, Prg> factory) {
if (factory == null) {
throw new NullPointerException("Factory must be effective.");
}
this.factory = factory;
}
public IProgramFactory<E, S, P, Prg> getFactory() {
return factory;
}
/**
* Returns the program that results from parsing the given string, or
* Optional.empty() if parsing has failed.
*
* When parsing has failed, the error messages can be retrieved with the
* getErrors() method.
*
*/
public ParseOutcome<Prg> parseString(String string) {
return parse(CharStreams.fromString(string));
}
/**
* Returns the program that results from parsing the file with the given name,
* or Optional.empty() if parsing has failed.
*
* When parsing has failed, the error messages can be retrieved with the
* getErrors() method.
*/
public ParseOutcome<Prg> parseFile(String filename) throws IOException {
return parse(CharStreams.fromStream(GUIUtils.openResource(filename)));
}
/**
* Returns the program that results from parsing the file with the given URL, or
* Optional.empty() if parsing has failed.
*
* When parsing has failed, the error messages can be retrieved with the
* getErrors() method.
*/
public ParseOutcome<Prg> parseFile(URL url) throws IOException {
return parse(CharStreams.fromStream(GUIUtils.openResource(url)));
}
/**
* Returns the program that results from parsing the given CharStream, or
* Optional.empty() if parsing has failed.
*
* When parsing has failed, the error messages can be retrieved with the
* getErrors() method.
*
* @note For more convenient methods, see the
* {@link #parseProgramFromString(String, ITaskFactory, List)},
* {@link #parseProgramFromFile(String, ITaskFactory, List)},
* {@link #parseString(String, List)} and {@link #parseFile(String, List)}
* methods.
*/
protected ParseOutcome<Prg> parse(CharStream input) {
reset();
WormsProgramLexer lexer = new WormsProgramLexer(input);
WormsProgramParser parser = new WormsProgramParser(new CommonTokenStream(lexer));
parser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line,
int charPositionInLine, String msg, RecognitionException e) {
errors.add(msg + " (" + line + ", " + charPositionInLine + ")");
}
});
ParserVisitor<E, S, P, Prg> visitor = new ParserVisitor<>(factory);
try {
visitor.visitProgram(parser.program());
if (errors.isEmpty()) {
assert visitor.getMain() != null;
Prg program = factory.createProgram(visitor.getProcedures(), visitor.getMain());
if (program != null) {
return ParseOutcome.success(program);
}
errors.add("Factory did not return a Program object");
}
} catch (MustNotImplementException e) {
errors.add(e.toString());
} catch (Exception e) {
e.printStackTrace();
errors.add(e.toString());
}
return ParseOutcome.failure(errors);
}
protected void reset() {
this.errors.clear();
}
public List<String> getErrors() {
return Collections.unmodifiableList(errors);
}
/**
* Create a new parser from the given factory.
*
* @param factory
* @return
*/
public static <E, S, T, P> ProgramParser<E, S, T, P> create(IProgramFactory<E, S, T, P> factory) {
return new ProgramParser<>(factory);
}
/**
* Parse program text using the given factory.
*
* @param text
* The text to parse
* @param factory
* The factory to use
* @return The parsed program, if any, or null if an error occurred during
* parsing.
*/
public static Program parseProgramFromString(String text, IProgramFactory<?, ?, ?, ? extends Program> factory) {
ProgramParser<?, ?, ?, ? extends Program> parser = create(factory);
ParseOutcome<? extends Program> outcome = parser.parseString(text);
if (outcome.isFail()) {
System.out.println("Parsing failed: " + outcome.getFailValue());
return null;
}
return outcome.getSuccessValue();
}
/**
* Parse program from a file using the given factory.
*
* @param filename
* The filename from which to read the program text
* @param factory
* The factory to use
* @return The parsed program, if any, or null if an error occurred during
* parsing.
*/
public static Program parseProgramFromFile(String filename, IProgramFactory<?, ?, ?, ? extends Program> factory)
throws IOException {
ProgramParser<?, ?, ?, ? extends Program> parser = create(factory);
ParseOutcome<? extends Program> outcome = parser.parseFile(filename);
if (outcome.isFail()) {
System.out.println("Parsing failed: " + outcome.getFailValue());
return null;
}
return outcome.getSuccessValue();
}
/**
* Parse program from a file using the given factory.
*
* @param filename
* The filename from which to read the program text
* @param factory
* The factory to use
* @return The parsed program, if any, or null if an error occurred during
* parsing.
*/
public static Program parseProgramFromURL(URL url, IProgramFactory<?, ?, ?, Program> factory) throws IOException {
ProgramParser<?, ?, ?, Program> parser = create(factory);
ParseOutcome<Program> outcome = parser.parseFile(url);
if (outcome.isFail()) {
System.out.println("Parsing failed: " + outcome.getFailValue());
return null;
}
return outcome.getSuccessValue();
}
}

View File

@@ -0,0 +1,61 @@
package worms.programs;
import be.kuleuven.cs.som.annotate.Value;
/**
* A source location represents a position in a source file,
* denoted by the line and column (position in the line) of
* a certain character in the file.
*
* This class is a value class.
*/
@Value
public final class SourceLocation {
private final int line;
private final int column;
public SourceLocation(int line, int column) {
this.line = line;
this.column = column;
}
public int getLine() {
return line;
}
public int getColumn() {
return column;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + column;
result = prime * result + line;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SourceLocation other = (SourceLocation) obj;
if (column != other.column)
return false;
if (line != other.line)
return false;
return true;
}
@Override
public String toString() {
return String.format("@%d,%d", line, column);
}
}

View File

@@ -0,0 +1,100 @@
package worms.programs;
/**
* An interface that holds either a success value of type S or a failure value of type F.
*/
public interface SuccessOrFail<S, F> {
public boolean isSuccess();
public S getSuccessValue();
public F getFailValue();
public default boolean isFail() {
return !isSuccess();
}
public static class DefaultSuccessOrFail<S, F> implements SuccessOrFail<S, F> {
private final boolean success;
private final F failValue;
private final S successValue;
private DefaultSuccessOrFail(boolean success, S successValue, F failValue) {
if (success && failValue != null) {
throw new IllegalArgumentException();
}
if (!success && successValue != null) {
throw new IllegalArgumentException();
}
this.success = success;
this.successValue = successValue;
this.failValue = failValue;
}
@Override
public boolean isSuccess() {
return success;
}
@Override
public F getFailValue() {
return failValue;
}
@Override
public S getSuccessValue() {
return successValue;
}
public static <S, F> SuccessOrFail<S, F> success(S successValue) {
return new DefaultSuccessOrFail<>(true, successValue, null);
}
public static <S, F> SuccessOrFail<S, F> failure(F failValue) {
return new DefaultSuccessOrFail<>(false, null, failValue);
}
@Override
public String toString() {
if (isSuccess()) {
return "SUCCESS value: " + getSuccessValue();
} else {
return "FAIL value: " + getFailValue();
}
}
}
public static class WrappedSuccessOrFail<S, F> implements SuccessOrFail<S, F> {
private final SuccessOrFail<S, F> wrapped;
protected WrappedSuccessOrFail(SuccessOrFail<S, F> wrapped) {
if (wrapped == null) {
throw new NullPointerException();
}
this.wrapped = wrapped;
}
@Override
public boolean isSuccess() {
return wrapped.isSuccess();
}
@Override
public S getSuccessValue() {
return wrapped.getSuccessValue();
}
@Override
public F getFailValue() {
return wrapped.getFailValue();
}
@Override
public String toString() {
return wrapped.toString();
}
}
}

View File

@@ -0,0 +1,392 @@
package worms.programs.internal.parser;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import worms.programs.IProgramFactory;
import worms.programs.SourceLocation;
import worms.programs.internal.parser.generated.WormsProgramBaseVisitor;
import worms.programs.internal.parser.generated.WormsProgramLexer;
import worms.programs.internal.parser.generated.WormsProgramParser.AddSubExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.AndOrExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.AssignmentStatementContext;
import worms.programs.internal.parser.generated.WormsProgramParser.BreakStatementContext;
import worms.programs.internal.parser.generated.WormsProgramParser.ComparisonExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.ConstantExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.CosExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.DistanceExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.EatActionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.FalseLiteralExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.FireActionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetAPExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetDirectionExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetHPExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetMaxAPExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetRadiusExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetXExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.GetYExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.IfStatementContext;
import worms.programs.internal.parser.generated.WormsProgramParser.InvokeStatementContext;
import worms.programs.internal.parser.generated.WormsProgramParser.IsFoodExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.IsProjectileExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.IsWormExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.JumpActionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.MoveActionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.MulDivExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.NotExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.NullExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.ParenExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.PrintStatementContext;
import worms.programs.internal.parser.generated.WormsProgramParser.ProceduredefContext;
import worms.programs.internal.parser.generated.WormsProgramParser.ProgramContext;
import worms.programs.internal.parser.generated.WormsProgramParser.ReadVariableExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.SameTeamExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.SearchObjExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.SelfExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.SequenceStatementContext;
import worms.programs.internal.parser.generated.WormsProgramParser.SinExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.SqrtExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.TrueLiteralExpressionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.TurnActionContext;
import worms.programs.internal.parser.generated.WormsProgramParser.WhileStatementContext;
public class ParserVisitor<E, S, P, Prg> extends WormsProgramBaseVisitor<Void> {
@Override
public Void visitProgram(ProgramContext ctx) {
procedures = ctx.procdef.stream().map(procdef -> procDefVisitor.visit(procdef)).collect(Collectors.toList());
List<S> mainStmts = ctx.programBody.stream().map(stmt -> statementVisitor.visit(stmt))
.collect(Collectors.toList());
if (mainStmts.size() == 1) {
main = mainStmts.get(0);
} else {
main = factory.createSequenceStatement(mainStmts, toSourceLocation(ctx));
}
assert main != null;
return null;
}
private class ProcedureDefinitionVisitor extends WormsProgramBaseVisitor<P> {
@Override
public P visitProceduredef(ProceduredefContext ctx) {
return getFactory().createProcedureDefinition(ctx.procname.getText(), statementVisitor.visit(ctx.body),
toSourceLocation(ctx));
}
}
private class StatementVisitor extends WormsProgramBaseVisitor<S> {
@Override
public S visitAssignmentStatement(AssignmentStatementContext ctx) {
return getFactory().createAssignmentStatement(ctx.variableName.getText(),
expressionVisitor.visit(ctx.value), toSourceLocation(ctx));
}
@Override
public S visitWhileStatement(WhileStatementContext ctx) {
return getFactory().createWhileStatement(expressionVisitor.visit(ctx.condition),
statementVisitor.visit(ctx.body), toSourceLocation(ctx));
}
@Override
public S visitIfStatement(IfStatementContext ctx) {
S ifBody = statementVisitor.visit(ctx.ifbody);
S elseBody = null;
if (ctx.elsebody != null)
elseBody = statementVisitor.visit(ctx.elsebody);
return getFactory().createIfStatement(expressionVisitor.visit(ctx.condition), ifBody, elseBody,
toSourceLocation(ctx));
}
@Override
public S visitPrintStatement(PrintStatementContext ctx) {
return getFactory().createPrintStatement(expressionVisitor.visit(ctx.value), toSourceLocation(ctx));
}
@Override
public S visitSequenceStatement(SequenceStatementContext ctx) {
if (ctx.stmts.size() != 1) {
return getFactory().createSequenceStatement(
ctx.stmts.stream().map(this::visit).collect(Collectors.toList()), toSourceLocation(ctx));
} else {
return visit(ctx.stmts.get(0));
}
}
@Override
public S visitInvokeStatement(InvokeStatementContext ctx) {
return getFactory().createInvokeStatement(ctx.procName.getText(), toSourceLocation(ctx));
}
@Override
public S visitBreakStatement(BreakStatementContext ctx) {
return getFactory().createBreakStatement(toSourceLocation(ctx));
}
@Override
public S visitTurnAction(TurnActionContext ctx) {
return getFactory().createTurnStatement(expressionVisitor.visit(ctx.angle), toSourceLocation(ctx));
}
@Override
public S visitMoveAction(MoveActionContext ctx) {
return getFactory().createMoveStatement(toSourceLocation(ctx));
}
@Override
public S visitJumpAction(JumpActionContext ctx) {
return getFactory().createJumpStatement(toSourceLocation(ctx));
}
@Override
public S visitEatAction(EatActionContext ctx) {
return getFactory().createEatStatement(toSourceLocation(ctx));
}
@Override
public S visitFireAction(FireActionContext ctx) {
return getFactory().createFireStatement(toSourceLocation(ctx));
}
}
private class ExpressionVisitor extends WormsProgramBaseVisitor<E> {
@Override
public E visitReadVariableExpression(ReadVariableExpressionContext ctx) {
return getFactory().createReadVariableExpression(ctx.variable.getText(), toSourceLocation(ctx));
}
@Override
public E visitConstantExpression(ConstantExpressionContext ctx) {
return getFactory().createDoubleLiteralExpression(Double.parseDouble(ctx.value.getText()),
toSourceLocation(ctx));
}
@Override
public E visitTrueLiteralExpression(TrueLiteralExpressionContext ctx) {
return getFactory().createBooleanLiteralExpression(true, toSourceLocation(ctx));
}
@Override
public E visitFalseLiteralExpression(FalseLiteralExpressionContext ctx) {
return getFactory().createBooleanLiteralExpression(false, toSourceLocation(ctx));
}
@Override
public E visitNullExpression(NullExpressionContext ctx) {
return getFactory().createNullExpression(toSourceLocation(ctx));
}
@Override
public E visitSelfExpression(SelfExpressionContext ctx) {
return getFactory().createSelfExpression(toSourceLocation(ctx));
}
@Override
public E visitParenExpression(ParenExpressionContext ctx) {
return expressionVisitor.visit(ctx.subExpr);
}
@Override
public E visitAddSubExpression(AddSubExpressionContext ctx) {
switch (ctx.op.getType()) {
case WormsProgramLexer.ADD:
return getFactory().createAdditionExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.SUB:
return getFactory().createSubtractionExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
default:
throw new IllegalArgumentException("Unknown operator: " + ctx.op);
}
}
@Override
public E visitMulDivExpression(MulDivExpressionContext ctx) {
switch (ctx.op.getType()) {
case WormsProgramLexer.MUL:
return getFactory().createMultiplicationExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.DIV:
return getFactory().createDivisionExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
default:
throw new IllegalArgumentException("Unknown operator: " + ctx.op);
}
}
@Override
public E visitSqrtExpression(SqrtExpressionContext ctx) {
return getFactory().createSqrtExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitSinExpression(SinExpressionContext ctx) {
return getFactory().createSinExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitCosExpression(CosExpressionContext ctx) {
return getFactory().createCosExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitAndOrExpression(AndOrExpressionContext ctx) {
switch (ctx.op.getType()) {
case WormsProgramLexer.AND:
return getFactory().createAndExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.OR:
return getFactory().createOrExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
default:
throw new IllegalArgumentException("Unknown operator: " + ctx.op);
}
}
@Override
public E visitNotExpression(NotExpressionContext ctx) {
return getFactory().createNotExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitComparisonExpression(ComparisonExpressionContext ctx) {
switch (ctx.op.getType()) {
case WormsProgramLexer.LT:
return getFactory().createLessThanExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.LTE:
return getFactory().createLessThanOrEqualExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.GT:
return getFactory().createGreaterThanExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.GTE:
return getFactory().createGreaterThanOrEqualExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.EQ:
return getFactory().createEqualityExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
case WormsProgramLexer.NEQ:
return getFactory().createInequalityExpression(expressionVisitor.visit(ctx.left),
expressionVisitor.visit(ctx.right), toSourceLocation(ctx));
default:
throw new IllegalArgumentException("Unknown operand: " + ctx.op);
}
}
@Override
public E visitGetXExpression(GetXExpressionContext ctx) {
return getFactory().createGetXExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitGetYExpression(GetYExpressionContext ctx) {
return getFactory().createGetYExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitGetRadiusExpression(GetRadiusExpressionContext ctx) {
return getFactory().createGetRadiusExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitGetDirectionExpression(GetDirectionExpressionContext ctx) {
return getFactory().createGetDirectionExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitGetAPExpression(GetAPExpressionContext ctx) {
return getFactory().createGetActionPointsExpression(expressionVisitor.visit(ctx.expr),
toSourceLocation(ctx));
}
@Override
public E visitGetMaxAPExpression(GetMaxAPExpressionContext ctx) {
return getFactory().createGetMaxActionPointsExpression(expressionVisitor.visit(ctx.expr),
toSourceLocation(ctx));
}
@Override
public E visitGetHPExpression(GetHPExpressionContext ctx) {
return getFactory().createHitPointsExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitSameTeamExpression(SameTeamExpressionContext ctx) {
return getFactory().createSameTeamExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitSearchObjExpression(SearchObjExpressionContext ctx) {
return getFactory().createSearchObjectExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitDistanceExpression(DistanceExpressionContext ctx) {
return getFactory().createDistanceExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitIsWormExpression(IsWormExpressionContext ctx) {
return getFactory().createIsWormExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitIsFoodExpression(IsFoodExpressionContext ctx) {
return getFactory().createIsFoodExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
@Override
public E visitIsProjectileExpression(IsProjectileExpressionContext ctx) {
return getFactory().createIsProjectileExpression(expressionVisitor.visit(ctx.expr), toSourceLocation(ctx));
}
}
private final IProgramFactory<E, S, P, Prg> factory;
private final ProcedureDefinitionVisitor procDefVisitor = new ProcedureDefinitionVisitor();
private final StatementVisitor statementVisitor = new StatementVisitor();
private final ExpressionVisitor expressionVisitor = new ExpressionVisitor();
private S main;
private List<P> procedures;
public ParserVisitor(IProgramFactory<E, S, P, Prg> factory) {
if (factory == null) {
throw new NullPointerException();
}
this.factory = factory;
}
private SourceLocation toSourceLocation(ParserRuleContext ctx) {
int line = ctx.getStart().getLine();
int column = ctx.getStart().getCharPositionInLine();
return new SourceLocation(line, column);
}
public IProgramFactory<E, S, P, Prg> getFactory() {
return factory;
}
public int toInt(Token z) {
return Integer.parseInt(z.getText());
}
public S getMain() {
return main;
}
public List<P> getProcedures() {
return Collections.unmodifiableList(procedures);
}
}

View File

@@ -0,0 +1,200 @@
// ANTLR v4 Grammar for controling Worms.
// Check the tutorial at http://jnb.ociweb.com/jnb/jnbJun2008.html
// or http://www.antlr.org/ for details.
grammar WormsProgram;
@header {
package worms.programs.internal.parser.generated;
}
// ------------------------------------------------------------------------
// --- Eval and Related Definitions ---------------------------------------
// ------------------------------------------------------------------------
program: (procdef+=proceduredef)*
(programBody+=statement)*
;
proceduredef: DEF procname=IDENTIFIER COLON?
body=statement
;
statement: assignmentStatement
| whileStatement
| ifStatement
| printStatement
| sequenceStatement
| invokeStatement
| breakStatement
| actionStatement
;
assignmentStatement: variableName=IDENTIFIER ASSIGN value=expression ';'
;
whileStatement: WHILE condition=expression COLON?
body=statement
;
ifStatement: IF condition=expression COLON?
ifbody=statement
(ELSE COLON?
elsebody=statement)?
;
printStatement: PRINT value=expression ';'
;
sequenceStatement: LEFT_BRACE (stmts+=statement)* RIGHT_BRACE
;
invokeStatement: INVOKE procName=IDENTIFIER ';'
;
breakStatement: BREAK ';'
;
actionStatement: TURN angle=expression ';' #turnAction
| MOVE ';' #moveAction
| JUMP ';' #jumpAction
| EAT ';' #eatAction
| FIRE ';' #fireAction
;
// order here sets order of operations (important for left-recursive expressions!)
expression: variable=IDENTIFIER #readVariableExpression
| value=NUMBER #constantExpression
| TRUE #trueLiteralExpression
| FALSE #falseLiteralExpression
| NULL #nullExpression
| SELF #selfExpression
| LEFT_PAREN subExpr=expression RIGHT_PAREN #parenExpression
| left=expression op=(MUL | DIV) right=expression #mulDivExpression
| left=expression op=(ADD | SUB) right=expression #addSubExpression
| left=expression op=(LT | LTE | GT | GTE | EQ | NEQ) right=expression #comparisonExpression
| left=expression op=(AND | OR) right=expression #andOrExpression
| SQRT LEFT_PAREN expr=expression RIGHT_PAREN #sqrtExpression
| SIN LEFT_PAREN expr=expression RIGHT_PAREN #sinExpression
| COS LEFT_PAREN expr=expression RIGHT_PAREN #cosExpression
| NOT expr=expression #notExpression
| GETX expr=expression #getXExpression
| GETY expr=expression #getYExpression
| GETRADIUS expr=expression #getRadiusExpression
| GETDIR expr=expression #getDirectionExpression
| GETAP expr=expression #getAPExpression
| GETMAXAP expr=expression #getMaxAPExpression
| GETHP expr=expression #getHPExpression
| SAMETEAM expr=expression #sameTeamExpression
| SEARCHOBJ expr=expression #searchObjExpression
| DISTANCE expr=expression #distanceExpression
| ISWORM expr=expression #isWormExpression
| ISFOOD expr=expression #isFoodExpression
| ISPROJECTILE expr=expression #isProjectileExpression
;
// ------------------------------------------------------------------------
// --- Specifiers -----------------------------------------------
// ------------------------------------------------------------------------
NULL: 'null';
SELF: 'self';
TRUE: 'true';
FALSE: 'false';
// ------------------------------------------------------------------------
// --- Unary Operations ---------------------------------------------------
// ------------------------------------------------------------------------
SQRT: 'sqrt';
SIN: 'sin';
COS: 'cos';
NOT: '!';
GETX: 'getx';
GETY: 'gety';
GETRADIUS: 'getradius';
GETDIR: 'getdir';
GETAP: 'getap';
GETMAXAP: 'getmaxap';
GETHP: 'gethp';
SAMETEAM: 'sameteam';
SEARCHOBJ: 'searchobj';
DISTANCE: 'distance';
ISWORM: 'isworm';
ISFOOD: 'isfood';
ISPROJECTILE: 'isprojectile';
// ------------------------------------------------------------------------
// --- Actions -----------------------------------------------
// ------------------------------------------------------------------------
TURN: 'turn';
MOVE: 'move';
JUMP: 'jump';
EAT: 'eat';
FIRE: 'fire';
// ------------------------------------------------------------------------
// --- Control Flow -------------------------------------------------------
// ------------------------------------------------------------------------
DEF: 'def';
IF: 'if';
INVOKE: 'invoke';
THEN: 'then';
ELSE: 'else';
WHILE: 'while';
BREAK: 'break';
PRINT: 'print';
// ------------------------------------------------------------------------
// --- Assignment and Arithmetics -----------------------------------------
// ------------------------------------------------------------------------
ASSIGN: ':=';
ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
AND: '&&';
OR: '||';
LT: '<';
LTE: '<=';
GT: '>';
GTE: '>=';
EQ: '==';
NEQ: '!=';
// ------------------------------------------------------------------------
// --- Literals and Variables ---------------------------------------------
// ------------------------------------------------------------------------
NUMBER: INTEGER | FLOAT;
FLOAT: INTEGER '.' ('0'..'9')+;
INTEGER: ('-'|'+')? ('0'..'9')+;
IDENTIFIER: LETTER (LETTER | DIGIT | '_')*;
fragment LETTER: LOWER | UPPER;
fragment LOWER: 'a'..'z';
fragment UPPER: 'A'..'Z';
fragment DIGIT: '0'..'9';
LEFT_PAREN: '(';
RIGHT_PAREN: ')';
LEFT_BRACE: '{';
RIGHT_BRACE: '}';
COLON: ':';
// ------------------------------------------------------------------------
// --- Syntactical Ballast ------------------------------------------------
// ------------------------------------------------------------------------
// Skip runs of newline, space and tab characters.
WHITESPACE: [ \t\r\n]+ -> skip;
// Single-line comments begin with //, are followed by any characters
// other than those in a newline, and are terminated by newline characters.
SINGLE_COMMENT: '//' ~('\r' | '\n')* NEWLINE -> skip;
fragment NEWLINE: ('\r'? '\n')+;

View File

@@ -0,0 +1,42 @@
package worms.programs.internal.parser.example;
import java.io.IOException;
import worms.programs.IProgramFactory;
import worms.programs.ParseOutcome;
import worms.programs.ProgramParser;
public class ExamplePrinter {
public static void main(String[] args) throws IOException {
IProgramFactory<PrintingObject, PrintingObject, PrintingObject, PrintingProgram> factory = PrintingObjectFactory.create();
ProgramParser<?, ?, ?, PrintingProgram> parser = ProgramParser.create(factory);
/*
ParseOutcome<PrintingProgram> outcome = parser.parseString(
"def controlled_move:"
+ " if getap self > 100.0:"
+ " { jump; print getx self; print gety self; }"
+ " else move;"
+ ""
+ "max_distance := 10.0;"
+ "while true: {"
+ " w := searchobj 0.0;"
+ " if isworm w: {"
+ " if sameteam w:"
+ " invoke controlled_move;"
+ " else if distance w < max_distance:"
+ " fire;"
+ " else"
+ " { turn d; max_distance := max_distance + 0.1; }"
+ " }"
+ "}");
*/
//ParseOutcome<PrintingProgram> outcome = parser.parseFile("programs/program_example.txt");
//ParseOutcome<PrintingProgram> outcome = parser.parseFile("programs/syntax_test.txt");
ParseOutcome<PrintingProgram> outcome = parser.parseFile("programs/program.txt");
System.out.println(outcome);
}
}

View File

@@ -0,0 +1,80 @@
package worms.programs.internal.parser.example;
import java.util.List;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import worms.programs.SourceLocation;
public class PrintingObject {
private boolean indented = false;
private final StringBuilder repr = new StringBuilder();
public PrintingObject(SourceLocation loc, String method, Object... args) {
if (loc != null) {
method = loc + " " + method;
}
if (args.length > 1) {
indented(method + "(");
indented = true;
for (int i = 0; i < args.length; i++) {
indented(repr(args[i]), args.length > 1 && i < args.length - 1);
}
indented = false;
indented(")");
} else {
String msg = method + "( ";
if (args.length > 0) {
msg += repr(args[0]).toString().trim();
}
msg += " )";
indented(msg);
}
}
private String repr(Object object) {
if (object instanceof String) {
object = "\"" + object + "\"";
} else if (object instanceof List<?>) {
object = String.format("Arrays.toList(%s)", ((List<?>) object)
.stream().map(this::repr)
.collect(Collectors.joining(", ### Arrays.toList\n")));
}
if (object != null) {
return object.toString();
} else {
return "null";
}
}
@Override
public String toString() {
return repr.toString();
}
private void indented(Object object) {
indented(object, false);
}
private void indented(Object object, boolean appendComma) {
if (object != null) {
String str = object.toString();
StringTokenizer tok = new StringTokenizer(str, "\n");
while (tok.hasMoreTokens()) {
if (indented)
repr.append("| ");
repr.append(tok.nextToken());
if (!tok.hasMoreTokens() && appendComma) {
repr.append(",");
}
repr.append("\n");
}
} else {
if (indented)
repr.append(" null");
}
}
}

View File

@@ -0,0 +1,49 @@
package worms.programs.internal.parser.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import worms.programs.IProgramFactory;
import worms.programs.SourceLocation;
public class PrintingObjectFactory {
/**
* Creates an implementation of IProgramFactory where the implementation of
* each interface method (except createProgram) just creates a
* PrintingObject with all arguments.
*/
@SuppressWarnings("unchecked")
public static IProgramFactory<PrintingObject, PrintingObject, PrintingObject, PrintingProgram> create() {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("createProgram")) {
List<PrintingObject> functions = (List<PrintingObject>)args[0];
PrintingObject main = (PrintingObject) args[1];
return new PrintingProgram(functions, main);
}
if (args != null) {
SourceLocation sourceLocation = (SourceLocation) args[args.length - 1];
if (args.length >= 1) {
return new PrintingObject(sourceLocation, method.getName(),
Arrays.copyOfRange(args, 0, args.length - 1));
} else {
return new PrintingObject(sourceLocation, method.getName());
}
} else {
return new PrintingObject(null, method.getName());
}
}
};
return (IProgramFactory<PrintingObject, PrintingObject, PrintingObject, PrintingProgram>) Proxy.newProxyInstance(
IProgramFactory.class.getClassLoader(), new Class[] { IProgramFactory.class }, handler);
}
}

View File

@@ -0,0 +1,22 @@
package worms.programs.internal.parser.example;
import java.util.List;
public class PrintingProgram {
private List<PrintingObject> procedures;
private PrintingObject main;
public PrintingProgram(List<PrintingObject> procedures, PrintingObject main) {
if (main == null) {
throw new NullPointerException("main null");
}
this.main = main;
this.procedures = procedures;
}
@Override
public String toString() {
return "Procedures: " + procedures.toString() + "\nMain:" + main.toString();
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,112 @@
T__0=1
NULL=2
SELF=3
TRUE=4
FALSE=5
SQRT=6
SIN=7
COS=8
NOT=9
GETX=10
GETY=11
GETRADIUS=12
GETDIR=13
GETAP=14
GETMAXAP=15
GETHP=16
SAMETEAM=17
SEARCHOBJ=18
DISTANCE=19
ISWORM=20
ISFOOD=21
ISPROJECTILE=22
TURN=23
MOVE=24
JUMP=25
EAT=26
FIRE=27
DEF=28
IF=29
INVOKE=30
THEN=31
ELSE=32
WHILE=33
BREAK=34
PRINT=35
ASSIGN=36
ADD=37
SUB=38
MUL=39
DIV=40
AND=41
OR=42
LT=43
LTE=44
GT=45
GTE=46
EQ=47
NEQ=48
NUMBER=49
FLOAT=50
INTEGER=51
IDENTIFIER=52
LEFT_PAREN=53
RIGHT_PAREN=54
LEFT_BRACE=55
RIGHT_BRACE=56
COLON=57
WHITESPACE=58
SINGLE_COMMENT=59
';'=1
'null'=2
'self'=3
'true'=4
'false'=5
'sqrt'=6
'sin'=7
'cos'=8
'!'=9
'getx'=10
'gety'=11
'getradius'=12
'getdir'=13
'getap'=14
'getmaxap'=15
'gethp'=16
'sameteam'=17
'searchobj'=18
'distance'=19
'isworm'=20
'isfood'=21
'isprojectile'=22
'turn'=23
'move'=24
'jump'=25
'eat'=26
'fire'=27
'def'=28
'if'=29
'invoke'=30
'then'=31
'else'=32
'while'=33
'break'=34
'print'=35
':='=36
'+'=37
'-'=38
'*'=39
'/'=40
'&&'=41
'||'=42
'<'=43
'<='=44
'>'=45
'>='=46
'=='=47
'!='=48
'('=53
')'=54
'{'=55
'}'=56
':'=57

View File

@@ -0,0 +1,317 @@
// Generated from WormsProgram.g4 by ANTLR 4.7.1
package worms.programs.internal.parser.generated;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
/**
* This class provides an empty implementation of {@link WormsProgramVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public class WormsProgramBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements WormsProgramVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitProgram(WormsProgramParser.ProgramContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitProceduredef(WormsProgramParser.ProceduredefContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStatement(WormsProgramParser.StatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAssignmentStatement(WormsProgramParser.AssignmentStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitWhileStatement(WormsProgramParser.WhileStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIfStatement(WormsProgramParser.IfStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPrintStatement(WormsProgramParser.PrintStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSequenceStatement(WormsProgramParser.SequenceStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitInvokeStatement(WormsProgramParser.InvokeStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitBreakStatement(WormsProgramParser.BreakStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTurnAction(WormsProgramParser.TurnActionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMoveAction(WormsProgramParser.MoveActionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitJumpAction(WormsProgramParser.JumpActionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitEatAction(WormsProgramParser.EatActionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFireAction(WormsProgramParser.FireActionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDistanceExpression(WormsProgramParser.DistanceExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitCosExpression(WormsProgramParser.CosExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetYExpression(WormsProgramParser.GetYExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAndOrExpression(WormsProgramParser.AndOrExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIsWormExpression(WormsProgramParser.IsWormExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNotExpression(WormsProgramParser.NotExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitComparisonExpression(WormsProgramParser.ComparisonExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParenExpression(WormsProgramParser.ParenExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetRadiusExpression(WormsProgramParser.GetRadiusExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTrueLiteralExpression(WormsProgramParser.TrueLiteralExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNullExpression(WormsProgramParser.NullExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSqrtExpression(WormsProgramParser.SqrtExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSinExpression(WormsProgramParser.SinExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSameTeamExpression(WormsProgramParser.SameTeamExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIsProjectileExpression(WormsProgramParser.IsProjectileExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIsFoodExpression(WormsProgramParser.IsFoodExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitConstantExpression(WormsProgramParser.ConstantExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSearchObjExpression(WormsProgramParser.SearchObjExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetXExpression(WormsProgramParser.GetXExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitReadVariableExpression(WormsProgramParser.ReadVariableExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMulDivExpression(WormsProgramParser.MulDivExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetDirectionExpression(WormsProgramParser.GetDirectionExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSelfExpression(WormsProgramParser.SelfExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetHPExpression(WormsProgramParser.GetHPExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAddSubExpression(WormsProgramParser.AddSubExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetMaxAPExpression(WormsProgramParser.GetMaxAPExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGetAPExpression(WormsProgramParser.GetAPExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFalseLiteralExpression(WormsProgramParser.FalseLiteralExpressionContext ctx) { return visitChildren(ctx); }
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,280 @@
// Generated from WormsProgram.g4 by ANTLR 4.7.1
package worms.programs.internal.parser.generated;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class WormsProgramLexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.7.1", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
T__0=1, NULL=2, SELF=3, TRUE=4, FALSE=5, SQRT=6, SIN=7, COS=8, NOT=9,
GETX=10, GETY=11, GETRADIUS=12, GETDIR=13, GETAP=14, GETMAXAP=15, GETHP=16,
SAMETEAM=17, SEARCHOBJ=18, DISTANCE=19, ISWORM=20, ISFOOD=21, ISPROJECTILE=22,
TURN=23, MOVE=24, JUMP=25, EAT=26, FIRE=27, DEF=28, IF=29, INVOKE=30,
THEN=31, ELSE=32, WHILE=33, BREAK=34, PRINT=35, ASSIGN=36, ADD=37, SUB=38,
MUL=39, DIV=40, AND=41, OR=42, LT=43, LTE=44, GT=45, GTE=46, EQ=47, NEQ=48,
NUMBER=49, FLOAT=50, INTEGER=51, IDENTIFIER=52, LEFT_PAREN=53, RIGHT_PAREN=54,
LEFT_BRACE=55, RIGHT_BRACE=56, COLON=57, WHITESPACE=58, SINGLE_COMMENT=59;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
public static String[] modeNames = {
"DEFAULT_MODE"
};
public static final String[] ruleNames = {
"T__0", "NULL", "SELF", "TRUE", "FALSE", "SQRT", "SIN", "COS", "NOT",
"GETX", "GETY", "GETRADIUS", "GETDIR", "GETAP", "GETMAXAP", "GETHP", "SAMETEAM",
"SEARCHOBJ", "DISTANCE", "ISWORM", "ISFOOD", "ISPROJECTILE", "TURN", "MOVE",
"JUMP", "EAT", "FIRE", "DEF", "IF", "INVOKE", "THEN", "ELSE", "WHILE",
"BREAK", "PRINT", "ASSIGN", "ADD", "SUB", "MUL", "DIV", "AND", "OR", "LT",
"LTE", "GT", "GTE", "EQ", "NEQ", "NUMBER", "FLOAT", "INTEGER", "IDENTIFIER",
"LETTER", "LOWER", "UPPER", "DIGIT", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACE",
"RIGHT_BRACE", "COLON", "WHITESPACE", "SINGLE_COMMENT", "NEWLINE"
};
private static final String[] _LITERAL_NAMES = {
null, "';'", "'null'", "'self'", "'true'", "'false'", "'sqrt'", "'sin'",
"'cos'", "'!'", "'getx'", "'gety'", "'getradius'", "'getdir'", "'getap'",
"'getmaxap'", "'gethp'", "'sameteam'", "'searchobj'", "'distance'", "'isworm'",
"'isfood'", "'isprojectile'", "'turn'", "'move'", "'jump'", "'eat'", "'fire'",
"'def'", "'if'", "'invoke'", "'then'", "'else'", "'while'", "'break'",
"'print'", "':='", "'+'", "'-'", "'*'", "'/'", "'&&'", "'||'", "'<'",
"'<='", "'>'", "'>='", "'=='", "'!='", null, null, null, null, "'('",
"')'", "'{'", "'}'", "':'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, null, "NULL", "SELF", "TRUE", "FALSE", "SQRT", "SIN", "COS", "NOT",
"GETX", "GETY", "GETRADIUS", "GETDIR", "GETAP", "GETMAXAP", "GETHP", "SAMETEAM",
"SEARCHOBJ", "DISTANCE", "ISWORM", "ISFOOD", "ISPROJECTILE", "TURN", "MOVE",
"JUMP", "EAT", "FIRE", "DEF", "IF", "INVOKE", "THEN", "ELSE", "WHILE",
"BREAK", "PRINT", "ASSIGN", "ADD", "SUB", "MUL", "DIV", "AND", "OR", "LT",
"LTE", "GT", "GTE", "EQ", "NEQ", "NUMBER", "FLOAT", "INTEGER", "IDENTIFIER",
"LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACE", "RIGHT_BRACE", "COLON", "WHITESPACE",
"SINGLE_COMMENT"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public WormsProgramLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "WormsProgram.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getChannelNames() { return channelNames; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2=\u01bf\b\1\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
"\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+
"\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+
",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64\t"+
"\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t="+
"\4>\t>\4?\t?\4@\t@\4A\tA\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4\3\4\3"+
"\4\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\b"+
"\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f"+
"\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3"+
"\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3"+
"\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3"+
"\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3"+
"\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3"+
"\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3"+
"\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3"+
"\30\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3"+
"\33\3\34\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3"+
"\37\3\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \3!\3!\3!\3!\3!\3\"\3\"\3\""+
"\3\"\3\"\3\"\3#\3#\3#\3#\3#\3#\3$\3$\3$\3$\3$\3$\3%\3%\3%\3&\3&\3\'\3"+
"\'\3(\3(\3)\3)\3*\3*\3*\3+\3+\3+\3,\3,\3-\3-\3-\3.\3.\3/\3/\3/\3\60\3"+
"\60\3\60\3\61\3\61\3\61\3\62\3\62\5\62\u0176\n\62\3\63\3\63\3\63\6\63"+
"\u017b\n\63\r\63\16\63\u017c\3\64\5\64\u0180\n\64\3\64\6\64\u0183\n\64"+
"\r\64\16\64\u0184\3\65\3\65\3\65\3\65\7\65\u018b\n\65\f\65\16\65\u018e"+
"\13\65\3\66\3\66\5\66\u0192\n\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<"+
"\3<\3=\3=\3>\3>\3?\6?\u01a5\n?\r?\16?\u01a6\3?\3?\3@\3@\3@\3@\7@\u01af"+
"\n@\f@\16@\u01b2\13@\3@\3@\3@\3@\3A\5A\u01b9\nA\3A\6A\u01bc\nA\rA\16A"+
"\u01bd\2\2B\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33"+
"\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67"+
"\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65"+
"i\66k\2m\2o\2q\2s\67u8w9y:{;}<\177=\u0081\2\3\2\5\4\2--//\5\2\13\f\17"+
"\17\"\"\4\2\f\f\17\17\2\u01c5\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t"+
"\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2"+
"\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2"+
"\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2"+
"+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2"+
"\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2"+
"C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3"+
"\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2"+
"\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2"+
"i\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3"+
"\2\2\2\2\177\3\2\2\2\3\u0083\3\2\2\2\5\u0085\3\2\2\2\7\u008a\3\2\2\2\t"+
"\u008f\3\2\2\2\13\u0094\3\2\2\2\r\u009a\3\2\2\2\17\u009f\3\2\2\2\21\u00a3"+
"\3\2\2\2\23\u00a7\3\2\2\2\25\u00a9\3\2\2\2\27\u00ae\3\2\2\2\31\u00b3\3"+
"\2\2\2\33\u00bd\3\2\2\2\35\u00c4\3\2\2\2\37\u00ca\3\2\2\2!\u00d3\3\2\2"+
"\2#\u00d9\3\2\2\2%\u00e2\3\2\2\2\'\u00ec\3\2\2\2)\u00f5\3\2\2\2+\u00fc"+
"\3\2\2\2-\u0103\3\2\2\2/\u0110\3\2\2\2\61\u0115\3\2\2\2\63\u011a\3\2\2"+
"\2\65\u011f\3\2\2\2\67\u0123\3\2\2\29\u0128\3\2\2\2;\u012c\3\2\2\2=\u012f"+
"\3\2\2\2?\u0136\3\2\2\2A\u013b\3\2\2\2C\u0140\3\2\2\2E\u0146\3\2\2\2G"+
"\u014c\3\2\2\2I\u0152\3\2\2\2K\u0155\3\2\2\2M\u0157\3\2\2\2O\u0159\3\2"+
"\2\2Q\u015b\3\2\2\2S\u015d\3\2\2\2U\u0160\3\2\2\2W\u0163\3\2\2\2Y\u0165"+
"\3\2\2\2[\u0168\3\2\2\2]\u016a\3\2\2\2_\u016d\3\2\2\2a\u0170\3\2\2\2c"+
"\u0175\3\2\2\2e\u0177\3\2\2\2g\u017f\3\2\2\2i\u0186\3\2\2\2k\u0191\3\2"+
"\2\2m\u0193\3\2\2\2o\u0195\3\2\2\2q\u0197\3\2\2\2s\u0199\3\2\2\2u\u019b"+
"\3\2\2\2w\u019d\3\2\2\2y\u019f\3\2\2\2{\u01a1\3\2\2\2}\u01a4\3\2\2\2\177"+
"\u01aa\3\2\2\2\u0081\u01bb\3\2\2\2\u0083\u0084\7=\2\2\u0084\4\3\2\2\2"+
"\u0085\u0086\7p\2\2\u0086\u0087\7w\2\2\u0087\u0088\7n\2\2\u0088\u0089"+
"\7n\2\2\u0089\6\3\2\2\2\u008a\u008b\7u\2\2\u008b\u008c\7g\2\2\u008c\u008d"+
"\7n\2\2\u008d\u008e\7h\2\2\u008e\b\3\2\2\2\u008f\u0090\7v\2\2\u0090\u0091"+
"\7t\2\2\u0091\u0092\7w\2\2\u0092\u0093\7g\2\2\u0093\n\3\2\2\2\u0094\u0095"+
"\7h\2\2\u0095\u0096\7c\2\2\u0096\u0097\7n\2\2\u0097\u0098\7u\2\2\u0098"+
"\u0099\7g\2\2\u0099\f\3\2\2\2\u009a\u009b\7u\2\2\u009b\u009c\7s\2\2\u009c"+
"\u009d\7t\2\2\u009d\u009e\7v\2\2\u009e\16\3\2\2\2\u009f\u00a0\7u\2\2\u00a0"+
"\u00a1\7k\2\2\u00a1\u00a2\7p\2\2\u00a2\20\3\2\2\2\u00a3\u00a4\7e\2\2\u00a4"+
"\u00a5\7q\2\2\u00a5\u00a6\7u\2\2\u00a6\22\3\2\2\2\u00a7\u00a8\7#\2\2\u00a8"+
"\24\3\2\2\2\u00a9\u00aa\7i\2\2\u00aa\u00ab\7g\2\2\u00ab\u00ac\7v\2\2\u00ac"+
"\u00ad\7z\2\2\u00ad\26\3\2\2\2\u00ae\u00af\7i\2\2\u00af\u00b0\7g\2\2\u00b0"+
"\u00b1\7v\2\2\u00b1\u00b2\7{\2\2\u00b2\30\3\2\2\2\u00b3\u00b4\7i\2\2\u00b4"+
"\u00b5\7g\2\2\u00b5\u00b6\7v\2\2\u00b6\u00b7\7t\2\2\u00b7\u00b8\7c\2\2"+
"\u00b8\u00b9\7f\2\2\u00b9\u00ba\7k\2\2\u00ba\u00bb\7w\2\2\u00bb\u00bc"+
"\7u\2\2\u00bc\32\3\2\2\2\u00bd\u00be\7i\2\2\u00be\u00bf\7g\2\2\u00bf\u00c0"+
"\7v\2\2\u00c0\u00c1\7f\2\2\u00c1\u00c2\7k\2\2\u00c2\u00c3\7t\2\2\u00c3"+
"\34\3\2\2\2\u00c4\u00c5\7i\2\2\u00c5\u00c6\7g\2\2\u00c6\u00c7\7v\2\2\u00c7"+
"\u00c8\7c\2\2\u00c8\u00c9\7r\2\2\u00c9\36\3\2\2\2\u00ca\u00cb\7i\2\2\u00cb"+
"\u00cc\7g\2\2\u00cc\u00cd\7v\2\2\u00cd\u00ce\7o\2\2\u00ce\u00cf\7c\2\2"+
"\u00cf\u00d0\7z\2\2\u00d0\u00d1\7c\2\2\u00d1\u00d2\7r\2\2\u00d2 \3\2\2"+
"\2\u00d3\u00d4\7i\2\2\u00d4\u00d5\7g\2\2\u00d5\u00d6\7v\2\2\u00d6\u00d7"+
"\7j\2\2\u00d7\u00d8\7r\2\2\u00d8\"\3\2\2\2\u00d9\u00da\7u\2\2\u00da\u00db"+
"\7c\2\2\u00db\u00dc\7o\2\2\u00dc\u00dd\7g\2\2\u00dd\u00de\7v\2\2\u00de"+
"\u00df\7g\2\2\u00df\u00e0\7c\2\2\u00e0\u00e1\7o\2\2\u00e1$\3\2\2\2\u00e2"+
"\u00e3\7u\2\2\u00e3\u00e4\7g\2\2\u00e4\u00e5\7c\2\2\u00e5\u00e6\7t\2\2"+
"\u00e6\u00e7\7e\2\2\u00e7\u00e8\7j\2\2\u00e8\u00e9\7q\2\2\u00e9\u00ea"+
"\7d\2\2\u00ea\u00eb\7l\2\2\u00eb&\3\2\2\2\u00ec\u00ed\7f\2\2\u00ed\u00ee"+
"\7k\2\2\u00ee\u00ef\7u\2\2\u00ef\u00f0\7v\2\2\u00f0\u00f1\7c\2\2\u00f1"+
"\u00f2\7p\2\2\u00f2\u00f3\7e\2\2\u00f3\u00f4\7g\2\2\u00f4(\3\2\2\2\u00f5"+
"\u00f6\7k\2\2\u00f6\u00f7\7u\2\2\u00f7\u00f8\7y\2\2\u00f8\u00f9\7q\2\2"+
"\u00f9\u00fa\7t\2\2\u00fa\u00fb\7o\2\2\u00fb*\3\2\2\2\u00fc\u00fd\7k\2"+
"\2\u00fd\u00fe\7u\2\2\u00fe\u00ff\7h\2\2\u00ff\u0100\7q\2\2\u0100\u0101"+
"\7q\2\2\u0101\u0102\7f\2\2\u0102,\3\2\2\2\u0103\u0104\7k\2\2\u0104\u0105"+
"\7u\2\2\u0105\u0106\7r\2\2\u0106\u0107\7t\2\2\u0107\u0108\7q\2\2\u0108"+
"\u0109\7l\2\2\u0109\u010a\7g\2\2\u010a\u010b\7e\2\2\u010b\u010c\7v\2\2"+
"\u010c\u010d\7k\2\2\u010d\u010e\7n\2\2\u010e\u010f\7g\2\2\u010f.\3\2\2"+
"\2\u0110\u0111\7v\2\2\u0111\u0112\7w\2\2\u0112\u0113\7t\2\2\u0113\u0114"+
"\7p\2\2\u0114\60\3\2\2\2\u0115\u0116\7o\2\2\u0116\u0117\7q\2\2\u0117\u0118"+
"\7x\2\2\u0118\u0119\7g\2\2\u0119\62\3\2\2\2\u011a\u011b\7l\2\2\u011b\u011c"+
"\7w\2\2\u011c\u011d\7o\2\2\u011d\u011e\7r\2\2\u011e\64\3\2\2\2\u011f\u0120"+
"\7g\2\2\u0120\u0121\7c\2\2\u0121\u0122\7v\2\2\u0122\66\3\2\2\2\u0123\u0124"+
"\7h\2\2\u0124\u0125\7k\2\2\u0125\u0126\7t\2\2\u0126\u0127\7g\2\2\u0127"+
"8\3\2\2\2\u0128\u0129\7f\2\2\u0129\u012a\7g\2\2\u012a\u012b\7h\2\2\u012b"+
":\3\2\2\2\u012c\u012d\7k\2\2\u012d\u012e\7h\2\2\u012e<\3\2\2\2\u012f\u0130"+
"\7k\2\2\u0130\u0131\7p\2\2\u0131\u0132\7x\2\2\u0132\u0133\7q\2\2\u0133"+
"\u0134\7m\2\2\u0134\u0135\7g\2\2\u0135>\3\2\2\2\u0136\u0137\7v\2\2\u0137"+
"\u0138\7j\2\2\u0138\u0139\7g\2\2\u0139\u013a\7p\2\2\u013a@\3\2\2\2\u013b"+
"\u013c\7g\2\2\u013c\u013d\7n\2\2\u013d\u013e\7u\2\2\u013e\u013f\7g\2\2"+
"\u013fB\3\2\2\2\u0140\u0141\7y\2\2\u0141\u0142\7j\2\2\u0142\u0143\7k\2"+
"\2\u0143\u0144\7n\2\2\u0144\u0145\7g\2\2\u0145D\3\2\2\2\u0146\u0147\7"+
"d\2\2\u0147\u0148\7t\2\2\u0148\u0149\7g\2\2\u0149\u014a\7c\2\2\u014a\u014b"+
"\7m\2\2\u014bF\3\2\2\2\u014c\u014d\7r\2\2\u014d\u014e\7t\2\2\u014e\u014f"+
"\7k\2\2\u014f\u0150\7p\2\2\u0150\u0151\7v\2\2\u0151H\3\2\2\2\u0152\u0153"+
"\7<\2\2\u0153\u0154\7?\2\2\u0154J\3\2\2\2\u0155\u0156\7-\2\2\u0156L\3"+
"\2\2\2\u0157\u0158\7/\2\2\u0158N\3\2\2\2\u0159\u015a\7,\2\2\u015aP\3\2"+
"\2\2\u015b\u015c\7\61\2\2\u015cR\3\2\2\2\u015d\u015e\7(\2\2\u015e\u015f"+
"\7(\2\2\u015fT\3\2\2\2\u0160\u0161\7~\2\2\u0161\u0162\7~\2\2\u0162V\3"+
"\2\2\2\u0163\u0164\7>\2\2\u0164X\3\2\2\2\u0165\u0166\7>\2\2\u0166\u0167"+
"\7?\2\2\u0167Z\3\2\2\2\u0168\u0169\7@\2\2\u0169\\\3\2\2\2\u016a\u016b"+
"\7@\2\2\u016b\u016c\7?\2\2\u016c^\3\2\2\2\u016d\u016e\7?\2\2\u016e\u016f"+
"\7?\2\2\u016f`\3\2\2\2\u0170\u0171\7#\2\2\u0171\u0172\7?\2\2\u0172b\3"+
"\2\2\2\u0173\u0176\5g\64\2\u0174\u0176\5e\63\2\u0175\u0173\3\2\2\2\u0175"+
"\u0174\3\2\2\2\u0176d\3\2\2\2\u0177\u0178\5g\64\2\u0178\u017a\7\60\2\2"+
"\u0179\u017b\4\62;\2\u017a\u0179\3\2\2\2\u017b\u017c\3\2\2\2\u017c\u017a"+
"\3\2\2\2\u017c\u017d\3\2\2\2\u017df\3\2\2\2\u017e\u0180\t\2\2\2\u017f"+
"\u017e\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0182\3\2\2\2\u0181\u0183\4\62"+
";\2\u0182\u0181\3\2\2\2\u0183\u0184\3\2\2\2\u0184\u0182\3\2\2\2\u0184"+
"\u0185\3\2\2\2\u0185h\3\2\2\2\u0186\u018c\5k\66\2\u0187\u018b\5k\66\2"+
"\u0188\u018b\5q9\2\u0189\u018b\7a\2\2\u018a\u0187\3\2\2\2\u018a\u0188"+
"\3\2\2\2\u018a\u0189\3\2\2\2\u018b\u018e\3\2\2\2\u018c\u018a\3\2\2\2\u018c"+
"\u018d\3\2\2\2\u018dj\3\2\2\2\u018e\u018c\3\2\2\2\u018f\u0192\5m\67\2"+
"\u0190\u0192\5o8\2\u0191\u018f\3\2\2\2\u0191\u0190\3\2\2\2\u0192l\3\2"+
"\2\2\u0193\u0194\4c|\2\u0194n\3\2\2\2\u0195\u0196\4C\\\2\u0196p\3\2\2"+
"\2\u0197\u0198\4\62;\2\u0198r\3\2\2\2\u0199\u019a\7*\2\2\u019at\3\2\2"+
"\2\u019b\u019c\7+\2\2\u019cv\3\2\2\2\u019d\u019e\7}\2\2\u019ex\3\2\2\2"+
"\u019f\u01a0\7\177\2\2\u01a0z\3\2\2\2\u01a1\u01a2\7<\2\2\u01a2|\3\2\2"+
"\2\u01a3\u01a5\t\3\2\2\u01a4\u01a3\3\2\2\2\u01a5\u01a6\3\2\2\2\u01a6\u01a4"+
"\3\2\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8\3\2\2\2\u01a8\u01a9\b?\2\2\u01a9"+
"~\3\2\2\2\u01aa\u01ab\7\61\2\2\u01ab\u01ac\7\61\2\2\u01ac\u01b0\3\2\2"+
"\2\u01ad\u01af\n\4\2\2\u01ae\u01ad\3\2\2\2\u01af\u01b2\3\2\2\2\u01b0\u01ae"+
"\3\2\2\2\u01b0\u01b1\3\2\2\2\u01b1\u01b3\3\2\2\2\u01b2\u01b0\3\2\2\2\u01b3"+
"\u01b4\5\u0081A\2\u01b4\u01b5\3\2\2\2\u01b5\u01b6\b@\2\2\u01b6\u0080\3"+
"\2\2\2\u01b7\u01b9\7\17\2\2\u01b8\u01b7\3\2\2\2\u01b8\u01b9\3\2\2\2\u01b9"+
"\u01ba\3\2\2\2\u01ba\u01bc\7\f\2\2\u01bb\u01b8\3\2\2\2\u01bc\u01bd\3\2"+
"\2\2\u01bd\u01bb\3\2\2\2\u01bd\u01be\3\2\2\2\u01be\u0082\3\2\2\2\16\2"+
"\u0175\u017c\u017f\u0184\u018a\u018c\u0191\u01a6\u01b0\u01b8\u01bd\3\b"+
"\2\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}

View File

@@ -0,0 +1,112 @@
T__0=1
NULL=2
SELF=3
TRUE=4
FALSE=5
SQRT=6
SIN=7
COS=8
NOT=9
GETX=10
GETY=11
GETRADIUS=12
GETDIR=13
GETAP=14
GETMAXAP=15
GETHP=16
SAMETEAM=17
SEARCHOBJ=18
DISTANCE=19
ISWORM=20
ISFOOD=21
ISPROJECTILE=22
TURN=23
MOVE=24
JUMP=25
EAT=26
FIRE=27
DEF=28
IF=29
INVOKE=30
THEN=31
ELSE=32
WHILE=33
BREAK=34
PRINT=35
ASSIGN=36
ADD=37
SUB=38
MUL=39
DIV=40
AND=41
OR=42
LT=43
LTE=44
GT=45
GTE=46
EQ=47
NEQ=48
NUMBER=49
FLOAT=50
INTEGER=51
IDENTIFIER=52
LEFT_PAREN=53
RIGHT_PAREN=54
LEFT_BRACE=55
RIGHT_BRACE=56
COLON=57
WHITESPACE=58
SINGLE_COMMENT=59
';'=1
'null'=2
'self'=3
'true'=4
'false'=5
'sqrt'=6
'sin'=7
'cos'=8
'!'=9
'getx'=10
'gety'=11
'getradius'=12
'getdir'=13
'getap'=14
'getmaxap'=15
'gethp'=16
'sameteam'=17
'searchobj'=18
'distance'=19
'isworm'=20
'isfood'=21
'isprojectile'=22
'turn'=23
'move'=24
'jump'=25
'eat'=26
'fire'=27
'def'=28
'if'=29
'invoke'=30
'then'=31
'else'=32
'while'=33
'break'=34
'print'=35
':='=36
'+'=37
'-'=38
'*'=39
'/'=40
'&&'=41
'||'=42
'<'=43
'<='=44
'>'=45
'>='=46
'=='=47
'!='=48
'('=53
')'=54
'{'=55
'}'=56
':'=57

View File

@@ -0,0 +1,306 @@
// Generated from WormsProgram.g4 by ANTLR 4.7.1
package worms.programs.internal.parser.generated;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
/**
* This interface defines a complete generic visitor for a parse tree produced
* by {@link WormsProgramParser}.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public interface WormsProgramVisitor<T> extends ParseTreeVisitor<T> {
/**
* Visit a parse tree produced by {@link WormsProgramParser#program}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitProgram(WormsProgramParser.ProgramContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#proceduredef}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitProceduredef(WormsProgramParser.ProceduredefContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#statement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitStatement(WormsProgramParser.StatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#assignmentStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAssignmentStatement(WormsProgramParser.AssignmentStatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#whileStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitWhileStatement(WormsProgramParser.WhileStatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#ifStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIfStatement(WormsProgramParser.IfStatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#printStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPrintStatement(WormsProgramParser.PrintStatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#sequenceStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSequenceStatement(WormsProgramParser.SequenceStatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#invokeStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitInvokeStatement(WormsProgramParser.InvokeStatementContext ctx);
/**
* Visit a parse tree produced by {@link WormsProgramParser#breakStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitBreakStatement(WormsProgramParser.BreakStatementContext ctx);
/**
* Visit a parse tree produced by the {@code turnAction}
* labeled alternative in {@link WormsProgramParser#actionStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTurnAction(WormsProgramParser.TurnActionContext ctx);
/**
* Visit a parse tree produced by the {@code moveAction}
* labeled alternative in {@link WormsProgramParser#actionStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMoveAction(WormsProgramParser.MoveActionContext ctx);
/**
* Visit a parse tree produced by the {@code jumpAction}
* labeled alternative in {@link WormsProgramParser#actionStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitJumpAction(WormsProgramParser.JumpActionContext ctx);
/**
* Visit a parse tree produced by the {@code eatAction}
* labeled alternative in {@link WormsProgramParser#actionStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitEatAction(WormsProgramParser.EatActionContext ctx);
/**
* Visit a parse tree produced by the {@code fireAction}
* labeled alternative in {@link WormsProgramParser#actionStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFireAction(WormsProgramParser.FireActionContext ctx);
/**
* Visit a parse tree produced by the {@code distanceExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDistanceExpression(WormsProgramParser.DistanceExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code cosExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitCosExpression(WormsProgramParser.CosExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getYExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetYExpression(WormsProgramParser.GetYExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code andOrExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAndOrExpression(WormsProgramParser.AndOrExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code isWormExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIsWormExpression(WormsProgramParser.IsWormExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code notExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNotExpression(WormsProgramParser.NotExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code comparisonExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitComparisonExpression(WormsProgramParser.ComparisonExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code parenExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParenExpression(WormsProgramParser.ParenExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getRadiusExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetRadiusExpression(WormsProgramParser.GetRadiusExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code trueLiteralExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTrueLiteralExpression(WormsProgramParser.TrueLiteralExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code nullExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNullExpression(WormsProgramParser.NullExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code sqrtExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSqrtExpression(WormsProgramParser.SqrtExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code sinExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSinExpression(WormsProgramParser.SinExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code sameTeamExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSameTeamExpression(WormsProgramParser.SameTeamExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code isProjectileExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIsProjectileExpression(WormsProgramParser.IsProjectileExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code isFoodExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIsFoodExpression(WormsProgramParser.IsFoodExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code constantExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitConstantExpression(WormsProgramParser.ConstantExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code searchObjExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSearchObjExpression(WormsProgramParser.SearchObjExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getXExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetXExpression(WormsProgramParser.GetXExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code readVariableExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitReadVariableExpression(WormsProgramParser.ReadVariableExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code mulDivExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMulDivExpression(WormsProgramParser.MulDivExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getDirectionExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetDirectionExpression(WormsProgramParser.GetDirectionExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code selfExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSelfExpression(WormsProgramParser.SelfExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getHPExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetHPExpression(WormsProgramParser.GetHPExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code addSubExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAddSubExpression(WormsProgramParser.AddSubExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getMaxAPExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetMaxAPExpression(WormsProgramParser.GetMaxAPExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code getAPExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGetAPExpression(WormsProgramParser.GetAPExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code falseLiteralExpression}
* labeled alternative in {@link WormsProgramParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFalseLiteralExpression(WormsProgramParser.FalseLiteralExpressionContext ctx);
}

View File

View File

@@ -0,0 +1,10 @@
package worms.util;
@SuppressWarnings("serial")
/**
* Students working alone on the project will throw <code>MustNotImplementException</code>
* for each method they must not implement.
*/
public class MustNotImplementException extends RuntimeException{
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
package worms.model;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;
import worms.util.Coordinate;
import java.util.concurrent.ThreadLocalRandom;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
/**
* A class of Bazookas involving a worm.
*
* @version 1.0
* @author Arthur Bols & Leen Dereu
*/
public class Bazooka extends Projectile {
/**
* @param worm
*
* @post ...
* |worm == worm
* @post ...
* |new.getMass() == 300
* @post ...
* |new.getForce() == calcForce(worm.getActionPoints())
*/
@Raw
public Bazooka(Worm worm) {
super(worm, 300, calcForce(worm.getActionPoints()));
}
/**
* @return ...
* |int nb =ThreadLocalRandom.current().nextInt(15) / 2
* |nb += (nb % 2 == 0 ? 1:0)
* |result == nb
*/
@Override
@Raw
protected int getRandomHitPoints() {
int nb =ThreadLocalRandom.current().nextInt(15) / 2;
nb += (nb % 2 == 0 ? 1:0);
return nb;
}
/**
* @return ...
* |result == this.hitPoints * (int) this.force
*
*/
@Basic
@Override
@Raw
protected int getImpactHitPoints() {
return this.hitPoints * (int) this.force;
}
/**
* @param value
*
* @post ...
* |if (value > 7)
* | value = 7
* |else if (value % 2 != 1)
* | if (value == 0)
* | value++
* | else
* | value--
* |super.hitPoints = value
*/
@Override
protected void setHitPoints(int value) {
if (value > 7) value = 7;
else if (value % 2 != 1) {
if (value == 0) value++;
else value--;
}
super.hitPoints = value;
}
/**
* @param actionPoints
*
* @return ...
* |double hp = 2.5 + actionPoints % 8.0
* |if (hp > 9.5
* | result == 9.5
* |result == hp
*/
public static double calcForce(double actionPoints) {
double hp = 2.5 + actionPoints % 8.0;
if (hp > 9.5) return 9.5;
return hp;
}
}

View File

@@ -0,0 +1,80 @@
package worms.model;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;
import worms.util.Coordinate;
/**
* A class of Food involving a world and a location.
*
* @version 2.0
* @author Arthur Bols & Leen Dereu
*/
public class Food extends GameObject {
/**
* @param world
* @param location
*
* @post ...
* |setWorld(world)
* @post ...
* |setLocation(location)
* @post ...
* |setOrientation(0.2)
* @post ...
* |setMass(getRadius(), 150)
*/
@Raw
public Food(World world, double[] location) {
super(world, location, 0.2);
final double rho = 150;
setMass(getRadius(), rho);
}
/**
* @return ...
* |result == this.poisonous
*/
@Basic
@Raw
public boolean isPoisonous() {
return this.poisonous;
}
/**
* @post ...
* |poisonous == true
*/
@Raw
public void poison() {
this.poisonous = true;
}
/**
* @post ...
* |poisonous == false
*/
@Raw
public void heal() {
this.poisonous = false;
}
private boolean poisonous = false;
/**
* @param location
*
* @return ...
* |if (getWorld() != null
* | result == super.isValidLocation(location) && getWorld().isAdjacent(location, getRadius())
* |result == super.isValidLocation(location)
*/
@Override
protected boolean isValidLocation(Coordinate location) {
if (getWorld() != null) return super.isValidLocation(location) && getWorld().isAdjacent(location, getRadius());
return super.isValidLocation(location);
}
}

View File

@@ -0,0 +1,393 @@
package worms.model;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;
import worms.util.Coordinate;
import static java.lang.Math.*;
/**
* A class of GameObjects involving a world, a location and a radius.
*
* @version 3.0
* @author Arthur Bols & Leen Dereu
*/
public abstract class GameObject {
// region Constructor
//===================================================================================
/**
* @param world
* @param location
* @param radius
*
* @post ...
* |setWorld(world)
* @post ...
* |setLocation(location)
* @post ...
* |setRadius(radius)
*/
@Raw
public GameObject(World world, double[] location, double radius) {
this(world, Coordinate.create(location), radius);
}
/**
* @param world
* @param location
* @param radius
*
* @post ...
* |new.getLocation() == location
* @post ...
* |new.getRadius() == radius
* @post ...
* |if (isValidWorld(world))
* | world.add(this)
* @post ...
* |new.getWorld() == world
*
* @throws IllegalArgumentException ...
* |!isValidLocation(location)
*/
@Raw
public GameObject(World world, Coordinate location, double radius) {
if (!isValidLocation(location)) throw new IllegalArgumentException("Illegal location");
setLocation(location);
setRadius(radius);
if (isValidWorld(world)) world.add(this);
setWorld(world);
}
// ===================================================================================
// endregion
// region world
//===================================================================================
/**
* @return ...
* |result == this.world
*/
@Basic
@Raw
public World getWorld() {
return this.world;
}
/**
* @param world
*
* @return ...
* |result == world != null && !world.hasActiveGame() && !world.isTerminated()
*/
public static boolean isValidWorld(World world) {
return world != null && !world.hasActiveGame() && !world.isTerminated();
}
/**
* @param world
*
* @post ...
* |if (world == null)
* | this.world = null
* | return
* @post ...
* |new.getWorld() == world
*
* @throws IllegalArgumentException ...
* |!isValidWorld(world)
*/
public void setWorld(World world) throws IllegalArgumentException {
if (world == null) {
this.world = null;
return;
}
if (!isValidWorld(world)) throw new IllegalArgumentException();
this.world = world;
}
protected World world;
// ===================================================================================
// endregion
// region location
//===================================================================================
/**
* @return ...
* |result == this.location
*/
public Coordinate getLocation() {
return this.location;
}
/**
* @return ...
* |result == this.location.toArray()
*/
public double[] getLocationArray() {
return this.location.toArray();
}
/**
* @param location
*
* @post ...
* |if (!isValidLocation(location)
* | if (!(location.getX() - radius < 0) || !(location.getX() + radius > getWorld().getWidth()) ||
* | !(location.getY() + radius > getWorld().getHeight()) || !(location.getY() - radius < 0))
* | world.remove(this)
* @post ...
* |if (isValidLocation(location)
* | new.getLocation() == location
*
* @throws IllegalArgumentException ...
* |!isValidLocation(location) && (location.getX() - radius < 0 ||
* |location.getX() + radius > getWorld().getWidth() ||
* |location.getY() + radius > getWorld().getHeight() ||
* |location.getY() - radius < 0)
*/
protected void setLocation(Coordinate location) throws IllegalArgumentException {
if (!isValidLocation(location)) {
if (!(location.getX() - radius < 0) ||
!(location.getX() + radius > this.world.getWidth()) ||
!(location.getY() + radius > this.world.getHeight()) ||
!(location.getY() - radius < 0)) {
this.world.remove(this);
} else throw new IllegalArgumentException();
}
this.location = location;
}
/**
* @param location
*
* @post ...
* |new.getLocation() == Coordinate.create(location)
*/
protected void setLocation(double[] location) {
setLocation(Coordinate.create(location));
}
/**
* @param location
*
* @return ...
* |if (world == null)
* | result == !Double.isNaN(location.getX()) && !Double.isNaN(location.getY())
* |result == !Double.isNaN(location.getX()) && !Double.isNaN(location.getY()) &&
* | !(location.getX() - getRadius() < 0) && !(location.getX() + getRadius() > getWorld().getWidth()) &&
* | !(location.getY() + getRadius() > getWorld().getHeight()) && !(location.getY() - getRadius() < 0) &&
* | getWorld().isPassable(location)
*/
protected boolean isValidLocation(Coordinate location) {
if (world == null) {
return !Double.isNaN(location.getX()) &&
!Double.isNaN(location.getY());
}
return !Double.isNaN(location.getX()) &&
!Double.isNaN(location.getY()) &&
!(location.getX() - this.radius < 0) &&
!(location.getX() + this.radius > this.world.getWidth()) &&
!(location.getY() + this.radius > this.world.getHeight()) &&
!(location.getY() - this.radius < 0) && this.world.isPassable(location);
}
protected Coordinate location;
// ===================================================================================
// endregion
// region radius
//===================================================================================
/**
* @return ...
* |result == this.radius
*/
@Basic
@Raw
public double getRadius() {
return this.radius;
}
/**
* @param radius
*
* @post ...
* |new.getRadius() == radius
*
* @throws IllegalArgumentException ...
* |!canHaveAsRadius(radius)
*/
@Raw
protected void setRadius(double radius) {
if (!canHaveAsRadius(radius)) throw new IllegalArgumentException();
this.radius = radius;
}
protected double radius;
/**
* @param radius
*
* @return ...
* |result == !Double.isNaN(radius) && radius > 0
*/
@Basic
@Raw
private boolean canHaveAsRadius(double radius) {
return !Double.isNaN(radius) && radius > 0;
}
// ===================================================================================
// endregion
// region mass
//===================================================================================
/**
* @return ...
* |result == this.mass
*/
@Basic
@Raw
public double getMass() {
return this.mass;
}
/**
* @param radius
* @param rho
*
* @post ...
* |new.getMass() == rho * (4.0 / 3.0 * PI * pow(radius, 3.0)
*/
@Raw
protected void setMass(double radius, double rho) {
this.mass = rho * (4.0 / 3.0 * PI * pow(radius, 3.0));
}
protected double mass;
// ===================================================================================
// endregion
// region distance calc
//===================================================================================
/**
* @param o
*
* @return ...
* |result == getDistance(o.getLocation(), o.getRadius())
*/
public double getDistance(GameObject o) {
return getDistance(o.getLocation(), o.getRadius());
}
/**
* @param otherLocation
* @param radius
*
* @return ...
* |result == Math.round((Math.sqrt(Math.pow((otherLocation.getX() - this.location.getX()), 2) + Math.pow(
* |(otherLocation.getY() - this.location.getY()), 2)) - radius - this.radius) * 10000.0) / 10000.0
*/
public double getDistance(Coordinate otherLocation, double radius) {
return Math.round((Math.sqrt(Math.pow((otherLocation.getX() - this.location.getX()), 2) +
Math.pow((otherLocation.getY() - this.location.getY()), 2)) - radius - this.radius) * 10000.0) / 10000.0;
}
/**
* @param start
* @param end
*
* @return ...
* |result == Math.sqrt(Math.pow(Math.abs(start.getX() - end.getX()), 2) +
* | Math.pow(Math.abs(start.getY() - end.getY()), 2))
*/
public static double getDistance(Coordinate start, Coordinate end) {
return Math.sqrt(Math.pow(Math.abs(start.getX() - end.getX()), 2) +
Math.pow(Math.abs(start.getY() - end.getY()), 2));
}
/**
* @param o
*
* @return ...
* |if (o.equals(this))
* | result == Double.NaN
* |Coordinate otherLoc = o.getLocation()
* |result == Math.abs(Math.atan(Math.abs(this.location.getX() - otherLoc.getX()) /
* | Math.abs(this.location.getY() - otherLoc.getY())) - Math.PI / 2.0)
*/
public double getAngle(GameObject o) {
if (o.equals(this)) return Double.NaN;
Coordinate otherLoc = o.getLocation();
return Math.abs(Math.atan(Math.abs(this.location.getX() - otherLoc.getX()) /
Math.abs(this.location.getY() - otherLoc.getY())) - Math.PI / 2.0);
}
// ===================================================================================
// endregion
// region destructor
//===================================================================================
/**
* @return ...
* |result == this.terminated
*/
@Basic
@Raw
public boolean isTerminated() {
return this.terminated;
}
/**
* @post ...
* |new.isTerminated() == true
* @post ...
* |if (this.world != null)
* | this.world.remove(this)
*/
@Basic
public void terminate() {
this.terminated = true;
if (this.world != null) {
this.world.remove(this);
}
}
private boolean terminated = false;
// ===================================================================================
// endregion
}

View File

@@ -0,0 +1,12 @@
package worms.model;
import worms.util.Coordinate;
public interface IJumpable {
void jump(double timeStep);
Coordinate jumpStep(double elapsed);
double jumpTime(double timeStep);
}

View File

@@ -0,0 +1,257 @@
package worms.model;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;
import worms.internal.gui.game.IActionHandler;
import worms.programs.Expression;
import worms.programs.Procedure;
import worms.programs.Statement;
import java.util.*;
import static java.lang.Math.ceil;
import static java.lang.Math.toDegrees;
public class Program {
public Program(List<Procedure> proc, Statement main) {
this.main = main;
procMap = new HashMap<>();
proc.forEach(p -> procMap.put(p.getName(), p.getBody()));
}
public Worm getWorm() {
return this.worm;
}
public Map<String, Object> getVariables() {
return this.varMap;
}
public void execute() {
enoughAP = true;
if (callStack.empty()) {
executeStatement(main);
} else {
while (!callStack.empty()) {
CallStackNode node = callStack.pop();
while(node.statementIterator == null && !callStack.empty()) {
executeStatement(node.lastStatement);
if (!enoughAP) break;
node = callStack.pop();
}
callStack.push(node);
if (node.statementIterator == null) {
executeStatement(node.lastStatement);
} else {
Iterator<Statement> it = node.statementIterator;
if (!enoughAP) break;
while (it.hasNext()) {
Statement current = it.next();
executeStatement(current);
if (!enoughAP) {
node.lastStatement = current;
break;
}
}
if (!it.hasNext() && enoughAP) callStack.pop();
}
if (!enoughAP) break;
}
}
}
public List<Object> debugExecute() {
execute();
if (!enoughAP) return null;
callStack.clear();
return printList;
}
protected void setWorm(Worm worm) {
this.worm = worm;
}
protected void setActionHandler(IActionHandler actionHandler) {
this.actionHandler = actionHandler;
}
private boolean breakLoop = false;
@SuppressWarnings({"unchecked", "SuspiciousMethodCalls"})
private void executeStatement(Statement s) {
if (!enoughAP) return;
Statement.Type mainType = s.getType();
switch (mainType) {
case BLOCK:
executeStatementBlock((List<Statement>) s.getData());
break;
case ASSIGN:
Statement.Assign data = (Statement.Assign) s.getData();
if (procMap.containsKey(data.getVariableName())) throw new IllegalArgumentException("Already a procedure with same name.");
varMap.put(data.getVariableName(), data.getValue().execute(this));
break;
case PRINT:
printList.add(((Expression) s.getData()).execute(this));
break;
case ACTION:
Statement.Action action = (Statement.Action) s.getData();
switch (action.getType()) {
case TURN:
Double val = action.getValue().execute(this);
if (val == null) throw new IllegalArgumentException("Turn cannot be null");
if (worm.getActionPoints() - (long) Math.abs(ceil(toDegrees(val) / 6)) < 0) {
enoughAP = false;
callStack.push(new CallStackNode(null, s));
return;
}
else if (!worm.canTurn(val)) throw new IllegalArgumentException("Invalid turn value");
actionHandler.turn(worm, action.getValue().execute(this));
break;
case MOVE:
try {
actionHandler.move(worm);
} catch (IllegalArgumentException | IllegalStateException e) {
enoughAP = false;
callStack.push(new CallStackNode(null, s));
return;
}
break;
case JUMP:
if (worm.getActionPoints() <= 0) {
enoughAP = false;
callStack.push(new CallStackNode(null, s));
return;
}
actionHandler.jump(worm);
break;
case EAT:
if (!worm.canEat()) {
enoughAP = false;
callStack.push(new CallStackNode(null, s));
return;
}
actionHandler.eat(worm);
break;
case FIRE:
if (!worm.canFire()) {
enoughAP = false;
callStack.push(new CallStackNode(null, s));
return;
}
actionHandler.fire(worm);
break;
}
break;
case WHILE:
inLoop++;
currentType.push(Statement.Type.WHILE);
CallStackNode whileNode = new CallStackNode(null, s);
callStack.push(whileNode);
Boolean condition = (Boolean) ((Statement.While) s.getData()).getCondition().execute(this);
if (condition == null) throw new IllegalArgumentException("Condition has to be a boolean");
while(condition) {
executeStatement(((Statement.While) s.getData()).getBody());
if (breakLoop || !enoughAP) {
breakLoop = false;
break;
}
condition = (Boolean) ((Statement.While) s.getData()).getCondition().execute(this);
if (condition == null) throw new IllegalArgumentException("Condition has to be a boolean");
}
if (enoughAP) {
callStack.remove(whileNode);
}
inLoop--;
currentType.pop();
break;
case IF:
if ((Boolean) ((Statement.If) s.getData()).getCondition().execute(this)) {
executeStatement(((Statement.If) s.getData()).getIfBody());
} else {
Statement elseBody = ((Statement.If) s.getData()).getElseBody();
if (elseBody != null) {
executeStatement(elseBody);
}
}
break;
case INVOKE:
currentType.push(Statement.Type.ASSIGN);
inProcedure++;
Statement proc = procMap.get(s.getData());
if (proc == null) throw new IllegalArgumentException("Procedure not defined");
executeStatement(proc);
inProcedure--;
currentType.pop();
break;
case BREAK:
if (inLoop == 0 && inProcedure == 0) {
throw new IllegalArgumentException("BREAK out of scope.");
}
if (currentType.peek() == Statement.Type.WHILE) {
breakLoop = true;
} else {
breakProcedure = true;
}
break;
}
}
private Stack<CallStackNode> callStack = new Stack<>();
private void executeStatementBlock(List<Statement> list) {
Iterator<Statement> it = list.iterator();
CallStackNode node = new CallStackNode(it, null);
callStack.push(node);
while(it.hasNext()) {
Statement current = it.next();
node.lastStatement = current;
executeStatement(current);
if (!enoughAP || breakLoop || breakProcedure) {
breakProcedure = false;
break;
}
}
if (!it.hasNext() && enoughAP) callStack.pop();
}
private class CallStackNode {
private Iterator<Statement> statementIterator;
private Statement lastStatement;
private CallStackNode(Iterator<Statement> st, Statement ls) {
statementIterator = st;
lastStatement = ls;
}
}
private final Map<String, Statement> procMap;
private final Map<String, Object> varMap = new HashMap<>();
private final List<Object> printList = new ArrayList<>();
private Stack<Statement.Type> currentType = new Stack<>();
private int inLoop = 0;
private int inProcedure = 0;
private boolean breakProcedure = false;
private boolean enoughAP = true;
private IActionHandler actionHandler;
private Worm worm;
private final Statement main;
}

View File

@@ -0,0 +1,343 @@
package worms.model;
import static java.lang.Math.*;
import worms.util.Coordinate;
import java.util.List;
/**
* A class of Projectiles involving a worm, a mass and a force.
*
* @version 1.0
* @author Arthur Bols & Leen Dereu
*/
public abstract class Projectile extends GameObject implements IJumpable {
// region constructor
//===================================================================================
public static final double G = 5.0;
public static final double FORCE_TIME = 0.5;
private static final int rho = 7800;
/**
* @param worm
* @param mass
* @param force
*
* @post ...
* |new.getWorld() == worm.getWorld()
* @post ...
* |new.getLocation() == calcLocation(worm.getLocation(), worm.getOrientation(), worm.getRadius(), mass)
* @post ...
* |new.getRadius() == calcRadius(mass)
* @post ...
* |new.getMass() == mass
* @post ...
* |new.getForce() == force
* @post ...
* |new.getOrientation() == worm.getOrientation()
* @post ...
* |new.getHitPoints() == getRadomHitPoints()
*/
protected Projectile (Worm worm, double mass, double force) {
super(worm.getWorld(), calcLocation(worm.getLocation(), worm.getOrientation(), worm.getRadius(), mass), calcRadius(mass));
super.mass = mass;
this.force = force;
this.orientation = worm.getOrientation();
this.hitPoints = getRandomHitPoints();
}
// ===================================================================================
// endregion
// region radius / orientation / force
//===================================================================================
/**
* @return ...
* |result == orientation
*/
public double getOrientation() {
return this.orientation;
}
private final double orientation;
/**
* @param mass
*
* @return ...
* |result == pow(((mass / 1000.0 / rho) * (3.0 / (4.0 * PI))), 1.0 / 3.0)
*/
public static double calcRadius(double mass) {
return pow(((mass / 1000.0 / rho) * (3.0 / (4.0 * PI))), 1.0 / 3.0);
}
/**
* @return ...
* |result == this.force
*/
public double getForce() {
return this.force;
}
protected final double force;
// ===================================================================================
// endregion
// region hit points
//===================================================================================
/**
* @return ...
* |result == this.hitPoints
*/
public int getHitPoints() {
return this.hitPoints;
}
/**
* @param value
*
* @post ...
* |new.getHitPoints() == this.hitPoints + value
*/
public void incrementHitPoints(int value) {
setHitPoints(this.hitPoints + value);
}
/**
* @param worm
*
* @post ...
* |new.worm.getHitPoints() == worm.getHitPoints - getImpactHitPoints()
* @post ...
* |terminate()
*/
public void hit(Worm worm){
worm.decreaseHitPoints(getImpactHitPoints());
terminate();
}
protected abstract void setHitPoints(int value) throws IllegalArgumentException;
protected abstract int getImpactHitPoints();
protected abstract int getRandomHitPoints();
protected int hitPoints;
// ===================================================================================
// endregion
// region jump
//===================================================================================
/**
* @param jumpTimeStep
*
* @post ...
* |double v = jumpVelocity();
* |double t = jumpTime(jumpTimeStep);
* |double a = getOrientation();
* |
* |if (!getWorld().isAdjacent(getLocation(),getRadius()))
* | newLocation = Coordinate.create(getLocation().getX() + v * t * cos(a),
* | getLocation().getY() + v * t * sin(a) - (G * t * t) / 2.0);
* |newLocation = this.location
* @post ...
* |if (!isValidLocation(newLocation))
* | terminate()
* | return
* @post ...
* |new.getLocation() == newLocation
* @post ...
* | List<Worm> worms = getWorld().getGameObjectsByClass(Worm.class)
* |for (Worm worm: worms)
* | if (this.getDistance(worm) < 0)
* | hit(worm)
*
* @throws IllegalStateException ...
* |!canJump()
*/
public void jump(double jumpTimeStep) throws IllegalStateException {
if (!canJump())
throw new IllegalStateException();
double v = jumpVelocity();
double t = jumpTime(jumpTimeStep);
double a = getOrientation();
Coordinate newLocation = this.location;
List<Worm> worms = getWorld().getGameObjectsByClass(Worm.class);
if (!getWorld().isAdjacent(getLocation(),getRadius())) {
newLocation = Coordinate.create(getLocation().getX() + v * t * cos(a),
getLocation().getY() + v * t * sin(a) - (G * t * t) / 2.0);
}
if (!isValidLocation(newLocation)) {
terminate();
return;
}
setLocation(newLocation);
for (Worm worm: worms) {
if (this.getDistance(worm) < 0) {
hit(worm);
}
}
}
/**
* @param timeStep
*
* @return ...
* |World world = getWorld()
* |double v = jumpVelocity();
* |double time = 0;
* |double a = getOrientation();
* |double radius = getRadius();
* |List<Worm> worms = world.getGameObjectsByClass(Worm.class);
* |if (!world.isPassable(this.location) || worms.stream().anyMatch(w -> w.getDistance(this) < 0))
* | result == 0.0
* |while(true)
* | time += timeStep
* | Coordinate newLoc = Coordinate.create(this.location.getX() + v * time * cos(a),
* | this.location.getY() + v * time * sin(a) - (G * time * time) / 2.0)
* | if (newLoc.getX() - radius < 0 || newLoc.getY() - radius < 0 || newLoc.getX() + radius >
* | world.getWidth() || newLoc.getY() + radius > world.getHeight() || !world.isPassable(newLoc) ||
* | worms.stream().anyMatch(w -> w.getDistance(newLoc, this.radius) < 0))
* | result == time
*
* @throws IllegalStateException ...
* |world == null
*/
public double jumpTime(double timeStep) {
World world = getWorld();
if (world == null) {
throw new IllegalStateException("World cannot be null");
}
double v = jumpVelocity();
double time = 0;
double a = getOrientation();
double radius = getRadius();
List<Worm> worms = world.getGameObjectsByClass(Worm.class);
if (!world.isPassable(this.location) || worms.stream().anyMatch(w -> w.getDistance(this) < 0)) {
return 0.0;
}
while(true) {
time += timeStep;
Coordinate newLoc = Coordinate.create(this.location.getX() + v * time * cos(a),
this.location.getY() + v * time * sin(a) - (G * time * time) / 2.0);
if (newLoc.getX() - radius < 0 || newLoc.getY() - radius < 0 || newLoc.getX() + radius > world.getWidth() ||
newLoc.getY() + radius > world.getHeight() || !world.isPassable(newLoc) ||
worms.stream().anyMatch(w -> w.getDistance(newLoc, this.radius) < 0)) {
return time;
}
}
}
/**
* @param elapsedTime
*
* @return ...
* |double velocity = this.jumpVelocity()
* |result == Coordinate.create(getLocation().getX() + velocity * cos(getOrientation()) * elapsedTime,
* | getLocation().getY() + velocity * sin(getOrientation()) * elapsedTime - 0.5 * G *
* | pow(elapsedTime, 2))
*
* @throws IllegalArgumentException ...
* |Double.isNaN(elapsedTime) || elapsedTime < 0
*/
public Coordinate jumpStep(double elapsedTime) {
if (Double.isNaN(elapsedTime) || elapsedTime < 0)
throw new IllegalArgumentException();
double velocity = this.jumpVelocity();
return Coordinate.create(getLocation().getX() + velocity * cos(getOrientation()) * elapsedTime,
getLocation().getY() + velocity * sin(getOrientation()) * elapsedTime - 0.5 * G * pow(elapsedTime, 2));
}
/**
* @return ...
* |result == getOrientation() < PI
*/
private boolean canJump() {
return getOrientation() < PI;
}
/**
* @return ...
* |result == (getForce() / (getMass() / 1000)) * FORCE_TIME
*/
private double jumpVelocity() {
return (getForce() / (getMass() / 1000)) * FORCE_TIME;
}
// ===================================================================================
// endregion
// region location
//===================================================================================
/**
* @param location
*
* @return ...
* |if (getWorld() == null)
* | result == !Double.isNaN(location.getX()) && !Double.isNaN(location.getY())
* |result == !Double.isNaN(location.getX()) && !Double.isNaN(location.getY()) &&
* | !(location.getX() - getRadius() < 0) && !(location.getX() + getRadius() > getWorld().getWidth()) &&
* | !(location.getY() + getRadius() > getWorld().getHeight()) && !(location.getY() - getRadius() < 0)
*/
@Override
protected boolean isValidLocation(Coordinate location) {
double radius = getRadius();
if (getWorld() == null) {
return !Double.isNaN(location.getX()) &&
!Double.isNaN(location.getY());
}
return !Double.isNaN(location.getX()) &&
!Double.isNaN(location.getY()) &&
!(location.getX() - radius < 0) &&
!(location.getX() + radius > getWorld().getWidth()) &&
!(location.getY() + radius > getWorld().getHeight()) &&
!(location.getY() - radius < 0);
}
/**
* @param wormLocation
* @param wormOrientation
* @param wormRadius
* @param mass
*
* @return ...
* |double radius = calcRadius(mass)
* |result == Coordinate.create(wormLocation.getX() + cos(wormOrientation) * (wormRadius + radius),
* | wormLocation.getY() + sin(wormOrientation) * (wormRadius + radius))
*/
public static Coordinate calcLocation(Coordinate wormLocation, double wormOrientation, double wormRadius, double mass) {
double radius = calcRadius(mass);
return Coordinate.create(wormLocation.getX() + cos(wormOrientation) * (wormRadius + radius),
wormLocation.getY() + sin(wormOrientation) * (wormRadius + radius));
}
// ===================================================================================
// endregion
}

Some files were not shown because too many files have changed in this diff Show More