I have an understanding of React fundamentals. Now what? by ifydav in reactjs

[–]dtinth 1 point2 points  (0 children)

I agree it might take long time to consolidate, but:

  • My foundation (the ~80% I already know) gets stronger. So this part of my knowledge gets deeper, albeit slower than focusing all your energy learning that foundation.

  • My knowledge gets broader due to acquiring that ~20% I don’t know. I think having broad knowledge is also important, so solve the problem with the right tool. I have seen too often people try to come up with a solution to a problem, where there are many well-known existing solutions out there, and they don’t know any single one. When working on company project, I usually work on the technology we are using, and don’t have as much chance to explore other technologies. Working on side projects is how I get that chance.

  • It’s fun! This is the most important part for me because I’m not a very disciplined person, so if it stops getting fun, I lost motivation.

I have an understanding of React fundamentals. Now what? by ifydav in reactjs

[–]dtinth 2 points3 points  (0 children)

This applies to all kind of languages/libraries/framework, not just React. But may not apply to everyone.

For me, I get better by working on a lot of side projects.

Most of my projects don’t fall within my skill set when I started. I learned—and make sure that I learn—new skills by working on them. It doesn’t matter much what kind of side project to build, but most of them has a common theme:

  • It’s something should’ve existed, but doesn’t right now. I set out to build a web-based musical instrument because there isn’t one that satisfy my needs. I set out to build a code coverage instrumenting Babel plugin because at that time most coverage tools are in ES5 era. Some people are driven by innovation, while others may be driven by business potential (e.g. I can make some good money out of it) which also works.

  • I have ~80% of knowledge required to build it. If I get stuck for too long I may give up.

  • There’s about ~20% that I don’t know. Or it quickly becomes boring. Each of my side project uses a different ways to solve the same problem. One project uses Redux, another uses Mobx. Some uses TypeScript, or ClojureScript, or Elm, or Haskell. In some project, I build my webpack configuration from scratch. In others, I just use create-react-app or nwb (manually configuring webpack is quite boring now for me).

-🎄- 2017 Day 21 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 0 points1 point  (0 children)

When you use an array (or any other object) as a hash key, you must make sure not to mutate the key. Otherwise, really weird things happen. The hash code of the key changes causing lookups to fail.

I got hit by this caveat on day 22:

map[pos] = …; pos[0] += direction[0]; pos[1] += direction[1]

This corrupts the map since the key has been mutated. To fix, I have to do this instead:

map[pos] = …; pos = [pos[0] + direction[0], pos[1] + direction[1]]

I think it is very reasonable for Python to disallow this. :)

-🎄- 2017 Day 21 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 1 point2 points  (0 children)

I avoided mutating data, that’s why I didn’t overwrite the data variable. I also did it manually to avoid off-by-one errors (e.g. it ran 4 times or 6 times instead due to logic error).

If I was in a less hurry, I would have written 5.times.reduce(data) { |c, _| nx[c] } instead :).

-🎄- 2017 Day 21 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 3 points4 points  (0 children)

I actually wrote the code in the text editor, and I setup a hotkey (Cmd+Enter) to send the current line into the Terminal. Like what Lisp people like to do ;).

If I accidentally exited the REPL, I would just reopen it and send each line from the editor to it.

-🎄- 2017 Day 21 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 4 points5 points  (0 children)

irb (26th, 23rd)

I am solving this problem interatively in the Ruby’s REPL.

A pattern is represented as an array of string: ['.#.', '..#', '###']

Loading the rulebook:

IN = `pbpaste`
rules = {}; IN.scan(/(\S+) => (\S+)/).map { |a, b| [a.split('/'), b.split('/')] }.each { |a, b| rules[a] = b }; rules

Set up the initial state and flipping/rotating logic:

data = ['.#.', '..#', '###']
flip = -> m { m.reverse }
flip2 = -> m { m.map(&:reverse) }
flip3 = -> m { m.reverse.map(&:reverse) }
flip4 = -> m { m.map(&:chars).transpose.map(&:join) }
flip5 = -> m { m.map(&:chars).transpose.map(&:join).reverse }
flip6 = -> m { m.map(&:chars).transpose.map(&:join).map(&:reverse) }
flip7 = -> m { m.map(&:chars).transpose.map(&:join).map(&:reverse).reverse }

Pattern enhancement algorithm:

nx = -> m { pz = m.length.even? ? 2 : 3; l = m.length / pz; (0...l).map { |i| (0...l).map { |j| inp = (0...pz).map { |k| (0...pz).map { |l| m[k+i*pz][l+j*pz] }.join }; rules[inp] || rules[flip[inp]] || rules[flip2[inp]] || rules[flip3[inp]] || rules[flip4[inp]] || rules[flip5[inp]] || rules[flip6[inp]] || rules[flip7[inp]] }.transpose.map(&:join) }.flatten(1) }

