Advertisement
Guest User

Untitled

a guest
Dec 4th, 2023
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 2.79 KB | Source Code | 0 0
  1. package day4
  2.  
  3. import (
  4.     "bufio"
  5.     "strings"
  6.     "unicode"
  7. )
  8.  
  9. const (
  10.     StateID int = iota
  11.     StateWinningNumbers
  12.     StateAvailableNumbers
  13.     StateLineEnd
  14. )
  15.  
  16. type (
  17.     Game struct {
  18.         ID        int
  19.         Winning   []int
  20.         Available []int
  21.     }
  22.  
  23.     transition struct {
  24.         state []rune
  25.     }
  26. )
  27.  
  28. func (t *transition) Append(c rune) {
  29.     t.state = append(t.state, c)
  30. }
  31.  
  32. func (t *transition) HasTransitioned(c rune) bool {
  33.     if len(t.state) == 0 {
  34.         return false
  35.     }
  36.  
  37.     lastState := t.state[len(t.state)-1]
  38.  
  39.     // No transition
  40.     if unicode.IsDigit(c) && unicode.IsDigit(lastState) {
  41.         return false
  42.     }
  43.  
  44.     // No transition
  45.     if c == ' ' && lastState == ' ' {
  46.         return false
  47.     }
  48.  
  49.     return true
  50. }
  51.  
  52. func (t *transition) Reset() {
  53.     t.state = make([]rune, 0)
  54. }
  55.  
  56. func (g *Game) SetID(c rune) {
  57.     g.ID = g.ID*10 + int(c-'0')
  58. }
  59.  
  60. func (g *Game) SetWinning(c rune, index int) {
  61.     if len(g.Winning) <= index {
  62.         g.Winning = append(g.Winning, int(c-'0'))
  63.     } else {
  64.         g.Winning[index] = g.Winning[index]*10 + int(c-'0')
  65.     }
  66. }
  67.  
  68. func (g *Game) SetAvailable(c rune, index int) {
  69.     if len(g.Available) <= index {
  70.         g.Available = append(g.Available, int(c-'0'))
  71.     } else {
  72.         g.Available[index] = g.Available[index]*10 + int(c-'0')
  73.     }
  74. }
  75.  
  76. func New(input string) []Game {
  77.     // Parsing solution implemented using a Finite State Machine
  78.     lines := strings.Count(input, "\n")
  79.     reader := strings.NewReader(input)
  80.     scanner := bufio.NewScanner(reader)
  81.     scanner.Split(bufio.ScanRunes)
  82.  
  83.     // Initial state
  84.     games := make([]Game, lines+1)
  85.     lineCounter := 0
  86.     winningTransition := transition{}
  87.     availableTransition := transition{}
  88.     winningCounter := 0
  89.     availableCounter := 0
  90.     state := StateID
  91.  
  92.     for scanner.Scan() {
  93.         c := rune(scanner.Bytes()[0])
  94.         switch state {
  95.         case StateID:
  96.             if c == ':' {
  97.                 state = StateWinningNumbers
  98.                 continue
  99.             }
  100.  
  101.             if unicode.IsDigit(c) {
  102.                 games[lineCounter].SetID(c)
  103.             }
  104.         case StateWinningNumbers:
  105.             if c == ' ' && winningTransition.HasTransitioned(c) {
  106.                 winningCounter++
  107.                 winningTransition.Append(c)
  108.                 continue
  109.             }
  110.  
  111.             if c == '|' {
  112.                 state = StateAvailableNumbers
  113.                 continue
  114.             }
  115.  
  116.             if unicode.IsDigit(c) {
  117.                 games[lineCounter].SetWinning(c, winningCounter)
  118.             }
  119.  
  120.             winningTransition.Append(c)
  121.         case StateAvailableNumbers:
  122.             if c == ' ' && availableTransition.HasTransitioned(c) {
  123.                 availableCounter++
  124.                 availableTransition.Append(c)
  125.                 continue
  126.             }
  127.  
  128.             if c == '\n' {
  129.                 state = StateLineEnd
  130.                 continue
  131.             }
  132.  
  133.             if unicode.IsDigit(c) {
  134.                 games[lineCounter].SetAvailable(c, availableCounter)
  135.             }
  136.  
  137.             availableTransition.Append(c)
  138.         case StateLineEnd:
  139.             lineCounter++
  140.             winningCounter = 0
  141.             availableCounter = 0
  142.             winningTransition.Reset()
  143.             availableTransition.Reset()
  144.             state = StateID
  145.         }
  146.     }
  147.  
  148.     return games
  149. }
  150.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement