Modified for ties
***
More tie work
7 files changed, 139 insertions(+), 46 deletions(-)

A => input-1.2.csv
A => input-1.3.csv
A => input-1.4.csv
A => input-1.5.csv
M main.go
M tie.csv => tie.1.csv
M tie.csv
A => input-1.2.csv +16 -0
@@ 0,0 1,16 @@ 
+A,B,C
+5,4,0
+4,1,5
+5,4,0
+5,4,0
+0,1,5
+0,1,5
+0,1,5
+5,4,0
+0,1,5
+4,1,5
+5,4,0
+5,4,0
+0,5,2
+0,1,5
+5,4,0

          
A => input-1.3.csv +16 -0
@@ 0,0 1,16 @@ 
+A,B,C
+5,4,0
+4,1,5
+5,4,0
+5,4,0
+0,1,5
+0,1,5
+0,1,5
+5,4,0
+0,1,5
+4,1,5
+5,4,0
+5,4,0
+0,5,3
+0,1,5
+5,4,0

          
A => input-1.4.csv +16 -0
@@ 0,0 1,16 @@ 
+A,B,C
+5,4,0
+4,1,5
+5,4,0
+5,4,0
+0,1,5
+0,1,5
+0,1,5
+5,4,0
+0,1,5
+4,1,5
+5,4,0
+5,4,0
+0,5,4
+0,1,5
+5,4,0

          
A => input-1.5.csv +16 -0
@@ 0,0 1,16 @@ 
+A,B,C
+5,4,0
+4,1,5
+5,4,0
+5,4,0
+0,1,5
+0,1,5
+0,1,5
+5,4,0
+0,1,5
+4,1,5
+5,4,0
+5,4,0
+0,4,5
+0,1,5
+5,4,0

          
M main.go +59 -30
@@ 12,7 12,6 @@ import (
 	"strings"
 )
 
-// FIXME: detect tie
 func main() {
 	/**************************/
 	/* Process the input data */

          
@@ 32,7 31,7 @@ func main() {
 	}
 
 	/*********************/
-	/* The SBB algorithm */
+	/* The MARS algorithm */
 	/*********************/
 
 	// As defined, R is max-min.

          
@@ 50,38 49,26 @@ func main() {
 	ttl := total(ints, diffs)
 	// wc is the index of the final winner
 	wc := max(ttl)
-	// Look for cycles
-	past := make([]int, 0)
-	for {
-		d2 := diff(ints, wc, R)
-		t2 := total(ints, d2)
-		w2 := max(t2)
-		// If the current max is the same as the previous max, then the algorithm has settled
-		// on a winner.
-		if w2 == wc {
-			break
-		}
-		// Check to see if we've seen this winner before (but not immediately before); if so,
-		// then we're looping; dump the cycle list and exit.
-		for _, cand := range past {
-			if w2 == cand {
-				fmt.Print("Cycle found in adjusted scoring ")
-				for _, c := range past {
-					fmt.Printf("%s => ", lines[0][c])
-				}
-				fmt.Printf("%s => ...\n", lines[0][w2])
-				printScoreDetails(w, lines, badVotes, ints, diffs, ttl)
-				return
-			}
-		}
-		// Add the current winner to the "seen before" list
-		past = append(past, w2)
-		// Set the "immediately previous" winner to the current winner for the next loop
-		wc = w2
+	// Look for cycles; if cycle, highest score wints
+	cycle := checkCycle(lines[0], ints, wc, R)
+	if cycle {
+		printScoreDetails(w, lines, badVotes, ints, diffs, ttl)
+		// If there's a tie, then it's a hard tie
+		checkTie(lines[0], subtotal(ints), w)
+		return
 	}
 
 	printScoreDetails(wc, lines, badVotes, ints, diffs, ttl)
 	printAdjustDetails(wc, lines, badVotes, ints, diffs, ttl)
+	// If there's a tie in the adjusted score, use the pure score
+	if checkTie(lines[0], ttl, wc) {
+		// Report if there's a hard tie (both adjusted and pure)
+		if checkTie(lines[0], subtotal(ints), w) {
+			fmt.Println("Hard tie (no winner possible)")
+			return
+		}
+		fmt.Printf("Winner based on pure score: %s\n", lines[0][w])
+	}
 }
 
 // getRange finds the maximum and minimum score values in the entire file.

          
@@ 187,6 174,48 @@ func total(lines [][]int, diffs [][]int)
 	return ttls
 }
 
+func checkTie(header []string, sttl []int, w int) bool {
+	var tie bool
+	for i, c := range sttl {
+		if sttl[w] == c && i != w {
+			fmt.Printf("Tie found between %s and %s\n", header[w], header[i])
+			tie = true
+		}
+	}
+	return tie
+}
+
+func checkCycle(header []string, ints [][]int, wc int, R int) bool {
+	past := make([]int, 0)
+	for {
+		d2 := diff(ints, wc, R)
+		t2 := total(ints, d2)
+		w2 := max(t2)
+		// If the current max is the same as the previous max, then the algorithm has settled
+		// on a winner.
+		if w2 == wc {
+			break
+		}
+		// Check to see if we've seen this winner before (but not immediately before); if so,
+		// then we're looping; dump the cycle list and exit.
+		for _, cand := range past {
+			if w2 == cand {
+				fmt.Print("Cycle found in adjusted scoring ")
+				for _, c := range past {
+					fmt.Printf("%s => ", header[c])
+				}
+				fmt.Printf("%s => ...\n", header[w2])
+				return true
+			}
+		}
+		// Add the current winner to the "seen before" list
+		past = append(past, w2)
+		// Set the "immediately previous" winner to the current winner for the next loop
+		wc = w2
+	}
+	return false
+}
+
 /****************************************************************************************/
 /* The functions below are all utility functions not relevant to the vote calculations; */
 /* they print or convert arrays and values.                                             */

          
M tie.csv => tie.1.csv +8 -8
@@ 1,9 1,9 @@ 
 A,B,C
-5,1,0
-5,1,0
-5,1,0
-5,1,0
-0,1,5
-0,1,5
-0,1,5
-0,1,5
+5,2,0
+5,2,0
+5,2,0
+5,2,0
+0,2,5
+0,2,5
+0,2,5
+0,2,5

          
M tie.csv +8 -8
@@ 1,9 1,9 @@ 
 A,B,C
-5,1,0
-5,1,0
-5,1,0
-5,1,0
-0,1,5
-0,1,5
-0,1,5
-0,1,5
+5,3,0
+5,3,0
+5,3,0
+5,3,0
+0,3,5
+0,3,5
+0,3,5
+0,3,5