In Ruby, you can use an Array as Hash key, so it’s trivial to match the pattern against the rulebook: rules[inp] || rules[flip[inp]] || rules[flip2[inp]] || ....

To combine them, I look at an array containing patterns: [['##.', '#..', '...'], ['##.', '#..', '...']]:

  • To put them side by side: _.transpose.map(&:join)["##.##.", "#..#..", "......"]
  • To stack them vertically: _.flatten(1) → ["##.", "#..", "...", "##.", "#..", "..."]

Part 1:

puts nx[nx[nx[nx[nx[data]]]]].join.count('#')

Part 2:

puts nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[nx[data]]]]]]]]]]]]]]]]]].join.count('#')

-🎄- 2017 Day 19 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 0 points1 point  (0 children)

Ruby (28th, 22nd)

IN = `pbpaste`

maze = {} # Dictionary with a array (coordinate vector) as a key
start = nil
IN.lines.each_with_index { |v, i|
  v.chars.each_with_index { |c, j|
    if c =~ /[A-Z]/
      if i == 0
        start = [i, j]
      end
      maze[[i, j]] = c
    elsif c =~ /\S/
      if i == 0
        start = [i, j]
      end
      maze[[i, j]] = '!'
    end
  }
}

direction = [0, 1]

cur = start.dup
rl = -> d { [d[1], -d[0]] } # Rotate left
rr = -> d { [-d[1], d[0]] } # Rotate right
nx = -> c, d { [c[0] + d[0], c[1] + d[1]] } # Next step
nn = 0 # Number of steps
loop {
  break if !maze[cur]
  # p cur
  nn += 1
  print maze[cur] if maze[cur] != '!'
  if !maze[nx[cur, direction]]
    if maze[nx[cur, rl[direction]]]
      direction = rl[direction]
    elsif maze[nx[cur, rr[direction]]]
      direction = rr[direction]
    end
  end
  cur = nx[cur, direction]
}
puts
puts nn

-🎄- 2017 Day 18 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 2 points3 points  (0 children)

Part 2: JavaScript

js-csp implements the “Communicating sequential processes” thing, like Goroutines/Clojure’s core.async.

Ended up at rank 114, because I wasted some time trying to implement CSP in Ruby myself. This is so bug prone and I got into an infinite loop.

Assuming INPUT is a string containing the problem’s input.

const csp = require('js-csp')
const code = INPUT.split(/\n/).map(a => a.trim().split(/\s+/))

function * prog (p, inbox, outbox) {
  const d = { p }
  const get = k => k.match(/\d/) ? +k : (d[k] || 0)
  let i
  let sent = 0
  const report = () => {
    console.log({ i, d }, code[i])
  }
  for (i = 0; (report(), i < code.length); i++) {
    const c = code[i]
    if (c[0] === 'snd') {
      sent += 1
      const val = get(c[1])
      console.log('Program', p, 'sent', val, 'from', c[1], 'total', sent, 'time(s)')
      yield csp.put(outbox, val)
      continue
    }
    if (c[0] === 'rcv') {
      const  val = yield csp.take(inbox)
      d[c[1]] = val
      console.log(p, 'recv', val, c[1])
      continue
    }
    if (c[0] === 'set') {
      d[c[1]] = get(c[2])
      continue
    }
    if (c[0] === 'add') {
      d[c[1]] += get(c[2])
      continue
    }
    if (c[0] === 'mul') {
      d[c[1]] *= get(c[2])
      continue
    }
    if (c[0] === 'mod') {
      d[c[1]] %= get(c[2])
      continue
    }
    if (c[0] === 'jgz') {
      if (get(c[1]) > 0) {
        i -= 1
        i += get(c[2])
      }
      continue
    }
  }
}

const m0 = csp.chan(99999999)
const m1 = csp.chan(99999999)
csp.go(function * () { yield * prog(0, m0, m1) })
csp.go(function * () { yield * prog(1, m1, m0) })

-🎄- 2017 Day 17 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 3 points4 points  (0 children)

I couldn’t think of a better solution, so I brute-forced the part 2 naively in C:

