day4.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "regexp"
  8. "strconv"
  9. "strings"
  10. )
  11. func checkByr(line string) int {
  12. if strings.Contains(line, "byr:") {
  13. re := regexp.MustCompile(`byr:(\d{4})`)
  14. result := re.FindStringSubmatch(line)
  15. if len(result) != 2 {
  16. return 0
  17. }
  18. byrString := result[1]
  19. if byrString == "" {
  20. return 0
  21. }
  22. byr, err := strconv.ParseInt(byrString, 10, 32)
  23. if err != nil {
  24. return 0
  25. }
  26. if byr >= 1920 && byr <= 2002 {
  27. return 1
  28. }
  29. }
  30. return 0
  31. }
  32. func checkIyr(line string) int {
  33. if strings.Contains(line, "iyr:") {
  34. re := regexp.MustCompile(`iyr:(\d{4})`)
  35. result := re.FindStringSubmatch(line)
  36. if len(result) != 2 {
  37. return 0
  38. }
  39. iyrString := result[1]
  40. if iyrString == "" {
  41. return 0
  42. }
  43. iyr, err := strconv.ParseInt(iyrString, 10, 32)
  44. if err != nil {
  45. return 0
  46. }
  47. if iyr >= 2010 && iyr <= 2020 {
  48. return 1
  49. }
  50. }
  51. return 0
  52. }
  53. func checkEyr(line string) int {
  54. if strings.Contains(line, "eyr:") {
  55. re := regexp.MustCompile(`eyr:(\d{4})`)
  56. result := re.FindStringSubmatch(line)
  57. if len(result) != 2 {
  58. return 0
  59. }
  60. eyrString := result[1]
  61. if eyrString == "" {
  62. return 0
  63. }
  64. eyr, err := strconv.ParseInt(eyrString, 10, 32)
  65. if err != nil {
  66. return 0
  67. }
  68. if eyr >= 2020 && eyr <= 2030 {
  69. return 1
  70. }
  71. }
  72. return 0
  73. }
  74. func checkHgt(line string) int {
  75. if strings.Contains(line, "hgt:") {
  76. re := regexp.MustCompile(`hgt:(\d+)(\w{2})`)
  77. result := re.FindStringSubmatch(line)
  78. if len(result) != 3 {
  79. return 0
  80. }
  81. hgtString := result[1]
  82. if hgtString == "" {
  83. return 0
  84. }
  85. tp := result[2]
  86. if tp == "" {
  87. return 0
  88. }
  89. hgt, err := strconv.ParseInt(hgtString, 10, 32)
  90. if err != nil {
  91. return 0
  92. }
  93. switch tp {
  94. case "cm":
  95. if hgt >= 150 && hgt <= 193 {
  96. return 1
  97. }
  98. case "in":
  99. if hgt >= 59 && hgt <= 76 {
  100. return 1
  101. }
  102. }
  103. }
  104. return 0
  105. }
  106. func checkHcl(line string) int {
  107. if strings.Contains(line, "hcl:#") {
  108. re := regexp.MustCompile(`hcl:#([0-9a-f]{6})`)
  109. result := re.FindStringSubmatch(line)
  110. if len(result) != 2 {
  111. return 0
  112. }
  113. hcl := result[1]
  114. if hcl != "" {
  115. return 1
  116. }
  117. }
  118. return 0
  119. }
  120. var eyeColors = []string{"amb", "blu", "brn", "gry", "grn", "hzl", "oth"}
  121. func checkEcl(line string) int {
  122. if strings.Contains(line, "ecl:") {
  123. re := regexp.MustCompile(`ecl:(\w{3})`)
  124. result := re.FindStringSubmatch(line)
  125. if len(result) != 2 {
  126. return 0
  127. }
  128. ecl := result[1]
  129. if ecl == "" {
  130. return 0
  131. }
  132. for _, color := range eyeColors {
  133. if color == ecl {
  134. return 1
  135. }
  136. }
  137. }
  138. return 0
  139. }
  140. func checkPid(line string) int {
  141. if strings.Contains(line, "pid:") {
  142. re := regexp.MustCompile(`pid:(\d+)`)
  143. result := re.FindStringSubmatch(line)
  144. if len(result) != 2 {
  145. return 0
  146. }
  147. pid := result[1]
  148. if pid == "" {
  149. return 0
  150. }
  151. if len(pid) != 9 {
  152. return 0
  153. }
  154. _, err := strconv.ParseInt(pid, 10, 32)
  155. if err == nil {
  156. return 1
  157. }
  158. }
  159. return 0
  160. }
  161. func getChecks() map[string]func(string) int {
  162. toCheck := make(map[string]func(string) int)
  163. toCheck["byr:"] = checkByr
  164. toCheck["iyr:"] = checkIyr
  165. toCheck["eyr:"] = checkEyr
  166. toCheck["hgt:"] = checkHgt
  167. toCheck["hcl:"] = checkHcl
  168. toCheck["ecl:"] = checkEcl
  169. toCheck["pid:"] = checkPid
  170. return toCheck
  171. }
  172. func performCheck(line string, name string, check func(string) int) (int, int) {
  173. check1 := 0
  174. check2 := 0
  175. if strings.Contains(line, name) {
  176. check1 = 1
  177. check2 = check(line)
  178. }
  179. return check1, check2
  180. }
  181. func checkLine(line string, toCheck map[string]func(string) int) (int, int) {
  182. checks1 := 0
  183. checks2 := 0
  184. for name, check := range toCheck {
  185. check1, check2 := performCheck(line, name, check)
  186. checks1 += check1
  187. checks2 += check2
  188. }
  189. return checks1, checks2
  190. }
  191. func countChecks(line string, toCheck map[string]func(string) int, valid1 *int, valid2 *int) {
  192. check1, check2 := checkLine(line, toCheck)
  193. if check1 == 7 {
  194. *valid1++
  195. }
  196. if check2 == 7 {
  197. *valid2++
  198. }
  199. }
  200. func main() {
  201. if len(os.Args) < 2 {
  202. log.Fatal("You need to specify a file!")
  203. }
  204. file, err := os.Open(os.Args[1])
  205. if err != nil {
  206. log.Fatalf("failed to open")
  207. }
  208. var (
  209. valid1, valid2 int
  210. text string
  211. )
  212. toCheck := getChecks()
  213. scanner := bufio.NewScanner(file)
  214. for scanner.Scan() {
  215. line := scanner.Text()
  216. if line == "" {
  217. countChecks(text, toCheck, &valid1, &valid2)
  218. text = ""
  219. continue
  220. }
  221. text += line + " "
  222. }
  223. if err := scanner.Err(); err != nil {
  224. log.Println(err)
  225. }
  226. countChecks(text, toCheck, &valid1, &valid2)
  227. fmt.Println("Part1: ", valid1)
  228. fmt.Println("Part2: ", valid2)
  229. }