140 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/csv"
 | 
						|
	"fmt"
 | 
						|
	rand "math/rand/v2"
 | 
						|
	"os"
 | 
						|
	"strconv"
 | 
						|
	// "strings"
 | 
						|
)
 | 
						|
 | 
						|
/* Structs */
 | 
						|
type State struct {
 | 
						|
	Name                       string
 | 
						|
	Votes                      int
 | 
						|
	VictoriousPartyPerElection map[string]string
 | 
						|
}
 | 
						|
 | 
						|
type VotesForEachParty struct {
 | 
						|
	Democrats   int
 | 
						|
	Republicans int
 | 
						|
}
 | 
						|
 | 
						|
type src = *rand.Rand
 | 
						|
 | 
						|
/* Globals */
 | 
						|
var r = rand.New(rand.NewPCG(uint64(1), uint64(2)))
 | 
						|
 | 
						|
/* Load data from csvs */
 | 
						|
func readStates() ([]State, error) {
 | 
						|
	var states map[string]State = make(map[string]State)
 | 
						|
 | 
						|
	/* Electoral college votes for the 2024 election*/
 | 
						|
	votes_file, err := os.Open("data/electoral-college-votes.csv")
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error opening the votes file: %v", err)
 | 
						|
	}
 | 
						|
	defer votes_file.Close()
 | 
						|
 | 
						|
	votes_reader := csv.NewReader(votes_file)
 | 
						|
	if _, err := votes_reader.Read(); err != nil { // Skip header
 | 
						|
		return nil, fmt.Errorf("error reading votes header: %v", err)
 | 
						|
	}
 | 
						|
	for {
 | 
						|
		csv_record, err := votes_reader.Read()
 | 
						|
		if err != nil {
 | 
						|
			break // EOF or an error
 | 
						|
		}
 | 
						|
		votes, err := strconv.Atoi(csv_record[1])
 | 
						|
		if err != nil {
 | 
						|
			continue // Error in converting votes, skip this record
 | 
						|
		}
 | 
						|
		state := csv_record[0]
 | 
						|
		if _, exists := states[state]; !exists {
 | 
						|
			states[state] = State{Name: state, Votes: votes, VictoriousPartyPerElection: make(map[string]string)}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Election results */
 | 
						|
	var years = []string{"2000", "2004", "2008", "2012", "2016", "2020"}
 | 
						|
	for _, year := range years {
 | 
						|
		results_filename := fmt.Sprintf("data/results/%s.csv", year)
 | 
						|
		results_file, err := os.Open(results_filename)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("error opening the results file for %s: %v", year, err)
 | 
						|
		}
 | 
						|
		defer results_file.Close()
 | 
						|
		resultsReader := csv.NewReader(results_file)
 | 
						|
		if _, err := resultsReader.Read(); err != nil { // Skip header
 | 
						|
			return nil, fmt.Errorf("error reading results header for %s: %v", year, err)
 | 
						|
		}
 | 
						|
		for {
 | 
						|
			record, err := resultsReader.Read()
 | 
						|
			if err != nil {
 | 
						|
				break // EOF or an error
 | 
						|
			}
 | 
						|
			state, party := record[0], record[1]
 | 
						|
			data, exists := states[state]
 | 
						|
			if !exists {
 | 
						|
				continue // State not found in votes map, skip
 | 
						|
			}
 | 
						|
			// Update the party winning in the specific year
 | 
						|
			data.VictoriousPartyPerElection[year] = party
 | 
						|
			states[state] = data
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Convert statesData map to a slice for returning
 | 
						|
	var states_slice []State
 | 
						|
	for _, state := range states {
 | 
						|
		states_slice = append(states_slice, state)
 | 
						|
	}
 | 
						|
 | 
						|
	return states_slice, nil
 | 
						|
}
 | 
						|
 | 
						|
func sampleFromState(state State) VotesForEachParty {
 | 
						|
	switch state.Name {
 | 
						|
	case "Nebraska":
 | 
						|
		return VotesForEachParty{Democrats: 1, Republicans: 0}
 | 
						|
	case "Maine":
 | 
						|
		return VotesForEachParty{Democrats: 1, Republicans: 0}
 | 
						|
	default:
 | 
						|
		{
 | 
						|
			p_republican := 0.0
 | 
						|
			for _, party := range state.VictoriousPartyPerElection {
 | 
						|
				if party == "R" {
 | 
						|
					p_republican++
 | 
						|
				}
 | 
						|
			}
 | 
						|
			p_republican = p_republican / float64(len(state.VictoriousPartyPerElection))
 | 
						|
			if r.Float64() < p_republican {
 | 
						|
				return VotesForEachParty{Democrats: 0, Republicans: state.Votes}
 | 
						|
			} else {
 | 
						|
				return VotesForEachParty{Democrats: state.Votes, Republicans: 0}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func main() {
 | 
						|
	states, err := readStates()
 | 
						|
	if err != nil {
 | 
						|
		fmt.Println("Error:", err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	for _, state := range states {
 | 
						|
		fmt.Printf("%s: Votes: %d,\n\tWinners: ", state.Name, state.Votes)
 | 
						|
		for year, party := range state.VictoriousPartyPerElection {
 | 
						|
			fmt.Printf("[%s: %s] ", year, party)
 | 
						|
		}
 | 
						|
		election_sample := sampleFromState(state)
 | 
						|
		fmt.Printf("\n\tSample: Democrat seats: %d, Republican seats: %d", election_sample.Democrats, election_sample.Republicans)
 | 
						|
		fmt.Println()
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
}
 |