A script to demonstrate Support Vector Machine (SVM) classification on outcomes of the battles of Robocode.
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.
robocode-svm/robocode-svm

173 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"
9 years ago
model="$datadir/model.data"
output="$datadir/output.data"
# Battle parameters
9 years ago
rounds=1000
width=500
height=500
robot1="sample.Corners"
robot2="sample.Fire"
9 years ago
9 years ago
# 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 supported, 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"
9 years ago
}
# 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
cat "$results" | tail -2 | awk 'NR==1F {print $2}'
}
9 years ago
# Generate the missing amount of data from running battles
generate_data() {
# Prepare the data directory
mkdir -p "$datadir/"
touch "$battles"
9 years ago
# If the data file has required amount if data
lines=$(wc -l < "$battles")
if [[ "$lines" -lt "$rounds" ]] ; then
9 years ago
# 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
9 years ago
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"
9 years ago
# 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
9 years ago
echo "Data have already been generated. Show accuracy or run the battle."
fi
fi
9 years ago
}
# 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
9 years ago
# Train the SVM with the training data
svm-train -c 10 -g 2 "$training" "$model" > /dev/null
9 years ago
# Check the accuracy of the testing data against the SVM model made of training data
svm-predict "$testing" "$model" "$output"
9 years ago
}
# Iterate over arguments
while :; do
case $1 in
-g|--generate)
generate_data --verbose
9 years ago
exit
;;
-a|--accuracy)
9 years ago
show_accuracy
exit
;;
-b|--battle)
run_battle --gui "$2" "$3" "$4"
exit
;;
-c|--clean)
9 years ago
rm -rf "$datadir"
echo "All the SVM data have been deleted."
exit
;;
-h|-\?|--help)
9 years ago
show_help
exit
;;
*)
echo "Type \`robocode-svm --help\` for list of supported commands."
9 years ago
exit
esac
# "command" reduces the chance of fatal errors in many shells.
command shift
done