Compare commits
285 Commits
Author | SHA1 | Date | |
---|---|---|---|
93cb385aaa | |||
80d6ce748c | |||
cc277a045f | |||
|
4cf6e67a78 | ||
|
e416911ae0 | ||
|
6f60a4d06d | ||
|
4b4667296e | ||
ecd65207ac | |||
|
91899be62c | ||
|
ec12d20967 | ||
|
8ab759026f | ||
|
e4c938dbcd | ||
|
f6c6399d6a | ||
|
94a76c2aca | ||
|
5c64518c41 | ||
|
552ed3ac94 | ||
|
47ae1f58c1 | ||
|
f21a01e1d3 | ||
|
9f8a250f71 | ||
|
7f82c3e334 | ||
|
b4425849b9 | ||
b0b94ab5d6 | |||
98de279626 | |||
f3d6d971b9 | |||
ffcc27104c | |||
21c9aea4fe | |||
|
49bd7e5950 | ||
|
9e0d87ccbc | ||
|
8b4e147d9e | ||
0fd761e611 | |||
8aa2699d69 | |||
|
0fbf371d79 | ||
|
38446cabb6 | ||
|
be9e8ae8f9 | ||
562e83ccfc | |||
|
c5f55f29fb | ||
|
817e63251a | ||
|
d30f39509f | ||
4d2a957995 | |||
|
12defdc769 | ||
5e9c6b25d9 | |||
36bf17b689 | |||
|
9f2e91836c | ||
119a112555 | |||
20bc7330f6 | |||
|
ed6be5d2b8 | ||
63cabe27fc | |||
facabe5723 | |||
|
d1559206d0 | ||
0457f135e4 | |||
902fb3b89d | |||
aae6e2ce58 | |||
c684158ba9 | |||
|
909d972654 | ||
|
6313adaf4c | ||
|
72cd481583 | ||
5236d4f0d6 | |||
4a1a48e1fe | |||
fa65975994 | |||
|
d80fb7d284 | ||
84a308dc59 | |||
945e5bad83 | |||
9f99e6f4e1 | |||
d3a9475494 | |||
4761ae72c2 | |||
2cd0d3af7a | |||
e0be7248ed | |||
bc05aee249 | |||
|
2e15a29a4d | ||
|
43b2bce9ee | ||
|
99450efe5f | ||
|
688bcd037a | ||
|
cc27abd957 | ||
2d8de28928 | |||
903ad34c64 | |||
518dcaf3fc | |||
dcaf7f0775 | |||
3ce0505f4e | |||
fb690e38f9 | |||
a3f608f593 | |||
ac937eb563 | |||
d1d52783a5 | |||
5ba8b7f3cd | |||
|
faf5866aa5 | ||
|
8c7a078aa1 | ||
|
383bf84152 | ||
d5bb4d4c51 | |||
|
18b326281c | ||
|
52e461de7b | ||
8d0d8630cf | |||
|
ae1924df51 | ||
78b40fd634 | |||
0da66764cf | |||
|
492299b18d | ||
|
9f9e2dc71e | ||
|
afac62772e | ||
|
d5cbb646ed | ||
|
4eacc246c5 | ||
|
5899928b34 | ||
|
af1ecdbf9f | ||
|
183caf85b4 | ||
0c68e1fa49 | |||
b7354dfbb1 | |||
|
76bc41cba3 | ||
fdc6517f9d | |||
e7490de309 | |||
|
dc5c5f361f | ||
35fb734030 | |||
8c2cb68d22 | |||
a6c127ee3b | |||
68aae2be6e | |||
|
1fff8ee8b9 | ||
|
5171f36916 | ||
|
ebb59b589c | ||
|
c069051001 | ||
48c05010f6 | |||
c0be2de7c1 | |||
262e652dee | |||
|
f9a13b9cfd | ||
afbdd5a88e | |||
dd2190910b | |||
|
a71ee1fb00 | ||
|
51dbd29285 | ||
17ce8566a3 | |||
016a2e2bbb | |||
14d67eb323 | |||
12d6d85325 | |||
|
6d56d86e74 | ||
|
81d3b31213 | ||
ed3843fc1e | |||
d2fac7e27b | |||
7ffe8803c2 | |||
|
adb06f032e | ||
ea150144ba | |||
c4a4bd9c2e | |||
|
a18d586388 | ||
|
8166920c94 | ||
|
6cd76282c0 | ||
|
dac6936895 | ||
dd0b0017d4 | |||
aa00b97ef0 | |||
|
144a46f810 | ||
9ad5255561 | |||
682a63cca1 | |||
049d3ba14b | |||
|
295c510d73 | ||
|
bfe9b06404 | ||
|
b613303b29 | ||
|
3807eb5d0f | ||
c89b7f2a5e | |||
|
0111516595 | ||
|
036a194fb3 | ||
c631e315bd | |||
2c517b0cf8 | |||
|
b61378e423 | ||
|
311ecfd9ce | ||
|
06ac444ba2 | ||
73b72c4902 | |||
f058452320 | |||
|
2442e41453 | ||
|
1ee2f05a60 | ||
|
f45fa3fa96 | ||
|
5f5948795f | ||
f4610de323 | |||
0fe3dc1a41 | |||
e55d7b2c67 | |||
f836afbcdb | |||
a40b6125c7 | |||
6a329e4533 | |||
|
d3bee9510b | ||
|
916342be71 | ||
|
d5873fd766 | ||
|
6e32d5f053 | ||
|
6288d46945 | ||
|
598abe6e63 | ||
|
5b2dc5ee0a | ||
e99123fb7c | |||
fe410b0643 | |||
e19a379ab6 | |||
711d8b69c3 | |||
|
78f195cccc | ||
23a6fcd4b9 | |||
8e5e976c00 | |||
157bd87ca9 | |||
9334d1e75d | |||
021cba609b | |||
|
ffb53f85da | ||
|
4f76b7305a | ||
ba22d855a8 | |||
e1416589b6 | |||
865c3c6429 | |||
|
c2951feb14 | ||
|
f0fb4a6cef | ||
|
87946a1c20 | ||
|
b15ccb5cca | ||
|
40e6a88c10 | ||
|
a361b4abba | ||
|
6374a40469 | ||
|
2f73e0f684 | ||
|
c324656fc2 | ||
5e032793cb | |||
d8981def95 | |||
d1617e9cf3 | |||
d86e5d542a | |||
|
919cb871e3 | ||
|
8c5a2ddb9b | ||
|
4da6bf97f3 | ||
|
1a5d4d66f2 | ||
|
d15ed2e073 | ||
|
71282e480f | ||
652a34e309 | |||
5ce16f8793 | |||
8d28f1f214 | |||
d82212f23e | |||
a4e9834ab0 | |||
0df8b044ef | |||
|
2add5e583a | ||
|
8aefb0c492 | ||
|
b2aef5ff19 | ||
|
42300e5b5c | ||
|
14603fa5ca | ||
1aa5892d3b | |||
ecbf7a1f4c | |||
8195a30ace | |||
3c8da5825f | |||
d51de2eea5 | |||
4a6cc78999 | |||
e0ac1d1958 | |||
|
1136a8ddf9 | ||
|
3f87802dd6 | ||
|
e9e6d14f0c | ||
|
2bcda45bb6 | ||
|
9a5c68f032 | ||
|
6a33cab348 | ||
|
681804af55 | ||
480719aa7e | |||
83e2ff1638 | |||
|
553d41172d | ||
|
5cb39b9c06 | ||
d7426ca4f8 | |||
baa10deb5d | |||
|
2821945d7f | ||
|
faba6f0f11 | ||
|
4429f2dc0f | ||
|
00e082400f | ||
51840ceee5 | |||
|
6aa12c7a1e | ||
50f8424f1f | |||
d594d7981b | |||
39d628f9d4 | |||
|
f41d6c8ede | ||
|
de2d40396e | ||
|
94357661af | ||
41128b67a4 | |||
|
a5d8b12cdd | ||
|
200e8e338a | ||
439752a856 | |||
79360637f6 | |||
|
05a795b493 | ||
|
4d1c5ad2e3 | ||
|
4a370d2d90 | ||
|
82e1cfa8d4 | ||
e58c4a2656 | |||
|
3545ff3894 | ||
|
da56d42f23 | ||
91d6a080d8 | |||
83ae8d18fb | |||
ada39c72b6 | |||
|
cb9a585e71 | ||
|
850a721a3b | ||
8088bfece9 | |||
517168ef49 | |||
3d2e56e093 | |||
a26b768b94 | |||
a3d89d553e | |||
cff052bb9f | |||
dbbc1cfdde | |||
b653e843e1 | |||
|
d22b1f9cbb | ||
47a13dac92 | |||
9804345a83 | |||
|
9b8b05f788 | ||
bcf9f8d7bd | |||
ca7eff1be7 | |||
26dbfd4666 |
125
.gitignore
vendored
Normal 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
After Width: | Height: | Size: 619 KiB |
BIN
Class Diagram4.jpg
Normal file
After Width: | Height: | Size: 448 KiB |
@@ -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>
|
@@ -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>
|
BIN
OGP1718-Worms/images/burger-poisonous.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
OGP1718-Worms/images/burger.png
Normal file
After Width: | Height: | Size: 32 KiB |
3
OGP1718-Worms/levels/Blocks.lvl
Normal file
@@ -0,0 +1,3 @@
|
||||
# A map with blocks
|
||||
map:Blocks.png
|
||||
height:20
|
BIN
OGP1718-Worms/levels/Blocks.png
Normal file
After Width: | Height: | Size: 175 B |
3
OGP1718-Worms/levels/Simple.lvl
Normal file
@@ -0,0 +1,3 @@
|
||||
# A simple map
|
||||
map:Simple.png
|
||||
height:20
|
BIN
OGP1718-Worms/levels/Simple.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
4
OGP1718-Worms/levels/Skulls-lowres.lvl
Normal file
@@ -0,0 +1,4 @@
|
||||
# A smaller version of the skulls map,
|
||||
# which may improve performance
|
||||
map:Skulls-lowres.png
|
||||
height:20
|
BIN
OGP1718-Worms/levels/Skulls-lowres.png
Normal file
After Width: | Height: | Size: 313 KiB |
3
OGP1718-Worms/levels/Skulls.lvl
Normal file
@@ -0,0 +1,3 @@
|
||||
# A large and complex map
|
||||
map:Skulls.png
|
||||
height:20
|
BIN
OGP1718-Worms/levels/Skulls.png
Normal file
After Width: | Height: | Size: 923 KiB |
4
OGP1718-Worms/levels/levels.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Blocks.lvl
|
||||
Simple.lvl
|
||||
Skulls-lowres.lvl
|
||||
Skulls.lvl
|
BIN
OGP1718-Worms/lib/antlr-runtime-4.7.1.jar
Normal file
35
OGP1718-Worms/programs/program.txt
Executable 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;
|
||||
}
|
||||
}
|
20
OGP1718-Worms/programs/program_example.txt
Executable 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; }
|
||||
}
|
||||
}
|
3
OGP1718-Worms/programs/program_simple.txt
Executable file
@@ -0,0 +1,3 @@
|
||||
turn 0.2;
|
||||
fire;
|
||||
move;
|
54
OGP1718-Worms/programs/syntax_test.txt
Executable 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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
0
OGP1718-Worms/src-provided/worms/internal/gui/AbstractPainter.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/ErrorScreen.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/GUIConstants.java
Normal file → Executable file
7
OGP1718-Worms/src-provided/worms/internal/gui/GUIOptions.java
Normal file → Executable 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";
|
||||
}
|
48
OGP1718-Worms/src-provided/worms/internal/gui/GUIUtils.java
Normal file → Executable 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));
|
||||
}
|
||||
}
|
||||
|
79
OGP1718-Worms/src-provided/worms/internal/gui/GameState.java
Normal file → Executable 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() {
|
||||
|
0
OGP1718-Worms/src-provided/worms/internal/gui/InputMode.java
Normal file → Executable file
228
OGP1718-Worms/src-provided/worms/internal/gui/Level.java
Executable 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();
|
||||
}
|
||||
}
|
0
OGP1718-Worms/src-provided/worms/internal/gui/Screen.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/WormsGUI.java
Normal file → Executable file
39
OGP1718-Worms/src-provided/worms/internal/gui/game/DefaultActionHandler.java
Normal file → Executable 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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
5
OGP1718-Worms/src-provided/worms/internal/gui/game/IActionHandler.java
Normal file → Executable 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.
|
||||
*
|
||||
|
0
OGP1718-Worms/src-provided/worms/internal/gui/game/ImageSprite.java
Normal file → Executable file
186
OGP1718-Worms/src-provided/worms/internal/gui/game/PlayGameScreen.java
Normal file → Executable 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
133
OGP1718-Worms/src-provided/worms/internal/gui/game/PlayGameScreenDebugPainter.java
Normal file → Executable 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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
187
OGP1718-Worms/src-provided/worms/internal/gui/game/PlayGameScreenPainter.java
Normal file → Executable 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) {
|
||||
|
2
OGP1718-Worms/src-provided/worms/internal/gui/game/Sprite.java
Normal file → Executable file
@@ -20,6 +20,8 @@ public abstract class Sprite<T> {
|
||||
|
||||
public abstract T getObject();
|
||||
|
||||
public abstract boolean isObjectAlive();
|
||||
|
||||
protected IFacade getFacade() {
|
||||
return getScreen().getFacade();
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
38
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/AddNewFood.java
Executable 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/AddNewTeam.java
Executable 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() {
|
||||
}
|
||||
|
||||
}
|
130
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/AddNewWorm.java
Executable 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();
|
||||
}
|
||||
|
||||
}
|
33
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Command.java
Normal file → Executable 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)");
|
||||
}
|
||||
|
||||
}
|
37
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Eat.java
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
83
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Fire.java
Executable 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();
|
||||
}
|
||||
}
|
||||
}
|
0
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/InstantaneousCommand.java
Normal file → Executable file
29
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Jump.java
Normal file → Executable 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();
|
||||
|
107
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Move.java
Normal file → Executable 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];
|
||||
}
|
||||
}
|
0
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Rename.java
Normal file → Executable 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();
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/StartGame.java
Normal file → Executable 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
16
OGP1718-Worms/src-provided/worms/internal/gui/game/commands/Turn.java
Normal file → Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
14
OGP1718-Worms/src-provided/worms/internal/gui/game/modes/DefaultInputMode.java
Normal file → Executable 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;
|
||||
}
|
||||
}
|
||||
|
1
OGP1718-Worms/src-provided/worms/internal/gui/game/modes/EnteringNameMode.java
Normal file → Executable 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);
|
||||
}
|
||||
|
46
OGP1718-Worms/src-provided/worms/internal/gui/game/modes/GameOverMode.java
Executable 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
64
OGP1718-Worms/src-provided/worms/internal/gui/game/modes/SetupInputMode.java
Executable 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");
|
||||
}
|
||||
|
||||
}
|
0
OGP1718-Worms/src-provided/worms/internal/gui/game/modes/TurningMode.java
Normal file → Executable file
129
OGP1718-Worms/src-provided/worms/internal/gui/game/sprites/FoodSprite.java
Executable 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
143
OGP1718-Worms/src-provided/worms/internal/gui/game/sprites/ProjectileSprite.java
Executable 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;
|
||||
}
|
||||
}
|
56
OGP1718-Worms/src-provided/worms/internal/gui/game/sprites/WormSprite.java
Normal file → Executable 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;
|
||||
}
|
||||
|
0
OGP1718-Worms/src-provided/worms/internal/gui/menu/AbstractMenuScreen.java
Normal file → Executable file
30
OGP1718-Worms/src-provided/worms/internal/gui/menu/ChooseLevelScreen.java
Executable 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() {
|
||||
}
|
||||
}
|
21
OGP1718-Worms/src-provided/worms/internal/gui/menu/MainMenuScreen.java
Normal file → Executable 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);
|
||||
}
|
||||
|
||||
|
0
OGP1718-Worms/src-provided/worms/internal/gui/menu/MenuInputMode.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/messages/Message.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/messages/MessageDisplay.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/messages/MessagePainter.java
Normal file → Executable file
0
OGP1718-Worms/src-provided/worms/internal/gui/messages/MessageType.java
Normal file → Executable file
446
OGP1718-Worms/src-provided/worms/programs/IProgramFactory.java
Executable 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<MyExpression, MyStatement, MyProc, Program>
|
||||
* </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();
|
||||
}
|
||||
|
||||
}
|
20
OGP1718-Worms/src-provided/worms/programs/ParseOutcome.java
Executable 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));
|
||||
}
|
||||
}
|
248
OGP1718-Worms/src-provided/worms/programs/ProgramParser.java
Executable 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<MyExpression, MyStatement, MyProcedure, Program> 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<MyExpression, MyStatement, Task> parser = new ProgramParser<>(factory);
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* Finally, parse a string or file: <code><pre>
|
||||
* ParseOurcome<Program> 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();
|
||||
}
|
||||
}
|
61
OGP1718-Worms/src-provided/worms/programs/SourceLocation.java
Executable 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);
|
||||
}
|
||||
|
||||
}
|
100
OGP1718-Worms/src-provided/worms/programs/SuccessOrFail.java
Executable 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
392
OGP1718-Worms/src-provided/worms/programs/internal/parser/ParserVisitor.java
Executable 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);
|
||||
}
|
||||
|
||||
}
|
200
OGP1718-Worms/src-provided/worms/programs/internal/parser/WormsProgram.g4
Executable 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')+;
|
||||
|
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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
|
@@ -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); }
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
@@ -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);
|
||||
}
|
0
OGP1718-Worms/src-provided/worms/util/ModelException.java
Normal file → Executable file
10
OGP1718-Worms/src-provided/worms/util/MustNotImplementException.java
Executable 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{
|
||||
|
||||
}
|
0
OGP1718-Worms/src/.gitignore
vendored
1061
OGP1718-Worms/src/worms/facade/Facade.java
Normal file
97
OGP1718-Worms/src/worms/model/Bazooka.java
Normal 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;
|
||||
}
|
||||
}
|
80
OGP1718-Worms/src/worms/model/Food.java
Normal 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);
|
||||
}
|
||||
}
|
393
OGP1718-Worms/src/worms/model/GameObject.java
Normal 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
|
||||
|
||||
}
|
12
OGP1718-Worms/src/worms/model/IJumpable.java
Normal 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);
|
||||
}
|
257
OGP1718-Worms/src/worms/model/Program.java
Normal 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;
|
||||
}
|
||||
|
343
OGP1718-Worms/src/worms/model/Projectile.java
Normal 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
|
||||
|
||||
}
|