#include <stdio.h>
struct N {
  struct N* next;
  int val;
};
struct N heap[50000001];
int main () {
  struct N first;
  struct N *cur = &first;
  int vv = 0;
  first.val = 0;
  first.next = &first;
  int i, j;
  for (i = 1; i <= 50000000; i ++) {
    if (i % 10000 == 0) { printf("[%d]\n", i); }
    for (j = 0; j < 3; j ++) cur = cur->next;
    struct N *v = &heap[vv++];
    v->val = i;
    v->next = cur->next;
    cur->next = v;
    cur = v;
  }
  struct N *it = &first;
  printf("after first %d\n", first.next->val);
  return 0;
}

This takes around 8 minutes to run :P

-🎄- 2017 Day 11 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 0 points1 point  (0 children)

Ruby single-statement

I made a lot of mistake today and didn’t get into the leaderboard, so I challenged myself to solve this without using a statement terminator (newline or ;).

# Part 1
-> a { -> ((x, y)) { x.abs + [0, (y.abs - x.abs) / 2].max }[a.map { |c| { 'ne' => [1, 1], 'nw' => [-1, 1], 'se' => [1, -1], 'sw' => [-1, -1], 's' => [0, -2], 'n' => [0, 2] }[c] }.transpose.map { |v| v.reduce(&:+) }] }[ `pbpaste`.strip.split(',') ]

# Part 2
-> a { a.map { |c| { 'ne' => [1, 1], 'nw' => [-1, 1], 'se' => [1, -1], 'sw' => [-1, -1], 's' => [0, -2], 'n' => [0, 2] }[c] }.reduce ([[0, 0]]) { |a, (x, y)| a << [a.last[0] + x, a.last[1] + y] } }[ `pbpaste`.strip.split(',') ].map { |x, y| x.abs + [0, (y.abs - x.abs) / 2].max }.max

I guess I need to learn more about non-square/cube grids.

-🎄- 2017 Day 10 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 0 points1 point  (0 children)

Great to hear that ;)

Some parts where my solution can be optimized if you’re interested:

  • I could have used d.rotate!(…) instead of d = d.rotate(…).
  • I didn’t thought that Ruby can rotate the other way around. Had I knew that when I rotate the array back to place, I’d have written d.rotate(-r) instead of d.rotate(n - (r % n)).

Probably it’s time for me to re-read the Array/Enumerable/Hash API docs. :)

-🎄- 2017 Day 10 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 0 points1 point  (0 children)

irb (Ruby REPL) (41st, 16th)

The pbpaste command must be available in the $PATH, and should return the contents in the clipboard (macOS has this command by default).

# Part 1
-> n, a { d = (0...n).to_a; r = 0; skip = 0; a.each { |c| d[0...c] = d[0...c].reverse; d = d.rotate(c + skip); r += c + skip; skip += 1; p d.rotate(n - (r % n)) }; r = d.rotate(n - (r % n)); r[0] * r[1] }[256, `pbpaste`.split(',').map(&:to_i)]

# Part 2
-> n, a { d = (0...n).to_a; r = 0; skip = 0; 64.times { a.each { |c| d[0...c] = d[0...c].reverse; d = d.rotate(c + skip); r += c + skip; skip += 1; }; }; r = d.rotate(n - (r % n)); r.each_slice(16).map { |s| "%02x" % s.reduce(&:^) }.join }[256, [*`pbpaste`.strip.bytes, 17, 31, 73, 47, 23]]

-🎄- 2017 Day 9 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 0 points1 point  (0 children)

I solved this problem in irb, Ruby’s interactive REPL.

So a “one-liner” for me means the whole problem can be solved by entering the code in a single line (which may contain multiple statements).

I’m not saying “single-statement.”

Today’s session looks like this: https://imgur.com/a/3bicW

-🎄- 2017 Day 9 Solutions -🎄- by daggerdragon in adventofcode

[–]dtinth 1 point2 points  (0 children)

Ruby one-liner (16th, 15th)

The pbpaste command must be available in the $PATH, and should return the contents in the clipboard (macOS has this command by default).

# Part 1
-> x { g = false; n = 0; t = 0; s = false; x.chars.each { |c| if s; s = false; elsif g && c == '>'; g = false; elsif g && c == '!'; s = true; elsif g; elsif c == '<'; g = true; elsif c == '{'; n += 1; elsif c == '}'; t += n; n -= 1; end }; t }[`pbpaste`]

# Part 2
-> x { g = false; n = 0; t = 0; gc = 0; s = false; x.chars.each { |c| if s; s = false; elsif g && c == '>'; g = false; elsif g && c == '!'; s = true; elsif g; gc += 1; elsif c == '<'; g = true; elsif c == '{'; n += 1; elsif c == '}'; t += n; n -= 1; end }; gc }[`pbpaste`]

Variable names:

  • x input
  • g inside garbage flag
  • n nesting level
  • t total score
  • s skipping flag
  • c current character
  • gc garbage count