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"
9 years ago
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"
9 years ago
}
# Run the battle wit the specified parameters
9 years ago
# @param gui --gui|--no-gui
9 years ago
# @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
9 years ago
# 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
9 years ago
tail -2 < "$results" | 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