initial commit

This commit is contained in:
mappu 2025-05-03 12:39:16 +12:00
commit 30fe2ec951
9 changed files with 270 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
sortvote
sortvote.exe

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# sortvote
Interactively sort a textfile with pairwise ranking.
Mostly useful for ranking your favourite Eurovision songs. Made with MIQT.
Usage: `./sortvote file.txt`
Any blank lines, or lines with leading `#` characters are skipped from sorting.

39
entries_esc2025.txt Normal file
View File

@ -0,0 +1,39 @@
# Eurovision Song Contest 2025 entrants
🇦🇱 Albania - Shkodra Elektronike - Zjerm
🇦🇲 Armenia - Parg - Survivor
🇦🇹 Austria - JJ - Wasted Love
🇦🇺 Australia - Go-Jo - Milkshake Man
🇦🇿 Azerbaijan - Mamagama - Run with U
🇧🇪 Belgium - Red Sebastian - Strobe Lights
🇨🇭 Switzerland - Zoë Më - Voyage
🇨🇾 Cyprus - Theo Evan - Shh
🇨🇿 Czechia - Adonxs - Kiss Kiss Goodbye
🇩🇪 Germany - Abor & Tynna - Baller
🇩🇰 Denmark - Sissal - Hallucination
🇪🇪 Estonia - Tommy Cash - Espresso Macchiato
🇪🇸 Spain - Melody - Esa diva
🇫🇮 Finland - Erika Vikman - Ich komme
🇫🇷 France - Louane - Maman
🇬🇧 United Kingdom - Remember Monday - What the Hell Just Happened
🇬🇪 Georgia - Mariam Shengelia - Freedom
🇬🇷 Greece - Klavdia - Asteromata
🇭🇷 Croatia - Marko Bošnjak - Poison Cake
🇮🇪 Ireland - Emmy - Laika Party
🇮🇱 Israel - Yuval Raphael - New Day Will Rise
🇮🇸 Iceland - Væb - Róa
🇮🇹 Italy - Lucio Corsi - Volevo essere un duro
🇱🇹 Lithuania - Katarsis - Tavo akys
🇱🇺 Luxembourg - Laura Thorn - La poupée monte le son
🇱🇻 Latvia - Tautumeitas - Bur man laimi
🇲🇪 Montenegro - Nina Žižić - Dobrodošli
🇲🇹 Malta - Miriana Conte - Serving
🇳🇱 Netherlands - Claude - C'est la vie
🇳🇴 Norway - Kyle Alessandro - Lighter
🇵🇱 Poland - Justyna Steczkowska - Gaja
🇵🇹 Portugal - Napa - Deslocado
🇷🇸 Serbia - Princ - Mila
🇸🇪 Sweden - KAJ - Bara bada bastu
🇸🇮 Slovenia - Klemen - How Much Time - Do We Have Left
🇸🇲 San Marino - Gabry Ponte - Tutta l'Italia
🇺🇦 Ukraine - Ziferblat - Bird of Pray

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module sortvote
go 1.19
require github.com/mappu/miqt v0.10.0

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/mappu/miqt v0.10.0 h1:w+ucRwdoIO7xS32us34lL2Mh0+aarywNpQz6c76ZSDY=
github.com/mappu/miqt v0.10.0/go.mod h1:xFg7ADaO1QSkmXPsPODoKe/bydJpRG9fgCYyIDl/h1U=

100
main.go Normal file
View File

@ -0,0 +1,100 @@
package main
import (
"fmt"
"math/rand"
"os"
"sort"
"strings"
qt "github.com/mappu/miqt/qt6"
"github.com/mappu/miqt/qt6/mainthread"
)
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)))
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.Show()
comparisons := 0
go func() {
sort.SliceStable(entries, func(i, j int) bool {
mainthread.Wait(func() {
comparisons++
ui.infoArea.AddItem(fmt.Sprintf("Comparison #%d", comparisons))
ui.infoArea.ScrollToBottom()
// Escape & used as an alt-accelerator
ui.b1.SetText(strings.ReplaceAll(entries[i], `&`, `&&`))
ui.b2.SetText(strings.ReplaceAll(entries[j], `&`, `&&`))
})
return <-ret
})
mainthread.Start(func() {
ui.b1.SetEnabled(false)
ui.b2.SetEnabled(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()
}

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

59
window.go Normal file
View File

@ -0,0 +1,59 @@
// Generated by miqt-uic. To update this file, edit the .ui file in
// Qt Designer, and then run 'go generate'.
//
//go:generate miqt-uic -InFile window.ui -OutFile window.go -Qt6
package main
import (
qt "github.com/mappu/miqt/qt6"
)
type MainWindowUi struct {
MainWindow *qt.QMainWindow
centralwidget *qt.QWidget
verticalLayout *qt.QVBoxLayout
infoArea *qt.QListWidget
b1 *qt.QPushButton
b2 *qt.QPushButton
}
// NewMainWindowUi creates all Qt widget classes for MainWindow.
func NewMainWindowUi() *MainWindowUi {
ui := &MainWindowUi{}
ui.MainWindow = qt.NewQMainWindow(nil)
ui.MainWindow.Resize(320, 415)
ui.MainWindow.SetWindowTitle("SortVote")
ui.centralwidget = qt.NewQWidget(ui.MainWindow.QWidget)
ui.verticalLayout = qt.NewQVBoxLayout(ui.centralwidget)
ui.verticalLayout.SetContentsMargins(11, 11, 11, 11)
ui.verticalLayout.SetSpacing(6)
ui.infoArea = qt.NewQListWidget(ui.centralwidget)
/* miqt-uic: no handler for infoArea property 'sizePolicy' */
ui.verticalLayout.AddWidget(ui.infoArea.QWidget)
ui.b1 = qt.NewQPushButton(ui.centralwidget)
/* miqt-uic: no handler for b1 property 'sizePolicy' */
ui.verticalLayout.AddWidget(ui.b1.QWidget)
ui.b2 = qt.NewQPushButton(ui.centralwidget)
/* miqt-uic: no handler for b2 property 'sizePolicy' */
ui.verticalLayout.AddWidget(ui.b2.QWidget)
ui.MainWindow.SetCentralWidget(ui.centralwidget) // Set central widget
ui.Retranslate()
return ui
}
// Retranslate reapplies all text translations.
func (ui *MainWindowUi) Retranslate() {
}

53
window.ui Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>415</height>
</rect>
</property>
<property name="windowTitle">
<string>SortVote</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="infoArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>