{"size": 1999, "ext": "js", "max_stars_repo_path": "2016/4b.js", "max_stars_repo_name": "jwhitfieldseed/advent-of-code", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "2016/4b.js", "max_issues_repo_name": "jwhitfieldseed/advent-of-code", "max_issues_repo_issues_event_min_datetime": "2016-12-10T23:31:15.000Z", "max_issues_repo_issues_event_max_datetime": "2016-12-10T23:32:36.000Z", "max_forks_repo_path": "2016/4b.js", "max_forks_repo_name": "jwhitfieldseed/advent-of-code", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": 2, "max_forks_count": null, "avg_line_length": 24.9875, "max_line_length": 68, "alphanum_fraction": 0.6213106553}
const { loadInput, fn } = require('./lib.js')
const { pipe, map, filter, toArray } = fn

// room-name-with-dashes-sectorid[checksum]
function parse (line) {
  const match = /([a-z-]+)-(\d+)\[([a-z]+)]/.exec(line.trim())
  if (match) {
    const [, name, rawSector, checksum] = match
    const sector = parseInt(rawSector, 10)
    return [name, sector, checksum]
  } else {
    throw new Error(`Bad line: ${line}`)
  }
}

// Return an object where the keys are each char in String `s`
// and the values are the number of times that char appears in s
function countLetters (s) {
  return s.split('')
    .filter(c => c !== '-')
    .reduce((counts, c) => {
      const count = counts[c] || 0
      return Object.assign(counts, { [c]: count + 1 })
    }, {})
}

function isReal ([name, sector, checksum]) {
  const counts = countLetters(name)
  return checksum === computeChecksum(counts)
}

// Return an ordered string of the letters in counting set `count`,
//  ordered by count then alphabetically
function computeChecksum (counts) {
  return Object.keys(counts)
    .sort((a, b) => ((counts[b] - counts[a]) || a.localeCompare(b)))
    .slice(0, 5)
    .join('')
}

// get the ascii code for char `c`
function ord (c) {
  return c.charCodeAt(0)
}

// decrypt a whole string
function decrypt ([encrypted, sector]) {
  const decrypted = encrypted.split('')
    .map(c => (c === '-') ? ' ' : shift(c, sector))
    .join('')

  return [decrypted, sector]
}

// decrypt a single character
function shift (c, n) {
  // 97: ASCII 'a'. offsets the caeaer cipher arithmetic.
  return String.fromCharCode(((ord(c) - 97 + n) % 26) + 97)
}

// Go
// const input = `
// aaaaa-bbb-z-y-x-123[abxyz]
// a-b-c-d-e-f-g-h-987[abcde]
// not-a-real-room-404[oarel]
// totally-real-room-200[decoy]`

const input = loadInput('4.txt')
const data = input.trim().split('\n')

const answer = pipe(data,
  map(parse),
  filter(isReal),
  map(decrypt),
  filter(([name]) => /north/.test(name)),
  toArray
)

console.log(answer)
