#!/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