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 Polls []Poll } type VotesForEachParty struct { Democrats int Republicans int } type Poll struct { PollId string SampleSize int PollResults map[string]float64 } // type src = *rand.Rand /* Globals */ var r = rand.New(rand.NewPCG(uint64(100), uint64(2224))) /* 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") // votes_file, err := os.Open("data/electoral-college-votes-2010-census.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) } 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 } results_file.Close() } /* Read polls */ polls_file, err := os.Open("data/polls/president_polls_state.csv") // Make sure to update this path if err != nil { return nil, fmt.Errorf("error opening the polls file: %v", err) } defer polls_file.Close() // Using a temporary map to group poll results by state and poll ID tmp_polls := make(map[string]map[string]Poll) polls_reader := csv.NewReader(polls_file) _, err = polls_reader.Read() // Skip the header if err != nil { return nil, fmt.Errorf("error reading polls header: %v", err) } for { record, err := polls_reader.Read() if err != nil { break // EOF or an error } state_name := record[12] // fmt.Printf("State: %s", state_name) poll_id := record[0] sampleSize, err := strconv.Atoi(record[22]) if err != nil { continue // If error, skip this record } candidateName := record[44] pct, err := strconv.ParseFloat(record[47], 64) // pct is in the 42nd column if err != nil { fmt.Printf("Error parsing percentage") continue // If error, skip this record } if _, exists := tmp_polls[state_name]; !exists { tmp_polls[state_name] = make(map[string]Poll) } poll, exists := tmp_polls[state_name][poll_id] if !exists { poll = Poll{ PollId: poll_id, SampleSize: sampleSize, PollResults: make(map[string]float64), } } poll.PollResults[candidateName] = pct tmp_polls[state_name][poll_id] = poll } // Add the aggregated poll data to the respective states for state_name, polls := range tmp_polls { var pollsSlice []Poll for _, poll := range polls { pollsSlice = append(pollsSlice, poll) } if state, exists := states[state_name]; exists { state.Polls = pollsSlice states[state_name] = state // Not redundant } else { // fmt.Printf("Encountered new state: %s\n", state_name) /* states[state_name] = State{ Name: state_name, Polls: pollsSlice, } */ } } // 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 { fmt.Printf("%s\n\n", state) switch state.Name { case "Nebraska": // 2000: R // 2004: R // 2008: Split, 1 D, 4 R // 2012: R // 2016: R // 2020: Split, 1 D, 4 R p_split := 2.0 / 6.0 if r.Float64() < p_split { return VotesForEachParty{Democrats: 1, Republicans: 4} } else { return VotesForEachParty{Democrats: 0, Republicans: 5} } case "Maine": // 2000: D // 2004: D // 2008: D // 2012: D // 2016: Split: 3 D, 1 R // 2020: Split, 3 D, 1 R p_split := 2.0 / 6.0 if r.Float64() < p_split { return VotesForEachParty{Democrats: 3, Republicans: 1} } else { 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 simulateElection(states []State) int { republican_seats := 0 for _, state := range states { // fmt.Printf("%s\n", state) election_sample := sampleFromState(state) republican_seats += election_sample.Republicans /* fmt.Printf("%s: Votes: %d,\n\tWinners: ", state.Name, state.Votes) for year, party := range state.VictoriousPartyPerElection { fmt.Printf("[%s: %s] ", year, party) } fmt.Printf("\n\tSample: Democrat seats: %d, Republican seats: %d", election_sample.Democrats, election_sample.Republicans) fmt.Println() */ } // fmt.Printf("\nDemocrat seats: %d\n", republican_seats) fmt.Printf(" (%d) ", republican_seats) if republican_seats >= 270 { return 1 } else { return 0 } } func main() { states, err := readStates() if err != nil { fmt.Println("Error:", err) return } n_sims := 1 p_republicans := 0.0 for i := 0; i < n_sims; i++ { result := simulateElection(states) fmt.Printf("Election result: %d\n", result) if result == 1 { p_republicans++ } } p_republicans = p_republicans / float64(n_sims) fmt.Printf("%% republicans: %f\n", p_republicans) }