package award import "strings" // wpxPrefix derives the CQ WPX prefix from a callsign. This is an approximation // of the official WPX rules — good enough to count distinct prefixes worked: // - standard call: letters+digits up to and including the LAST digit of the // first group (F4BPO→F4, EA8ABC→EA8, 9A1AA→9A1, OH2BH→OH2) // - no digit: first two letters + "0" (RAEM→RA0) // - portable "A/B": a short alpha(+digit) segment is treated as the prefix // designator; a lone-digit segment replaces the call's digit (F4BPO/9→F9) func wpxPrefix(call string) string { c := strings.ToUpper(strings.TrimSpace(call)) if c == "" { return "" } if strings.Contains(c, "/") { return portablePrefix(c) } return standardPrefix(c) } func portablePrefix(c string) string { parts := strings.Split(c, "/") // Drop pure operating-modifier suffixes. kept := make([]string, 0, len(parts)) for _, p := range parts { switch p { case "P", "M", "MM", "AM", "QRP", "A", "R", "B", "LH": continue } if p != "" { kept = append(kept, p) } } if len(kept) == 0 { kept = parts } // Pick a base = the longest segment (the actual call). base := kept[0] for _, p := range kept[1:] { if len(p) > len(base) { base = p } } for _, p := range kept { if p == base { continue } if isAllDigits(p) { // Lone digit replaces the call's region digit: F4BPO/9 → F9. return replaceLastDigit(standardPrefix(base), p) } if len(p) <= 4 && hasLetter(p) { // Prefix designator wins: VP8/F4BPO → VP8 (+digit if missing). return ensureTrailingDigit(p) } } return standardPrefix(base) } // standardPrefix applies the basic WPX rule to a plain callsign: the prefix is // the call up to and including its last digit (9A1AA→9A1, EA8ABC→EA8). Standard // callsigns carry no digit in the suffix, so "last digit" is the prefix digit. func standardPrefix(c string) string { lastDigit := -1 for i := 0; i < len(c); i++ { if c[i] >= '0' && c[i] <= '9' { lastDigit = i } } if lastDigit < 0 { // No digit at all: first two letters + 0. if len(c) >= 2 { return c[:2] + "0" } return c + "0" } return c[:lastDigit+1] } func ensureTrailingDigit(p string) string { for i := 0; i < len(p); i++ { if p[i] >= '0' && p[i] <= '9' { return p } } return p + "0" } func replaceLastDigit(prefix, digit string) string { for i := len(prefix) - 1; i >= 0; i-- { if prefix[i] >= '0' && prefix[i] <= '9' { return prefix[:i] + digit } } return prefix + digit } func isAllDigits(s string) bool { if s == "" { return false } for i := 0; i < len(s); i++ { if s[i] < '0' || s[i] > '9' { return false } } return true } func hasLetter(s string) bool { for i := 0; i < len(s); i++ { if (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') { return true } } return false }