github.com/vpayno/adventofcode-2022-golang-workspace@v0.0.0-20230605190011-dbafed5593de/reports/coverage.html (about)

     1  
     2  <!DOCTYPE html>
     3  <html>
     4  	<head>
     5  		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     6  		<title>day01: Go Coverage Report</title>
     7  		<style>
     8  			body {
     9  				background: black;
    10  				color: rgb(80, 80, 80);
    11  			}
    12  			body, pre, #legend span {
    13  				font-family: Menlo, monospace;
    14  				font-weight: bold;
    15  			}
    16  			#topbar {
    17  				background: black;
    18  				position: fixed;
    19  				top: 0; left: 0; right: 0;
    20  				height: 42px;
    21  				border-bottom: 1px solid rgb(80, 80, 80);
    22  			}
    23  			#content {
    24  				margin-top: 50px;
    25  			}
    26  			#nav, #legend {
    27  				float: left;
    28  				margin-left: 10px;
    29  			}
    30  			#legend {
    31  				margin-top: 12px;
    32  			}
    33  			#nav {
    34  				margin-top: 10px;
    35  			}
    36  			#legend span {
    37  				margin: 0 5px;
    38  			}
    39  			.cov0 { color: rgb(192, 0, 0) }
    40  .cov1 { color: rgb(128, 128, 128) }
    41  .cov2 { color: rgb(116, 140, 131) }
    42  .cov3 { color: rgb(104, 152, 134) }
    43  .cov4 { color: rgb(92, 164, 137) }
    44  .cov5 { color: rgb(80, 176, 140) }
    45  .cov6 { color: rgb(68, 188, 143) }
    46  .cov7 { color: rgb(56, 200, 146) }
    47  .cov8 { color: rgb(44, 212, 149) }
    48  .cov9 { color: rgb(32, 224, 152) }
    49  .cov10 { color: rgb(20, 236, 155) }
    50  
    51  		</style>
    52  	</head>
    53  	<body>
    54  		<div id="topbar">
    55  			<div id="nav">
    56  				<select id="files">
    57  				
    58  				<option value="file0">github.com/vpayno/adventofcode-2022-golang-workspace/cmd/day01/aoc-day01.go (100.0%)</option>
    59  				
    60  				<option value="file1">github.com/vpayno/adventofcode-2022-golang-workspace/cmd/day02/aoc-day02.go (100.0%)</option>
    61  				
    62  				<option value="file2">github.com/vpayno/adventofcode-2022-golang-workspace/cmd/day03/aoc-day03.go (100.0%)</option>
    63  				
    64  				<option value="file3">github.com/vpayno/adventofcode-2022-golang-workspace/cmd/day04/aoc-day04.go (100.0%)</option>
    65  				
    66  				<option value="file4">github.com/vpayno/adventofcode-2022-golang-workspace/internal/aocshared/aocshared.go (100.0%)</option>
    67  				
    68  				<option value="file5">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day01/app.go (100.0%)</option>
    69  				
    70  				<option value="file6">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day01/init.go (100.0%)</option>
    71  				
    72  				<option value="file7">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day02/app.go (100.0%)</option>
    73  				
    74  				<option value="file8">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day02/init.go (100.0%)</option>
    75  				
    76  				<option value="file9">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day03/app.go (100.0%)</option>
    77  				
    78  				<option value="file10">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day03/init.go (100.0%)</option>
    79  				
    80  				<option value="file11">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day04/app.go (100.0%)</option>
    81  				
    82  				<option value="file12">github.com/vpayno/adventofcode-2022-golang-workspace/internal/day04/init.go (100.0%)</option>
    83  				
    84  				</select>
    85  			</div>
    86  			<div id="legend">
    87  				<span>not tracked</span>
    88  			
    89  				<span class="cov0">no coverage</span>
    90  				<span class="cov1">low coverage</span>
    91  				<span class="cov2">*</span>
    92  				<span class="cov3">*</span>
    93  				<span class="cov4">*</span>
    94  				<span class="cov5">*</span>
    95  				<span class="cov6">*</span>
    96  				<span class="cov7">*</span>
    97  				<span class="cov8">*</span>
    98  				<span class="cov9">*</span>
    99  				<span class="cov10">high coverage</span>
   100  			
   101  			</div>
   102  		</div>
   103  		<div id="content">
   104  		
   105  		<pre class="file" id="file0" style="display: none">// Package main is the cli module for the application.
   106  package main
   107  
   108  import (
   109          "fmt"
   110  
   111          app "github.com/vpayno/adventofcode-2022-golang-workspace/internal/day01"
   112  )
   113  
   114  var challengeName = "day01"
   115  
   116  func main() <span class="cov10" title="2">{
   117          // Create the configuration object.
   118          conf := app.Setup(challengeName)
   119  
   120          // Run the main application.
   121          err := app.Run(conf)
   122          if err != nil </span><span class="cov1" title="1">{
   123                  fmt.Println("Encountered error while running app.Run()")
   124                  fmt.Println()
   125                  fmt.Println(err)
   126  
   127                  // Don't panic
   128                  return
   129          }</span>
   130  }
   131  </pre>
   132  		
   133  		<pre class="file" id="file1" style="display: none">// Package main is the cli module for the application.
   134  package main
   135  
   136  import (
   137          "fmt"
   138  
   139          app "github.com/vpayno/adventofcode-2022-golang-workspace/internal/day02"
   140  )
   141  
   142  var challengeName = "day02"
   143  
   144  func main() <span class="cov10" title="2">{
   145          // Create the configuration object.
   146          conf := app.Setup(challengeName)
   147  
   148          // Run the main application.
   149          err := app.Run(conf)
   150          if err != nil </span><span class="cov1" title="1">{
   151                  fmt.Println("Encountered error while running app.Run()")
   152                  fmt.Println()
   153                  fmt.Println(err)
   154  
   155                  // Don't panic
   156                  return
   157          }</span>
   158  }
   159  </pre>
   160  		
   161  		<pre class="file" id="file2" style="display: none">// Package main is the cli module for the application.
   162  package main
   163  
   164  import (
   165          "fmt"
   166  
   167          app "github.com/vpayno/adventofcode-2022-golang-workspace/internal/day03"
   168  )
   169  
   170  var challengeName = "day03"
   171  
   172  func main() <span class="cov10" title="2">{
   173          // Create the configuration object.
   174          conf := app.Setup(challengeName)
   175  
   176          // Run the main application.
   177          err := app.Run(conf)
   178          if err != nil </span><span class="cov1" title="1">{
   179                  fmt.Println("Encountered error while running app.Run()")
   180                  fmt.Println()
   181                  fmt.Println(err)
   182  
   183                  // Don't panic
   184                  return
   185          }</span>
   186  }
   187  </pre>
   188  		
   189  		<pre class="file" id="file3" style="display: none">// Package main is the cli module for the application.
   190  package main
   191  
   192  import (
   193          "fmt"
   194  
   195          app "github.com/vpayno/adventofcode-2022-golang-workspace/internal/day04"
   196  )
   197  
   198  var challengeName = "day04"
   199  
   200  func main() <span class="cov10" title="2">{
   201          // Create the configuration object.
   202          conf := app.Setup(challengeName)
   203  
   204          // Run the main application.
   205          err := app.Run(conf)
   206          if err != nil </span><span class="cov1" title="1">{
   207                  fmt.Println("Encountered error while running app.Run()")
   208                  fmt.Println()
   209                  fmt.Println(err)
   210  
   211                  // Don't panic
   212                  return
   213          }</span>
   214  }
   215  </pre>
   216  		
   217  		<pre class="file" id="file4" style="display: none">// Package aocshared is the module with the cli logic for the application.
   218  package aocshared
   219  
   220  import (
   221          "bufio"
   222          "fmt"
   223          "os"
   224          "path/filepath"
   225  )
   226  
   227  // GetFile takes a file name and returns a file handle.
   228  func GetFile(fileName string) (*os.File, error) <span class="cov7" title="4">{
   229          fileRoot, err := os.Getwd()
   230          if err != nil </span><span class="cov1" title="1">{
   231                  return nil, err
   232          }</span>
   233  
   234          <span class="cov6" title="3">fileRoot = filepath.Clean(fileRoot + "/../../")
   235          fileName = filepath.Clean(fileRoot + "/" + fileName)
   236  
   237          // strings.HasPrefix() is pointless since we're generating the full path.
   238  
   239          // https://securego.io/docs/rules/g304.html - this gosec check seems to want
   240          // panic() calls
   241          file, err := os.Open(fileName) // #nosec
   242  
   243          return file, err</span>
   244  }
   245  
   246  // GetScanner takes a file handle and returns a bufio scanner.
   247  func GetScanner(file *os.File) *bufio.Scanner <span class="cov1" title="1">{
   248          scanner := bufio.NewScanner(file)
   249          scanner.Split(bufio.ScanLines)
   250  
   251          return scanner
   252  }</span>
   253  
   254  // ShowResult prints the passed integer.
   255  func ShowResult(result int) <span class="cov1" title="1">{
   256          fmt.Printf("%d\n", result)
   257  }</span>
   258  
   259  // Empty type to avoid ugly struct{}{}
   260  var Empty struct{}
   261  
   262  // Set holds a collection of unique items.
   263  type Set map[rune]struct{}
   264  
   265  // SetFromSlice creates a set from a slice.
   266  func SetFromSlice(slice []rune) Set <span class="cov1" title="1">{
   267          set := make(Set)
   268  
   269          for _, element := range slice </span><span class="cov10" title="6">{
   270                  set[element] = Empty
   271          }</span>
   272  
   273          <span class="cov1" title="1">return set</span>
   274  }
   275  
   276  // SetIntersect finds the intersection of two sets.
   277  func SetIntersect(s1, s2 Set) []rune <span class="cov1" title="1">{
   278          common := []rune{}
   279  
   280          for key := range s1 </span><span class="cov7" title="4">{
   281                  _, found := s2[key]
   282                  if found </span><span class="cov1" title="1">{
   283                          common = append(common, key)
   284                  }</span>
   285          }
   286  
   287          <span class="cov1" title="1">return common</span>
   288  }
   289  
   290  // SplitString converts a string into a slice of runes.
   291  func SplitString(str string) []rune <span class="cov1" title="1">{
   292          runes := []rune{}
   293  
   294          for _, r := range str </span><span class="cov7" title="4">{
   295                  runes = append(runes, r)
   296          }</span>
   297  
   298          <span class="cov1" title="1">return runes</span>
   299  }
   300  </pre>
   301  		
   302  		<pre class="file" id="file5" style="display: none">// Package day01 is the module with the cli logic for the application.
   303  package day01
   304  
   305  import (
   306          "bufio"
   307          "fmt"
   308          "sort"
   309          "strconv"
   310  
   311          "github.com/vpayno/adventofcode-2022-golang-workspace/internal/aocshared"
   312  )
   313  
   314  // Run is called my the gain function. It's basically the main function of the app.
   315  func Run(conf Config) error <span class="cov2" title="3">{
   316          file, err := aocshared.GetFile(conf.inputFileName)
   317          if err != nil </span><span class="cov1" title="1">{
   318                  return err
   319          }</span>
   320  
   321          <span class="cov1" title="2">scanner := aocshared.GetScanner(file)
   322  
   323          data, err := loadData(scanner)
   324          if err != nil </span><span class="cov1" title="1">{
   325                  return err
   326          }</span>
   327  
   328          <span class="cov1" title="1">topCalories := getMaxCalories(data)
   329  
   330          aocshared.ShowResult(topCalories)
   331  
   332          topThreeCalories := getResultTopThreeCalories(data)
   333  
   334          aocshared.ShowResult(topThreeCalories)
   335  
   336          return nil</span>
   337  }
   338  
   339  func loadData(file *bufio.Scanner) (map[string]int, error) <span class="cov2" title="4">{
   340          var err error
   341  
   342          data := map[string]int{}
   343  
   344          var elfCounter = 1
   345          var calories int
   346  
   347          for file.Scan() </span><span class="cov10" title="4482">{
   348                  line := file.Text()
   349  
   350                  elfName := fmt.Sprintf("%s%d", "elf", elfCounter)
   351  
   352                  if line == "" </span><span class="cov7" title="482">{
   353                          elfCounter++
   354                          data[elfName] = calories
   355                          calories = 0
   356  
   357                          continue</span>
   358                  }
   359  
   360                  <span class="cov9" title="4000">calorie, err := strconv.Atoi(line)
   361                  if err != nil </span><span class="cov1" title="2">{
   362                          return map[string]int{}, err
   363                  }</span>
   364  
   365                  <span class="cov9" title="3998">calories += calorie</span>
   366          }
   367  
   368          <span class="cov1" title="2">return data, err</span>
   369  }
   370  
   371  func getMaxCalories(data map[string]int) int <span class="cov1" title="2">{
   372          var result int
   373  
   374          for _, calories := range data </span><span class="cov6" title="246">{
   375                  if calories &gt; result </span><span class="cov3" title="8">{
   376                          result = calories
   377                  }</span>
   378          }
   379  
   380          <span class="cov1" title="2">return result</span>
   381  }
   382  
   383  func getTopThreeSum(calories []int) int <span class="cov2" title="3">{
   384          var sum int
   385  
   386          var start int
   387  
   388          if len(calories) &gt; 3 </span><span class="cov2" title="3">{
   389                  start += len(calories) - 3
   390          }</span>
   391  
   392          <span class="cov2" title="3">sort.Ints(calories)
   393  
   394          for _, calorie := range calories[start:] </span><span class="cov3" title="9">{
   395                  sum += calorie
   396          }</span>
   397  
   398          <span class="cov2" title="3">return sum</span>
   399  }
   400  
   401  func getResultTopThreeCalories(data map[string]int) int <span class="cov1" title="2">{
   402          totals := []int{}
   403  
   404          for _, calories := range data </span><span class="cov6" title="246">{
   405                  totals = append(totals, calories)
   406          }</span>
   407  
   408          <span class="cov1" title="2">result := getTopThreeSum(totals)
   409  
   410          return result</span>
   411  }
   412  </pre>
   413  		
   414  		<pre class="file" id="file6" style="display: none">// Package day01 is the module with the cli logic for the cmd application.
   415  package day01
   416  
   417  // Config holds the application's configuration.
   418  type Config struct {
   419          appName       string
   420          inputFileName string
   421  }
   422  
   423  // Setup creates the applications configuration object.
   424  func Setup(appName string) Config <span class="cov10" title="4">{
   425  
   426          conf := Config{
   427                  appName:       appName,
   428                  inputFileName: "data/" + appName + "/" + appName + "-input.txt",
   429          }
   430  
   431          return conf
   432  }</span>
   433  </pre>
   434  		
   435  		<pre class="file" id="file7" style="display: none">// Package day02 is the module with the cli logic for the application.
   436  package day02
   437  
   438  import (
   439          "bufio"
   440          "fmt"
   441          "strings"
   442  
   443          "github.com/vpayno/adventofcode-2022-golang-workspace/internal/aocshared"
   444  )
   445  
   446  // Run is called my the gain function. It's basically the main function of the app.
   447  func Run(conf Config) error <span class="cov2" title="3">{
   448          file, err := aocshared.GetFile(conf.inputFileName)
   449          if err != nil </span><span class="cov1" title="1">{
   450                  return err
   451          }</span>
   452  
   453          <span class="cov1" title="2">scanner := aocshared.GetScanner(file)
   454  
   455          data, err := loadData(scanner)
   456          if err != nil </span><span class="cov1" title="1">{
   457                  return err
   458          }</span>
   459  
   460          <span class="cov1" title="1">totalScore := getTotalScore(data)
   461  
   462          aocshared.ShowResult(totalScore)
   463  
   464          return nil</span>
   465  }
   466  
   467  func loadData(file *bufio.Scanner) (rounds, error) <span class="cov2" title="4">{
   468          var err error
   469  
   470          data := rounds{}
   471  
   472          for file.Scan() </span><span class="cov10" title="5018">{
   473                  line := file.Text()
   474  
   475                  if line == "" </span><span class="cov1" title="2">{
   476                          continue</span>
   477                  }
   478  
   479                  <span class="cov9" title="5016">s := strings.Fields(line)
   480  
   481                  if len(s) != 2 </span><span class="cov1" title="2">{
   482                          err := fmt.Errorf("wrong number of records: has %d, need %d", len(s), 2)
   483                          return []round{}, err
   484                  }</span>
   485  
   486                  <span class="cov9" title="5014">theirMove := string2move[s[them]]
   487                  yourGoal := string2outcome[s[goal]]
   488  
   489                  r := round{
   490                          them: theirMove,
   491                          goal: yourGoal,
   492                  }
   493  
   494                  data = append(data, r)</span>
   495          }
   496  
   497          <span class="cov1" title="2">return data, err</span>
   498  }
   499  
   500  func getTotalScore(data rounds) int <span class="cov1" title="2">{
   501          var result int
   502  
   503          for _, r := range data </span><span class="cov9" title="2503">{
   504                  result += r.score()
   505          }</span>
   506  
   507          <span class="cov1" title="2">return result</span>
   508  }
   509  </pre>
   510  		
   511  		<pre class="file" id="file8" style="display: none">// Package day02 is the module with the cli logic for the cmd application.
   512  package day02
   513  
   514  // Config holds the application's configuration.
   515  type Config struct {
   516          appName       string
   517          inputFileName string
   518  }
   519  
   520  // record ids (columns in input file)
   521  const (
   522          them int = iota
   523          goal
   524  )
   525  
   526  // Outcome describes the possible outcomes.
   527  type outcome int
   528  
   529  const (
   530          loose outcome = 0
   531          draw  outcome = 3
   532          win   outcome = 6
   533  )
   534  
   535  var outcomeNames = map[outcome]string{
   536          loose: "loose",
   537          draw:  "draw",
   538          win:   "win",
   539  }
   540  
   541  // Move descrives possible moves.
   542  type move int
   543  
   544  const (
   545          rock     move = 1
   546          paper    move = 2
   547          scissors move = 3
   548  )
   549  
   550  var moveNames = map[move]string{
   551          rock:     "rock",
   552          paper:    "paper",
   553          scissors: "scissors",
   554  }
   555  
   556  var string2move = map[string]move{
   557          "A": rock,
   558          "B": paper,
   559          "C": scissors,
   560  }
   561  
   562  var string2outcome = map[string]outcome{
   563          "X": loose,
   564          "Y": draw,
   565          "Z": win,
   566  }
   567  
   568  // Round describes one round of rock-paper-scissors.
   569  type round struct {
   570          them move
   571          goal outcome
   572  }
   573  
   574  func (r *round) yourMove() move <span class="cov10" title="2521">{
   575          var you move
   576  
   577          switch r.goal </span>{
   578          case loose:<span class="cov7" title="411">
   579                  switch r.them </span>{
   580                  case rock:<span class="cov5" title="43">
   581                          you = scissors</span>
   582                  case paper:<span class="cov7" title="323">
   583                          you = rock</span>
   584                  case scissors:<span class="cov5" title="45">
   585                          you = paper</span>
   586                  }
   587          case win:<span class="cov8" title="848">
   588                  switch r.them </span>{
   589                  case rock:<span class="cov6" title="84">
   590                          you = paper</span>
   591                  case paper:<span class="cov7" title="225">
   592                          you = scissors</span>
   593                  case scissors:<span class="cov8" title="539">
   594                          you = rock</span>
   595                  }
   596          default:<span class="cov9" title="1262">
   597                  you = r.them</span>
   598          }
   599  
   600          <span class="cov10" title="2521">return you</span>
   601  }
   602  
   603  func (r *round) score() int <span class="cov9" title="2512">{
   604          return int(r.goal) + int(r.yourMove())
   605  }</span>
   606  
   607  func (r *round) update(slice []move) <span class="cov1" title="1">{
   608          r.them = slice[them]
   609          r.goal = outcome(int(slice[goal]))
   610  }</span>
   611  
   612  type rounds []round
   613  
   614  // Setup creates the applications configuration object.
   615  func Setup(appName string) Config <span class="cov2" title="4">{
   616  
   617          conf := Config{
   618                  appName:       appName,
   619                  inputFileName: "data/" + appName + "/" + appName + "-input.txt",
   620          }
   621  
   622          return conf
   623  }</span>
   624  </pre>
   625  		
   626  		<pre class="file" id="file9" style="display: none">// Package day03 is the module with the cli logic for the application.
   627  package day03
   628  
   629  import (
   630          "bufio"
   631          "fmt"
   632  
   633          "github.com/vpayno/adventofcode-2022-golang-workspace/internal/aocshared"
   634  )
   635  
   636  // Run is called my the gain function. It's basically the main function of the app.
   637  func Run(conf Config) error <span class="cov3" title="6">{
   638          file, err := aocshared.GetFile(conf.inputFileName)
   639          if err != nil </span><span class="cov1" title="2">{
   640                  return err
   641          }</span>
   642  
   643          <span class="cov2" title="4">scanner := aocshared.GetScanner(file)
   644  
   645          data, err := loadData(scanner)
   646          if err != nil </span><span class="cov1" title="1">{
   647                  return err
   648          }</span>
   649  
   650          <span class="cov2" title="3">prioritySum, err := getPrioritySum(data)
   651          if err != nil </span><span class="cov1" title="1">{
   652                  return err
   653          }</span>
   654  
   655          <span class="cov1" title="2">aocshared.ShowResult(prioritySum)
   656  
   657          groupPrioritySum, err := getGroupPrioritySum(data)
   658          if err != nil </span><span class="cov1" title="1">{
   659                  return err
   660          }</span>
   661  
   662          <span class="cov1" title="1">aocshared.ShowResult(groupPrioritySum)
   663  
   664          return nil</span>
   665  }
   666  
   667  func loadData(file *bufio.Scanner) (rucksacks, error) <span class="cov3" title="7">{
   668          data := rucksacks{}
   669  
   670          for file.Scan() </span><span class="cov10" title="907">{
   671                  line := file.Text()
   672  
   673                  if line == "" </span><span class="cov1" title="1">{
   674                          continue</span>
   675                  }
   676  
   677                  <span class="cov9" title="906">r := rucksack{}
   678                  err := r.addItems(line)
   679                  if err != nil </span><span class="cov2" title="3">{
   680                          return data, err
   681                  }</span>
   682  
   683                  <span class="cov9" title="903">data = append(data, r)</span>
   684          }
   685  
   686          <span class="cov2" title="4">return data, nil</span>
   687  }
   688  
   689  func getPrioritySum(data rucksacks) (int, error) <span class="cov3" title="5">{
   690          var result int
   691  
   692          for _, r := range data </span><span class="cov9" title="608">{
   693                  priority, err := r.getSharedPriority()
   694                  if err != nil </span><span class="cov1" title="2">{
   695                          return 0, err
   696                  }</span>
   697  
   698                  <span class="cov9" title="606">result += priority</span>
   699          }
   700  
   701          <span class="cov2" title="3">return result, nil</span>
   702  }
   703  
   704  func getGroupPrioritySum(data rucksacks) (int, error) <span class="cov3" title="5">{
   705          var groupSum int
   706          group := []string{}
   707          sacks := [][]string{}
   708  
   709          if len(data) == 0 </span><span class="cov1" title="1">{
   710                  err := fmt.Errorf("rucksack list is empty: %v", data)
   711                  return 0, err
   712          }</span>
   713  
   714          <span class="cov2" title="4">if len(data)%3 != 0 </span><span class="cov1" title="2">{
   715                  err := fmt.Errorf("rucksack list length, %d, isn't evenly divisible by 3", len(data))
   716                  return 0, err
   717          }</span>
   718  
   719          <span class="cov1" title="2">for i, r := range data </span><span class="cov8" title="306">{
   720                  if i%3 == 0 &amp;&amp; i &gt; 0 </span><span class="cov7" title="100">{
   721                          sacks = append(sacks, group)
   722                          group = []string{}
   723                  }</span>
   724  
   725                  <span class="cov8" title="306">group = append(group, r.items)</span>
   726          }
   727  
   728          <span class="cov1" title="2">sacks = append(sacks, group)
   729  
   730          for _, group := range sacks </span><span class="cov7" title="102">{
   731                  // not handling the case where the number of rucksacks isn't evenly divisibleby 3
   732                  g1 := aocshared.SetFromSlice(aocshared.SplitString(group[0]))
   733                  g2 := aocshared.SetFromSlice(aocshared.SplitString(group[1]))
   734                  g3 := aocshared.SetFromSlice(aocshared.SplitString(group[2]))
   735  
   736                  c1 := aocshared.SetFromSlice(aocshared.SetIntersect(g1, g2))
   737                  c2 := aocshared.SetFromSlice(aocshared.SetIntersect(g1, g3))
   738                  c3 := aocshared.SetFromSlice(aocshared.SetIntersect(g2, g3))
   739  
   740                  c1 = aocshared.SetFromSlice(aocshared.SetIntersect(c1, c2))
   741                  c1 = aocshared.SetFromSlice(aocshared.SetIntersect(c1, c3))
   742  
   743                  for item := range c1 </span><span class="cov7" title="102">{
   744                          priority := getPriority(item)
   745                          groupSum += priority
   746                  }</span>
   747          }
   748  
   749          <span class="cov1" title="2">return groupSum, nil</span>
   750  }
   751  </pre>
   752  		
   753  		<pre class="file" id="file10" style="display: none">// Package day03 is the module with the cli logic for the cmd application.
   754  package day03
   755  
   756  import (
   757          "errors"
   758          "fmt"
   759          "strings"
   760          "unicode"
   761  )
   762  
   763  // Config holds the application's configuration.
   764  type Config struct {
   765          appName       string
   766          inputFileName string
   767  }
   768  
   769  // Rucksack holds an Elf's items.
   770  type rucksack struct {
   771          items string
   772  }
   773  
   774  func (r *rucksack) addItems(items string) error <span class="cov8" title="922">{
   775          if len(items)%2 != 0 </span><span class="cov2" title="4">{
   776                  return fmt.Errorf("items list isn't evenly divisible (len=%d)", len(items))
   777          }</span>
   778  
   779          <span class="cov8" title="918">r.items = items
   780  
   781          return nil</span>
   782  }
   783  
   784  func (r *rucksack) getCollection(num int) string <span class="cov8" title="1226">{
   785  
   786          if num == 1 </span><span class="cov7" title="613">{
   787                  return r.items[0 : len(r.items)/2]
   788          }</span>
   789  
   790          <span class="cov7" title="613">return r.items[len(r.items)/2:]</span>
   791  }
   792  
   793  // lot's of room or optimizations
   794  func (r *rucksack) getSharedItem() (rune, error) <span class="cov7" title="612">{
   795          collection1 := r.getCollection(1)
   796          collection2 := r.getCollection(2)
   797  
   798          for _, char := range collection1 </span><span class="cov10" title="4466">{
   799                  if strings.ContainsRune(collection2, char) </span><span class="cov7" title="608">{
   800                          return char, nil
   801                  }</span>
   802          }
   803  
   804          <span class="cov2" title="4">return rune(0), errors.New("rucksack compartments doesn't have a shared item")</span>
   805  }
   806  
   807  func (r *rucksack) getSharedPriority() (int, error) <span class="cov7" title="610">{
   808          shared, err := r.getSharedItem()
   809          if err != nil </span><span class="cov2" title="3">{
   810                  return 0, err
   811          }</span>
   812  
   813          <span class="cov7" title="607">return getPriority(shared), nil</span>
   814  }
   815  
   816  type rucksacks []rucksack
   817  
   818  // Setup creates the applications configuration object.
   819  func Setup(appName string) Config <span class="cov3" title="7">{
   820  
   821          conf := Config{
   822                  appName:       appName,
   823                  inputFileName: "data/" + appName + "/" + appName + "-input.txt",
   824          }
   825  
   826          return conf
   827  }</span>
   828  
   829  func getPriority(item rune) int <span class="cov8" title="713">{
   830          if unicode.IsLower(item) </span><span class="cov7" title="322">{
   831                  return int(item) - 96
   832          }</span>
   833  
   834          <span class="cov7" title="391">return int(item) - 38</span>
   835  }
   836  </pre>
   837  		
   838  		<pre class="file" id="file11" style="display: none">// Package day04 is the module with the cli logic for the application.
   839  package day04
   840  
   841  import (
   842          "bufio"
   843  
   844          "github.com/vpayno/adventofcode-2022-golang-workspace/internal/aocshared"
   845  )
   846  
   847  // Run is called my the gain function. It's basically the main function of the app.
   848  func Run(conf Config) error <span class="cov3" title="8">{
   849          file, err := aocshared.GetFile(conf.inputFileName)
   850          if err != nil </span><span class="cov1" title="1">{
   851                  return err
   852          }</span>
   853  
   854          <span class="cov3" title="7">scanner := aocshared.GetScanner(file)
   855  
   856          data, err := loadData(scanner)
   857          if err != nil </span><span class="cov3" title="6">{
   858                  return err
   859          }</span>
   860  
   861          <span class="cov1" title="1">fullyContainedSum := getFullyContainedCount(data)
   862  
   863          aocshared.ShowResult(fullyContainedSum)
   864  
   865          partiallyContainedSum := getPartiallyContainedCount(data)
   866  
   867          aocshared.ShowResult(partiallyContainedSum)
   868  
   869          return nil</span>
   870  }
   871  
   872  func loadData(file *bufio.Scanner) (pairs, error) <span class="cov4" title="15">{
   873          data := pairs{}
   874  
   875          for file.Scan() </span><span class="cov10" title="2029">{
   876                  line := file.Text()
   877  
   878                  if line == "" </span><span class="cov1" title="1">{
   879                          continue</span>
   880                  }
   881  
   882                  <span class="cov9" title="2028">p := pair{}
   883                  err := p.addPair(line)
   884                  if err != nil </span><span class="cov3" title="12">{
   885                          return data, err
   886                  }</span>
   887  
   888                  <span class="cov9" title="2016">data = append(data, p)</span>
   889          }
   890  
   891          <span class="cov2" title="3">return data, nil</span>
   892  }
   893  
   894  func getFullyContainedCount(data pairs) int <span class="cov1" title="2">{
   895          var count int
   896  
   897          for _, p := range data </span><span class="cov9" title="1006">{
   898                  if p.isFullyContained(1) || p.isFullyContained(2) </span><span class="cov8" title="500">{
   899                          count++
   900                  }</span>
   901          }
   902  
   903          <span class="cov1" title="2">return count</span>
   904  }
   905  
   906  func getPartiallyContainedCount(data pairs) int <span class="cov1" title="2">{
   907          var count int
   908  
   909          for _, p := range data </span><span class="cov9" title="1006">{
   910                  if p.isPartiallyContained(1) || p.isPartiallyContained(2) </span><span class="cov8" title="863">{
   911                          count++
   912                  }</span>
   913          }
   914  
   915          <span class="cov1" title="2">return count</span>
   916  }
   917  </pre>
   918  		
   919  		<pre class="file" id="file12" style="display: none">// Package day04 is the module with the cli logic for the cmd application.
   920  package day04
   921  
   922  import (
   923          "fmt"
   924          "strconv"
   925          "strings"
   926  )
   927  
   928  // Config holds the application's configuration.
   929  type Config struct {
   930          appName       string
   931          inputFileName string
   932  }
   933  
   934  // Section stores the start and end range of an Elf's section.
   935  type section struct {
   936          start int
   937          end   int
   938  }
   939  
   940  func (s *section) addRange(r string) error <span class="cov10" title="4075">{
   941          data := strings.Split(r, "-")
   942  
   943          if len(data) != 2 </span><span class="cov1" title="2">{
   944                  return fmt.Errorf("range did not contain start and end values (%v)", data)
   945          }</span>
   946  
   947          <span class="cov9" title="4073">var err error
   948  
   949          start, err := strconv.Atoi(data[0])
   950          if err != nil </span><span class="cov1" title="2">{
   951                  return err
   952          }</span>
   953  
   954          <span class="cov9" title="4071">end, err := strconv.Atoi(data[1])
   955          if err != nil </span><span class="cov1" title="2">{
   956                  return err
   957          }</span>
   958  
   959          <span class="cov9" title="4069">if start &lt; 1 </span><span class="cov1" title="2">{
   960                  return fmt.Errorf("range start, %d, is less than 1", start)
   961          }</span>
   962  
   963          <span class="cov9" title="4067">if end &gt; 99 </span><span class="cov1" title="2">{
   964                  return fmt.Errorf("range end, %d, is greather than 99", end)
   965          }</span>
   966  
   967          <span class="cov9" title="4065">s.start = start
   968          s.end = end
   969  
   970          return nil</span>
   971  }
   972  
   973  // Pair holds 2 elves sections.
   974  type pair struct {
   975          elf1 section
   976          elf2 section
   977  }
   978  
   979  func (p *pair) addPair(input string) error <span class="cov9" title="2042">{
   980          data := strings.Split(input, ",")
   981  
   982          if len(data) != 2 </span><span class="cov1" title="2">{
   983                  return fmt.Errorf("input list doesn't contain two entries (%v)", data)
   984          }</span>
   985  
   986          <span class="cov9" title="2040">err := p.elf1.addRange(data[0])
   987          if err != nil </span><span class="cov2" title="6">{
   988                  return err
   989          }</span>
   990  
   991          <span class="cov9" title="2034">err = p.elf2.addRange(data[1])
   992          if err != nil </span><span class="cov2" title="4">{
   993                  return err
   994          }</span>
   995  
   996          <span class="cov9" title="2030">return nil</span>
   997  }
   998  
   999  func (p *pair) isFullyContained(elfNo int) bool <span class="cov9" title="1749">{
  1000          if elfNo == 1 </span><span class="cov8" title="1007">{
  1001                  return p.elf1.start &gt;= p.elf2.start &amp;&amp; p.elf1.end &lt;= p.elf2.end
  1002          }</span>
  1003  
  1004          <span class="cov8" title="742">return p.elf2.start &gt;= p.elf1.start &amp;&amp; p.elf2.end &lt;= p.elf1.end</span>
  1005  }
  1006  
  1007  func (p *pair) isPartiallyContained(elfNo int) bool <span class="cov8" title="1238">{
  1008          if elfNo == 1 </span><span class="cov8" title="1006">{
  1009                  return (p.elf2.start &lt;= p.elf1.start &amp;&amp; p.elf1.start &lt;= p.elf2.end) || (p.elf2.start &lt;= p.elf1.end &amp;&amp; p.elf1.end &lt;= p.elf2.end)
  1010          }</span>
  1011  
  1012          <span class="cov6" title="232">return (p.elf1.start &lt;= p.elf2.start &amp;&amp; p.elf2.start &lt;= p.elf1.end) || (p.elf1.start &lt;= p.elf2.end &amp;&amp; p.elf2.end &lt;= p.elf1.end)</span>
  1013  }
  1014  
  1015  type pairs []pair
  1016  
  1017  // Setup creates the applications configuration object.
  1018  func Setup(appName string) Config <span class="cov3" title="9">{
  1019  
  1020          conf := Config{
  1021                  appName:       appName,
  1022                  inputFileName: "data/" + appName + "/" + appName + "-input.txt",
  1023          }
  1024  
  1025          return conf
  1026  }</span>
  1027  </pre>
  1028  		
  1029  		</div>
  1030  	</body>
  1031  	<script>
  1032  	(function() {
  1033  		var files = document.getElementById('files');
  1034  		var visible;
  1035  		files.addEventListener('change', onChange, false);
  1036  		function select(part) {
  1037  			if (visible)
  1038  				visible.style.display = 'none';
  1039  			visible = document.getElementById(part);
  1040  			if (!visible)
  1041  				return;
  1042  			files.value = part;
  1043  			visible.style.display = 'block';
  1044  			location.hash = part;
  1045  		}
  1046  		function onChange() {
  1047  			select(files.value);
  1048  			window.scrollTo(0, 0);
  1049  		}
  1050  		if (location.hash != "") {
  1051  			select(location.hash.substr(1));
  1052  		}
  1053  		if (!visible) {
  1054  			select("file0");
  1055  		}
  1056  	})();
  1057  	</script>
  1058  </html>