Skip to content

Instantly share code, notes, and snippets.

@majelbstoat
Created February 25, 2021 14:15
Show Gist options
  • Save majelbstoat/f29ccece5088060c0177bd5db0068d71 to your computer and use it in GitHub Desktop.
Save majelbstoat/f29ccece5088060c0177bd5db0068d71 to your computer and use it in GitHub Desktop.
This code scans a text file and performs some basic manipulations on its contents to unearth amulets,
as defined by Robin Sloan.
Learn more about them at https://text.bargains
USAGE: go run .
Expects a filename called shakespeare.txt in the same directory.
I used a version from the Gutenberg Project, with gratitude:
https://ocw.mit.edu/ans7870/6/6.006/s08/lecturenotes/files/t8.shakespeare.txt
Example results here: https://twitter.com/majelbstoat/status/1364936594445189122
Yes, you could make it more efficient, or do other text manipulations! Why not try? :)
Released under CC0 https://creativecommons.org/publicdomain/zero/1.0/
package main
import (
"bufio"
"crypto/sha256"
"fmt"
"log"
"math"
"os"
"strings"
)
var results int
var longest int
var best map[int][]string
var cache map[string]bool
func main() {
// return
file, err := os.Open("./shakespeare.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
cache = make(map[string]bool)
best = make(map[int][]string)
for i := 4; i <= 10; i++ {
best[i] = make([]string, 0)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
checkCandidate(line, "RAW")
line = strings.Trim(line, " ")
checkCandidate(line, "TRIMMED")
for _, punc := range []string{",", ".", ";", "-"} {
l := strings.ReplaceAll(line, punc, "")
if l != line {
checkCandidate(line, "DEPUNC")
line = l
}
}
words := strings.Split(line, " ")
spaces := len(words) - 1
if spaces > 4 {
// cap the max permutations to 16 so it finishes in a reasonable time.
continue
}
permutations := int(math.Pow(2, float64(spaces)))
for i := 0; i < permutations; i++ {
s := ""
for j := 0; j < spaces; j++ {
o := " "
if hasBit(i, uint(j)) {
o = "\n"
}
s = fmt.Sprintf("%s%s%s", s, words[j], o)
}
s = fmt.Sprintf("%s%s", s, words[spaces])
checkCandidate(s, fmt.Sprintf("LINED %d", i))
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("\nFOUND %d amulets\n", results)
for l, b := range best {
if len(best[l]) > 0 {
fmt.Printf("%d:\n\n", l)
}
for _, o := range b {
fmt.Printf("%s", o)
}
fmt.Printf("\n")
}
}
func checkCandidate(line, munging string) {
h := sha256.New()
h.Write([]byte(line))
candidate := fmt.Sprintf("%x", h.Sum(nil))
if strings.Contains(candidate, "8888") {
if _, ok := cache[line]; ok {
return
}
cache[line] = true
max := 0
consecutive := 0
for _, c := range candidate {
if c == '8' {
consecutive++
} else {
if consecutive > max {
max = consecutive
}
consecutive = 0
}
}
if consecutive > max {
max = consecutive
}
if max > longest {
longest = max
}
output := fmt.Sprintf("%s: (%8s) \"%s\"\n", candidate, munging, line)
best[max] = append(best[max], output)
results++
}
}
func hasBit(n int, pos uint) bool {
val := n & (1 << pos)
return (val > 0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment