github.com/cycloss/advent-of-code@v0.0.0-20221210145555-15039b95faa6/2015/day8.go (about)

     1  package aoc2015
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  )
     7  
     8  type token struct {
     9  	codeCount, charCount, encodedCount int
    10  }
    11  
    12  type tokeniser struct {
    13  	index int
    14  	bytes []byte
    15  }
    16  
    17  func Day8() {
    18  	var bytes, _ = ioutil.ReadFile("inputs/day8.txt")
    19  	var tokeniser = newTokeniser(bytes)
    20  	var tokens = tokeniser.tokeniseBytes()
    21  	var codeTotal, charTotal, encodedTotal = calculateTotal(tokens)
    22  	var res = codeTotal - charTotal
    23  	fmt.Printf("Result: %d\n", res)
    24  	// plus 2 for surrounding quotes
    25  	var encodedDiff = encodedTotal - codeTotal
    26  	fmt.Printf("Encoded diff: %d\n", encodedDiff)
    27  }
    28  
    29  func newTokeniser(b []byte) *tokeniser {
    30  	return &tokeniser{-1, b}
    31  }
    32  
    33  func (t *tokeniser) tokeniseBytes() []*token {
    34  	var tokens = []*token{}
    35  	for t.next() {
    36  		var token = t.getNextToken()
    37  		tokens = append(tokens, token)
    38  	}
    39  	return tokens
    40  }
    41  
    42  func (t *tokeniser) next() bool {
    43  	t.index++
    44  	return t.index < len(t.bytes)
    45  }
    46  
    47  func (t *tokeniser) current() byte {
    48  	return t.bytes[t.index]
    49  }
    50  
    51  const backslash = byte('\\')
    52  const quote = byte('"')
    53  const newline byte = '\n'
    54  
    55  func (t *tokeniser) getNextToken() *token {
    56  
    57  	var current = t.current()
    58  	switch current {
    59  	case newline:
    60  		return &token{}
    61  	case backslash:
    62  		return t.handleEscaped()
    63  	case quote:
    64  		// add 3 as should be surrounding quote
    65  		return &token{codeCount: 1, encodedCount: 3}
    66  	default:
    67  		return &token{charCount: 1, codeCount: 1, encodedCount: 1}
    68  	}
    69  }
    70  
    71  func (t *tokeniser) handleEscaped() *token {
    72  	if !t.next() {
    73  		return &token{charCount: 1, encodedCount: 1, codeCount: 1}
    74  	}
    75  	var current = t.current()
    76  	switch current {
    77  	case backslash:
    78  		// must escape two back slashes
    79  		return &token{codeCount: 2, charCount: 1, encodedCount: 4}
    80  	case quote:
    81  		return &token{codeCount: 2, charCount: 1, encodedCount: 4}
    82  	default:
    83  		// must be hex sequence
    84  		t.index += 2
    85  		return &token{codeCount: 4, charCount: 1, encodedCount: 5}
    86  	}
    87  }
    88  
    89  func calculateTotal(tokens []*token) (int, int, int) {
    90  	var codeTotal, charTotal, encodedTotal int
    91  	for _, token := range tokens {
    92  		codeTotal += token.codeCount
    93  		charTotal += token.charCount
    94  		encodedTotal += token.encodedCount
    95  	}
    96  
    97  	return codeTotal, charTotal, encodedTotal
    98  }