sortvote/main.go

145 lines
3.0 KiB
Go

package main
import (
"fmt"
"math/rand"
"os"
"sort"
"strings"
qt "github.com/mappu/miqt/qt6"
"github.com/mappu/miqt/qt6/mainthread"
)
func formatButtonText(s string) string {
// Escape & used as an alt-accelerator
s = strings.ReplaceAll(s, `&`, `&&`)
// Replace " - " with newlines
s = strings.ReplaceAll(s, ` - `, "\n")
return s
}
func main() {
qt.NewQApplication(os.Args)
appName := "SortVote"
qt.QCoreApplication_SetApplicationName(appName)
if len(os.Args) < 2 {
qt.QMessageBox_Critical(nil, appName, "Usage: ./sortvote filename.txt")
os.Exit(1)
}
b, err := os.ReadFile(os.Args[1])
if err != nil {
qt.QMessageBox_Critical(nil, appName, fmt.Sprintf("Error reading file %q: %s", os.Args[1], err.Error()))
os.Exit(1)
}
file_lines := strings.Split(string(b), "\n")
entries := make([]string, 0, len(file_lines))
for _, line := range file_lines {
if len(line) > 0 && line[0] != '#' {
entries = append(entries, line)
}
}
// Start with a randomized order for fairness
for i := range entries {
j := rand.Intn(i + 1)
entries[i], entries[j] = entries[j], entries[i]
}
//
ui := NewMainWindowUi()
ui.MainWindow.SetWindowTitle(os.Args[1] + " - " + appName)
ui.infoArea.AddItem(fmt.Sprintf("Sorting %d entries", len(entries)))
ui.infoArea.AddItem("Use [Q] and [Z] to select with the keyboard")
ui.infoArea.ScrollToBottom()
active := true
ret := make(chan bool, 0)
ui.b1.OnClicked(func() { // Set up click handlers only once
ret <- true
})
ui.b2.OnClicked(func() {
ret <- false
})
ui.MainWindow.OnKeyPressEvent(func(super func(event *qt.QKeyEvent), event *qt.QKeyEvent) {
if !active {
super(event)
return
}
keytext := strings.ToLower(event.Text())
if keytext == `q` {
ret <- true
} else if keytext == `z` {
ret <- false
} else { // not our event
super(event)
}
})
ui.MainWindow.Show()
ui.infoArea.SetFocusPolicy(qt.NoFocus) // prevent stealing keyboard input
comparisons := 0
go func() {
sort.SliceStable(entries, func(i, j int) bool {
// Towards the end, sort.SliceStable has the pattern of putting one
// entry in the top button all the time
// Maybe shuffle them
shuf := (rand.Int()%2 == 0)
if shuf {
i, j = j, i
}
mainthread.Wait(func() {
comparisons++
ui.infoArea.AddItem(fmt.Sprintf("Comparison #%d", comparisons))
ui.infoArea.ScrollToBottom()
ui.b1.SetText(formatButtonText(entries[i]))
ui.b2.SetText(formatButtonText(entries[j]))
})
if shuf {
return !<-ret
}
return <-ret
})
active = false
mainthread.Start(func() {
ui.b1.SetVisible(false)
ui.b2.SetVisible(false)
// Sorting 39 entries took 77 comparisons
// Finished sorting 37 entries in 219 comparisons
// 37 x log_2(37) = 192 so we are 15% over(?)
ui.infoArea.AddItem(fmt.Sprintf("Finished sorting %d entries in %d comparisons", len(entries), comparisons))
for i, ent := range entries {
ui.infoArea.AddItem(fmt.Sprintf("%02d. %s", i+1, ent))
ui.infoArea.ScrollToBottom()
}
})
}()
qt.QApplication_Exec()
}