d04.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package main
  2. import "strings"
  3. import "strconv"
  4. import "bufio"
  5. import "sort"
  6. import "fmt"
  7. import "os"
  8. type KeyValue struct {
  9. Key rune
  10. Value int
  11. }
  12. type KeyValues []KeyValue
  13. func (this KeyValues) Len() int {
  14. return len(this)
  15. }
  16. func (this KeyValues) Swap(i, j int) {
  17. tmp := this[i]
  18. this[i] = this[j]
  19. this[j] = tmp
  20. }
  21. func (this KeyValues) Less(i, j int) bool {
  22. if this[i].Value == this[j].Value {
  23. return this[i].Key > this[j].Key
  24. }
  25. return this[i].Value < this[j].Value
  26. }
  27. type Room struct {
  28. EncryptedName string
  29. DecryptedName string
  30. Checksum string
  31. RoomId int
  32. }
  33. func shiftRune(r rune, shift int) string {
  34. if r == '-' {
  35. return " "
  36. }
  37. res := int(r) +shift
  38. if res > 'z' {
  39. res = res - 'z' + 'a' -1
  40. }
  41. return string(res)
  42. }
  43. func NewRoom(roomName string, sectorId int) Room {
  44. var result Room
  45. letters := make(map[rune]int)
  46. letterShift := sectorId %26
  47. result.EncryptedName = roomName
  48. for _, l := range(roomName) {
  49. if (l != '-') {
  50. letters[l] ++
  51. }
  52. result.DecryptedName += shiftRune(l, letterShift)
  53. }
  54. sortedLetters := make(KeyValues, len(letters))
  55. i := 0
  56. for k, v := range letters {
  57. sortedLetters[i] = KeyValue{k, v}
  58. i++
  59. }
  60. sort.Sort(sort.Reverse(sortedLetters))
  61. for i =0; i < 5; i++ {
  62. result.Checksum += string(sortedLetters[i].Key)
  63. }
  64. result.RoomId = sectorId
  65. return result
  66. }
  67. func (this Room) isValid(checksum string) bool {
  68. return this.Checksum == checksum
  69. }
  70. func parseLine(line string) (Room, string) {
  71. words := strings.FieldsFunc(line, func(r rune) bool {
  72. return (r == '-' || r == '[' || r == ']')
  73. })
  74. checkSum := words[len(words) -1]
  75. sectorId, _ := strconv.Atoi(words[len(words) -2])
  76. words = words[:len(words) -2]
  77. var roomName string
  78. first := true
  79. for word := range(words) {
  80. if (first) {
  81. first = false
  82. } else {
  83. roomName += "-"
  84. }
  85. roomName += words[word]
  86. }
  87. return NewRoom(roomName, sectorId), checkSum
  88. }
  89. func main() {
  90. reader := bufio.NewReader(os.Stdin)
  91. valid := 0
  92. for true {
  93. line, _, err := reader.ReadLine()
  94. if string(line) != "" {
  95. room, checkSum := parseLine(string(line))
  96. if room.isValid(checkSum) {
  97. valid += room.RoomId
  98. if strings.Contains(room.DecryptedName, "northpole") {
  99. fmt.Println("Found `North Pole objects` secret room: " +strconv.Itoa(room.RoomId))
  100. }
  101. }
  102. }
  103. if err != nil {
  104. break
  105. }
  106. }
  107. fmt.Println(valid)
  108. }