You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
5.1 KiB
172 lines
5.1 KiB
#!/usr/bin/env bash
|
|
|
|
#set -x
|
|
|
|
# File locations
|
|
datadir="./data"
|
|
battles="$datadir/battle.data"
|
|
settings="$datadir/settings.last.battle"
|
|
results="$datadir/results.last.data"
|
|
training="$datadir/training.scale"
|
|
testing="$datadir/testing.scale"
|
|
model="$datadir/model.data"
|
|
output="$datadir/output.data"
|
|
|
|
# Battle parameters
|
|
rounds=1000
|
|
width=500
|
|
height=500
|
|
robot1="sample.Corners"
|
|
robot2="sample.Fire"
|
|
|
|
# Requires a function because of two points where it is called
|
|
show_help() {
|
|
echo "Generate the data required for SVM classification and show the accuracy"
|
|
echo "of the generated SVM model. If coordinates are provided, one visual battle"
|
|
echo "is shown to support the prediction."
|
|
echo ""
|
|
echo "USAGE: robocode-svm ACTION"
|
|
echo "USAGE: robocode-svm --battle x y [alpha]"
|
|
echo ""
|
|
echo " --battle Shows visual run of the specified battle"
|
|
echo " -g,--generate Just generate the battle data"
|
|
echo " -a,--accuracy Show the accuracy of the SVM model,"
|
|
echo " -c,--clean Delete all the battle data!"
|
|
echo " -h,--help Show this help"
|
|
}
|
|
|
|
# Run the battle wit the specified parameters
|
|
# @param gui --gui|--no-gui
|
|
# @param x the position of the roaming robot on x-axis
|
|
# @param y the position of the roaming robot on y-axis
|
|
# @param alpha the orientation of the gun of the roaming robot (OPTIONAL)
|
|
run_battle() {
|
|
# The x and y parameters are required integers
|
|
regexint='^-?[0-9]+$'
|
|
if ! [[ $2 =~ $regexint && $3 =~ $regexint ]] ; then
|
|
echo "The coordinates of the starting robot must be numeric!"
|
|
exit
|
|
fi
|
|
|
|
# The alpha parameter is optional
|
|
if [[ -z $4 ]] ; then
|
|
alpha=0
|
|
else
|
|
alpha=$4
|
|
fi
|
|
|
|
{ # Write current settings to a file; first robot starts in the middle, othwe one roaming
|
|
echo "#Battle Properties"
|
|
echo "robocode.battleField.width=$width"
|
|
echo "robocode.battleField.height=$height"
|
|
echo "robocode.battle.numRounds=1"
|
|
echo "robocode.battle.gunCoolingRate=0.07"
|
|
echo "robocode.battle.rules.inactivityTime=450"
|
|
echo "robocode.battle.selectedRobots=$robot1,$robot2"
|
|
echo "robocode.battle.initialPositions=($((width/2)),$((height/2)),0),($2,$3,$alpha)"
|
|
} > "$settings"
|
|
|
|
# Transform the gui parameter to format digestable by robocode cmd
|
|
if [[ $1 == "--no-gui" ]] ; then
|
|
gui="-nodisplay"
|
|
else
|
|
printf "The winner is: "
|
|
fi
|
|
|
|
# Run battle without GUI, following the settings file, save the results into file
|
|
robocode "$gui" -battle "$(pwd)/$settings" -results "$(pwd)/$results" > /dev/null
|
|
# Obtain the winner from the results file
|
|
tail -2 < "$results" | awk 'NR==1F {print $2}'
|
|
}
|
|
|
|
# Generate the missing amount of data from running battles
|
|
generate_data() {
|
|
# Prepare the data directory
|
|
mkdir -p "$datadir/"
|
|
touch "$battles"
|
|
|
|
# If the data file has required amount if data
|
|
lines=$(wc -l < "$battles")
|
|
if [[ "$lines" -lt "$rounds" ]] ; then
|
|
# Repeat the battle desired number of times (till the battle data file does not contain $rounds entries
|
|
echo "Generating the data for SVM predition. Depending on the machine, this may take very long time."
|
|
delta=$((rounds - lines))
|
|
for ((i = 1; i <= "$delta"; i++)) ; do
|
|
# Generate input parameters
|
|
number=$RANDOM; let "number %= $width"; x=$number
|
|
number=$RANDOM; let "number %= $height"; y=$number
|
|
number=$RANDOM; let "number %= 360"; alpha=$number
|
|
|
|
winner=$(run_battle --no-gui "$x" "$y" "$alpha")
|
|
if [[ "$winner" == "$robot1" ]] ; then
|
|
winner=1
|
|
else
|
|
winner=2
|
|
fi
|
|
|
|
# Append the result of the battle to the battle data file
|
|
echo "$winner 1:$x 2:$y 3:$alpha" >> "$battles"
|
|
# Print a dot to infrom user tht something is happening
|
|
printf "."
|
|
done
|
|
printf "\nData generation has been successful.\n"
|
|
else
|
|
# This does not happen when called by accuracy
|
|
if [[ "$1" == "--verbose" ]] ; then
|
|
echo "Data have already been generated. Show accuracy or run the battle."
|
|
fi
|
|
fi
|
|
|
|
}
|
|
|
|
# Recalculate and display the accuracy of the SVM
|
|
show_accuracy() {
|
|
# Check if the data have been generated, if not, generate first
|
|
generate_data #quiet
|
|
|
|
# Calculate the lines needed to split the data to 90% and 10%
|
|
tr=$(bc <<< "scale=0; ($rounds * 0.9) / 1");
|
|
te=$(bc <<< "scale=0; ($rounds - $tr) / 1");
|
|
|
|
# Scale the battles to interval <0, 1> and split them to training set and testing set;
|
|
# misuse tee for 'process substituion' and send its stdout do /dev/null
|
|
svm-scale -l 0 -u 1 "$battles" | tee >(head -n "$tr" > "$training") >(tail -n "$te" > "$testing") > /dev/null
|
|
# Train the SVM with the training data
|
|
svm-train -c 10 -g 2 "$training" "$model" > /dev/null
|
|
# Check the accuracy of the testing data against the SVM model made of training data
|
|
svm-predict "$testing" "$model" "$output"
|
|
}
|
|
|
|
|
|
# Iterate over arguments
|
|
while :; do
|
|
case $1 in
|
|
-g|--generate)
|
|
generate_data --verbose
|
|
exit
|
|
;;
|
|
-a|--accuracy)
|
|
show_accuracy
|
|
exit
|
|
;;
|
|
-b|--battle)
|
|
run_battle --gui "$2" "$3" "$4"
|
|
exit
|
|
;;
|
|
-c|--clean)
|
|
rm -rf "$datadir"
|
|
echo "All the SVM data have been deleted."
|
|
exit
|
|
;;
|
|
-h|-\?|--help)
|
|
show_help
|
|
exit
|
|
;;
|
|
*)
|
|
echo "Type \`robocode-svm --help\` for list of supported commands."
|
|
exit
|
|
esac
|
|
# "command" reduces the chance of fatal errors in many shells.
|
|
command shift
|
|
done
|
|
|
|
|