Skip to content

Instantly share code, notes, and snippets.

@qrnik
Created February 28, 2020 17:48
Show Gist options
  • Save qrnik/6b8176f49662aa4ff1fad5844fedb1f3 to your computer and use it in GitHub Desktop.
Save qrnik/6b8176f49662aa4ff1fad5844fedb1f3 to your computer and use it in GitHub Desktop.
Parser for Google HashCode 2020 online qualification round input & output
package main
import (
"fmt"
"github.com/pwamej/parser/library"
"io/ioutil"
"os"
"sort"
"strconv"
"strings"
)
func main() {
if len(os.Args) < 2 {
printerr("Command missing, available commands: 'decode', 'encode'")
os.Exit(1)
}
input, err := ioutil.ReadAll(os.Stdin)
if err != nil {
printerr(fmt.Sprintf("Error while reading stdin: %e", err))
os.Exit(1)
}
cmd := os.Args[1]
switch cmd {
case "decode":
fmt.Print(decodeInput(string(input)))
case "encode":
s, err := encodeOutput(string(input))
if err != nil {
printerr(fmt.Sprintf("Error while parsing stdin: %e", err))
os.Exit(1)
}
fmt.Print(s)
default:
printerr(fmt.Sprintf("Invalid command '%s', available commands: 'decode', 'encode'", cmd))
os.Exit(1)
}
}
func decodeInput(input string) string {
result := new(strings.Builder)
lines := strings.Split(input, "\n")
header := strings.Fields(lines[0])
books := atoi(header[0])
libraryCount := atoi(header[1])
result.WriteString(fmt.Sprintf("B=%d;\n", books))
result.WriteString(fmt.Sprintf("L=%d;\n", libraryCount))
result.WriteString("D=" + header[2] + ";\n")
scores := strings.Split(lines[1], " ")
result.WriteString("scores=[" + strings.Join(scores, ",") + "];\n")
bookCount := make([]int, 0, libraryCount)
signupProcessLength := make([]int, 0, libraryCount)
booksPerDay := make([]int, 0, libraryCount)
hasBook := make([][]bool, libraryCount)
for i := range hasBook {
hasBook[i] = make([]bool, books)
}
for i := 2; i <= 2*libraryCount; i += 2 {
libraryId := (i - 2) / 2
libraryHeader := toIntSlice(lines[i])
bookCount = append(bookCount, libraryHeader[0])
signupProcessLength = append(signupProcessLength, libraryHeader[1])
booksPerDay = append(booksPerDay, libraryHeader[2])
libraryBooks := toSet(toIntSlice(lines[i+1]))
for bookId := range hasBook[libraryId] {
hasBook[libraryId][bookId] = contains(libraryBooks, bookId)
}
}
result.WriteString("book_count=" + intSliceToString(bookCount) + ";\n")
result.WriteString("signup_process_length=" + intSliceToString(signupProcessLength) + ";\n")
result.WriteString("books_per_day=" + intSliceToString(booksPerDay) + ";\n")
result.WriteString("has_book=" + boolMatrixToString(hasBook) + ";\n")
return result.String()
}
func encodeOutput(rawModelOutput string) (string, error) {
libraries, err := library.Parse(rawModelOutput)
if err != nil {
return "", err
}
sort.Sort(BySignupDay(libraries))
for _, l := range libraries {
sort.Sort(ByScanDay(l.ScannedBooks))
}
result := new(strings.Builder)
result.WriteString(fmt.Sprintf("%d\n", len(libraries)))
for _, l := range libraries {
result.WriteString(fmt.Sprintf("%d %d\n", l.Id, len(l.ScannedBooks)))
bookIds := make([]int, len(l.ScannedBooks))
for i, v := range l.ScannedBooks {
bookIds[i] = v.Id
}
result.WriteString(strings.Trim(fmt.Sprint(bookIds), "[]") + "\n")
}
return result.String(), nil
}
type BySignupDay []*library.Library
func (a BySignupDay) Len() int {
return len(a)
}
func (a BySignupDay) Less(i, j int) bool {
return a[i].SignupDay < a[j].SignupDay
}
func (a BySignupDay) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
type ByScanDay []library.Book
func (a ByScanDay) Len() int {
return len(a)
}
func (a ByScanDay) Less(i, j int) bool {
return a[i].ScanDay < a[j].ScanDay
}
func (a ByScanDay) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func boolMatrixToString(m [][]bool) string {
result := new(strings.Builder)
result.WriteString("[")
for _, a := range m {
result.WriteString("|" + boolSliceToString(a))
}
result.WriteString("|]")
return result.String()
}
func boolSliceToString(a []bool) string {
return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(a)), ","), "[]")
}
func intSliceToString(a []int) string {
return strings.Join(strings.Fields(fmt.Sprint(a)), ",")
}
func toSet(s []int) map[int]struct{} {
set := make(map[int]struct{})
for _, v := range s {
set[v] = struct{}{}
}
return set
}
func contains(set map[int]struct{}, v int) bool {
_, ok := set[v]
return ok
}
func toIntSlice(s string) []int {
fields := strings.Fields(s)
ints := make([]int, len(fields))
for i, v := range fields {
ints[i] = atoi(v)
}
return ints
}
func atoi(s string) int {
i, _ := strconv.Atoi(s)
return i
}
func printerr(s string) {
_, err := fmt.Fprintln(os.Stderr, s)
if err != nil {
panic("Error when writing to stderr")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment