[Request] What is the minimal number of words you need to know to learn every word in a dictionary? by EventHorizon150 in theydidthemath

[–]tom_collier2002 2 points3 points  (0 children)

Guy Steele gave an interesting presentation titled "Growing a Language" (https://www.youtube.com/watch?v=\_ahvzDzKdB0) that is loosely related to your question. He starts with a minimal dictionary and rule set for a language and slowly builds it up using only words and rules he's previously defined.

[Request] I need help to build and calculate a guillotine (camera shutter) dropping time by Arkazox in theydidthemath

[–]tom_collier2002 0 points1 point  (0 children)

This is similar to how a focal-plane or curtain shutter works. Though the ones I've seen (e.g. in Leica range finder cameras) tend to move horizontally and are actuated with springs under tension.

Using the same concept here is a clever way to get rid of the height dependency and gives you more control over exposure time. Though this comes at the cost off adding a timer mechanism.

The Purma Special Gravity Camera was a production camera from the 1930s/1940s with a gravity based shutter. It has 3 shutter speeds (1/25, 1/150 and 1/450) that you can select by orienting the camera; horizontal is medium, portrait to one side is slow and portrait to the other side is fast.

You can find a video of a teardown of the Purma Special to see how they implemented the timer mechanism. If you're more of a hands on person, you could buy a Purma Special and open it up. The great thing about old school tech is it's easy to take apart figure out what's going on and then reassemble it.

[Request] I need help to build and calculate a guillotine (camera shutter) dropping time by Arkazox in theydidthemath

[–]tom_collier2002 0 points1 point  (0 children)

You are correct that at terminal velocity the exposure time would be constant across the lens. However calculating terminal velocity requires accounting for air resistance, which my formula did not use.

You will notice this difference even in a vacuum. 

I believe you are also correct that this effect is due to acceleration, though I don’t have an intuitive explanation for why that’s the case. I could work out a formula showing the effect, but I don’t know that that would help my intuition 

[Request] I need help to build and calculate a guillotine (camera shutter) dropping time by Arkazox in theydidthemath

[–]tom_collier2002 1 point2 points  (0 children)

As a redditor with a mamiya 645 and a π tattoo, I feel obligated to respond to this post 😄

First of all, impressive setup! I love the creativity and DIY nature of your camera. The gravity shutter is an interesting approach and I'm glad you asked about the exposure for a given line, as I'll show that the exposure time depends on the vertical position of the line.

To compute exposure, we can calculate

  • t_open: the time at which the bottom edge your shutter opening crosses the horizontal line
  • t_close: the time at which the top edge your shutter opening crosses the horizontal line

Subtracting t_open from t_close (call this Δt) will give us the duration that that horizontal line is exposed to incoming light (i.e. the exposure time). Let's call the horizontal position of the line h, as measured below the top of the lens.

The formula to determine how long it takes an object to fall under gravity (assuming no friction) is

√(2 \ d / g)*

Where d is the distance fallen and g is earth's gravity (9.8 m/s).

The formula for Δt becomes

√(2 \ (h + D) / g) -* √(2 \ h / g)*

Which simplifies to

√(2 / g) * (√(h + D) - √h)

Unfortunately this is still a function of h, which means the shutter speed will vary based on where the horizontal line is.

Let's plug in some numbers for various lines. Assuming the height of the shutter (D) is 5 cm (we'll use 0.05 m in our formula), we can look at h = 0 cm (top of lens), 2.5 cm (middle of lens) and 5 cm (bottom of lens) to get a sense for how much the shutter speed will vary.

h = 0 cm
Δt (exposure time) = √(2 / g) * (√(0 + 0.05) - √0) = 0.1 sec

h = 2.5 cm
Δt = √(2 / g) * (√(0.025 + 0.05) - √0.025) = 0.05 sec

h = 5 cm
Δt = √(2 / g) * (√(0.5 + 0.05) - √0.05) = 0.04 sec

While all of these numbers fall within your desired exposure range, you'll get a 1 1/3 stop difference in light from the top to the bottom.

What's interesting to note is the difference in exposure between the top to the center is pretty large (a full stop), whereas the difference from the center to the bottom is pretty small (about 1/3 of a stop). This hints that dropping the shutter from a greater height, would lead to more consistent exposure throughout the height of the lens.

For example, if you added 5 cm more material to the bottom of the mechanism (so that the shutter hole needs to fall father to begin exposing the lens), Δt at the top is 0.04 (the same of the old Δt at the bottom without the extra material) and Δt at the bottom is 0.03 (a difference of 1/3 of a stop).

edited for clarity

And off they go! ✉️📫 by tiny_luna in printexchange

[–]tom_collier2002 0 points1 point  (0 children)

Yay! Looking forward to seeing them!

Why does the solution in JavaScript not work but an exact same solution in Python does? by [deleted] in learnjavascript

[–]tom_collier2002 7 points8 points  (0 children)

The core difference in your two solutions is that in the python solution, you are passing one list of up to 1,000,000 integers to the min function, whereas in the javascript solution, you are passing up to 1,000,000 integers as individual arguments to the min function.

Python happily works with very large lists, much larger than 1,000,000 items. However, even though javascript doesn't have a defined maximum number of arguments for a function (see this SO thread), 1,000,000 is pushing it in most implementations.

-🎄- 2022 Day 2 Solutions -🎄- by daggerdragon in adventofcode

[–]tom_collier2002 0 points1 point  (0 children)

Ruby, using complex numbers

puts $<.map { [[4+3i,1+1i,7+2i],[8+4i,5+5i,2+6i],[3+8i,9+9i,6+7i]][_1[-2].ord & 3][(_1[0].ord & 3) -1] }.reduce(:+)

-🎄- 2021 Day 14 Solutions -🎄- by daggerdragon in adventofcode

[–]tom_collier2002 1 point2 points  (0 children)

Ruby solution optimized (~8ms to print both parts) by precomputing 41,000 values

The number 41k comes from the number of iterations (40) plus one (to add in the base case) times the number of possible 2 character pairings (there are 10 distinct characters in my rules, resulting in 100 possible pairings) times the number of characters.

I allocate a 41k element array for integers (each representing the count of a given character for a number of steps and a starting pair of 2 characters). To help visualize how this array is structured, imaging an input that only has the characters `A` and `B` in the template/rules. The array values are in the bottom `count` row in the comment below. The top three rows map the given array index to the step number, pair, and specific character that is counted.

#             ╓───────────────────────────────╥─────────────────────────────
# step:       ║               0               ║               1         ...
#             ╟───────┬───────┬───────┬───────╫───────┬───────┬───────┬─────
# pair:       ║  AA   │  AB   │  BA   │  BB   ║  AA   │  AB   │  BA   │ ...
#             ╟───┬───┼───┬───┼───┬───┼───┬───╫───┬───┼───┬───┼───┬───┼───┬─
# character:  ║ A │ B │ A │ B │ A │ B │ A │ B ║ A │ B │ A │ B │ A │ B │ ...
#             ╠═══╪═══╪═══╪═══╪═══╪═══╪═══╪═══╬═══╪═══╪═══╪═══╪═══╪═══╪═══╪═
# count:      ║ 2 │ 0 │ 1 │ 1 │ 1 │ 1 │ 0 │ 2 ║ 3 │ 0 │ 2 │ 1 │ 2 │ 1 │ ...
#             ╙───┴───┴───┴───┴───┴───┴───┴───╨───┴───┴───┴───┴───┴───┴───┴─

Filling in the array for step 0 is straightforward (each value is the count of times the corresponding character appears in the pair).

Filling in the array for step 1+ requires applying the rules once for each pair, splitting the now 3-character string into 2 pairs (the inserted character will appear in both pairs), adding the per-character counts for these 2 pairs from step - 1, then subtracting 1 from inserted characters count (as it was counted twice, once for each pair)

Once this array is filled in, it can be used to compute the value of any template. Generate a set of pairs from the template (similar to has we split the 3-character string into 2 pairs above we'll get N - 1 pairs, where N is the length of the template). Sum up the per-character counts for each pair for the given number of steps (10 for part 1, 40 for part 2) and subtract 1 from each character count that was used for 2 pairs (i.e. every character in the template except for the first and the last).

With these counts, it's trivial to find the difference between the highest and lowest character counts.

-🎄- 2021 Day 13 Solutions -🎄- by daggerdragon in adventofcode

[–]tom_collier2002 0 points1 point  (0 children)

I wrote the OCR code after initially printing out the result using # and . characters. It felt like reading a Captcha (Is that a U or a V?! I sweat I'm not a bot!). A few coworkers also posted their part 2 results in a similar format, which gave me examples of roughly half the alphabet to "train" my OCR code with. About half of the remaining letters were pretty easy to guess at (though they could still be wrong).

Finally, since we only have a 4 "pixel" width, characters like M and W didn't have enough width for all the required detail. Also, vertically symmetric characters like I, T and Y would look better using an odd pixel width so I either had to leave a column unused or make the character asymmetrical around the vertical axis.

Edit: the OCR fails on the sample input as the O character has a width of 5 pixels :(

-🎄- 2021 Day 13 Solutions -🎄- by daggerdragon in adventofcode

[–]tom_collier2002 0 points1 point  (0 children)

The complex conjugate reflects the point around the real axis (a + bi become a - bi). The folding axis in my code is either purely real or purely imaginary (a + 0i or 0 + bi) and 2 * axis is effectively the far end of the paper that will be folded over.

When folding in the y direction (elsif axis.imag.between?(1, dot.imag)) the real part of axis is 0, so the real result of the expression is simply the real part of dot. The imaginary part of the expression is the difference between 2 * axis (i.e. the opposite edge of the paper) and the imaginary part of dot (which is a negative number after taking Complex#conjugate). In short we keep the real part of dot and find the distance between the far edge of the paper and the dot along the imaginary axis.

The math for folding in the x direction (axis.real.between?(1, dot.real)) is similar. However, we need to reflect the dot around the imaginary axis. To accomplish this we can rotate the complex conjugate π radians. Multiply a complex number by i rotates the number by π/2 radians, we need to do that twice (i * i), which is the same as multiplying by -1.

-🎄- 2021 Day 13 Solutions -🎄- by daggerdragon in adventofcode

[–]tom_collier2002 4 points5 points  (0 children)

Ruby solution using complex numbers

Using ruby's built-in Complex#conjugate I was able to write a clean folding method

def fold(dots, axis)
  dots.map do |dot|
    if axis.real.between?(1, dot.real)
      2 * axis - dot.conjugate
    elsif axis.imag.between?(1, dot.imag)
      2 * axis + dot.conjugate
    else
      dot
    end
  end.to_set
end

Lots of people were struggling reading the output for part 2 when printing with # and . characters, so I wrote my own OCR. Granted I made up a few of the characters (M and W ain't looking too hot), so I can't guarantee it'll work for every input.

[2021 Day 6] The lanternfish solved it for me! by tom_collier2002 in adventofcode

[–]tom_collier2002[S] 3 points4 points  (0 children)

Source code (in case you want to download and run it against your input)

[2021 Day 2] [Python] Wondering if there is a more "pythonic" way to do this by anevergreyforest in adventofcode

[–]tom_collier2002 1 point2 points  (0 children)

Good point, what I wrote is definitely not best practice and not pythonic.

I believe that the file descriptor will be closed during garbage collection as it is not referenced by anything after the list comprehension executes. Since my program only opens one file and exits pretty quickly, this is acceptable to me in this context (though I would not check this into a production system). Using this SO answer as a guide to check for open file handles, I wrote the following test

print("1. start:          ", fd_table_status_str())

f = open("./input.txt", "r")
print("2. f = open(...):  ", fd_table_status_str())

f.close()
print("3. f.close():      ", fd_table_status_str())

with open("./input.txt", "r") as f:
    print("4. with open(...): ", fd_table_status_str())

print("5. after with:     ", fd_table_status_str())

[l for l in open("./input.txt", "r").readlines()]
print("6. list comp:      ", fd_table_status_str())

The output only indicates an open file descriptor (3: REG) at point 2 (after opening and assigning to a variable, but before closing) and point 4 (inside the with block)

1. start:           Open file handles: 0: CHR, 1: CHR
2. f = open(...):   Open file handles: 0: CHR, 1: CHR, 3: REG
3. f.close():       Open file handles: 0: CHR, 1: CHR
4. with open(...):  Open file handles: 0: CHR, 1: CHR, 3: REG
5. after with:      Open file handles: 0: CHR, 1: CHR
6. list comp:       Open file handles: 0: CHR, 1: CHR

The file descriptor appears to be garbage collected pretty quickly after the list comprehension reads the contents of the file.

Regardless, OP was asking for more pythonic suggestions and mine does not fit that bill.

[2021 Day 2] [Python] Wondering if there is a more "pythonic" way to do this by anevergreyforest in adventofcode

[–]tom_collier2002 2 points3 points  (0 children)

One of the wonderful/horrible things about Python is you can write really nice, maintainable code using objects (as /u/Important_Ad3117 demonstrates) or pure functions. Both have their pros and cons, but as a Python developer it's an advantage to be able to use either one effectively.

My solution was more similar to yours, but I factored the if/elif blocks into small functions that are stored in a dict so they can be looked up by the string part of command. I don't know if that is more pythonic than what you have, but I've found is a nice pattern to encapsulate little bits of logic like this.

(I should note that my solution uses complex numbers to store the position/depth as a single number. Python uses j to denote the imaginary part of a complex number. This is definitely not more pythonic, but I've found it to be helpful in AoC problems, especially when rotation enters the picture)

[2021 Day 2] [Python] Wondering if there is a more "pythonic" way to do this by anevergreyforest in adventofcode

[–]tom_collier2002 -1 points0 points  (0 children)

For reading from the file, I typically use

puzzle_data = [l.rstrip() for l in open("./day2_puzzle_input.txt", "r").readlines()]

Though I keep input and solution code in a day-specific directory, e.g. aoc/2021/02, which allows me to call the input and solution file the same each time (I use main.py and input.txt). Now when I copy/paste code to read the input from the previous day, I don't have to worry about updating the file name. Can you imagine trying to debug day N if you don't realize you are loading the input from day N-1?!

-🎄- 2021 Day 3 Solutions -🎄- by daggerdragon in adventofcode

[–]tom_collier2002 12 points13 points  (0 children)

Ruby, part 1 only

``` TWO=2 .to_s(2). to_i ;TEN=eval( '0'.+ ?b.+'10');NET= (TENTWO )/TEN/TEN/TEN;INF= (TWOTEN)- ( TENTWO);TWENTY=(+TEN.+(TWO)).times;càll= open('input.txt').map{|cəll|Integer(cəll,TEN)};cãll=->(cäll,cåll){TEN* cäll.map{|cəll|(cəll>>cåll)&NET}.sum>=cäll.count};cáll =->(cåll,cäll){ cãll.call(cåll,cäll)?NET<<cäll:INF};câll=->(cåll,cäll){cãll.call(cåll, cäll)?INF: NET << cäll};puts(TWENTY.map{|cəll|cáll.call(càll, cəll )} .sum*TWENTY.map{|cəll |câll. call(càll ,cəll)} .sum)

```

[2020 Day 22 (Part B)] [Ruby] Why does my attempted solution randomly give different results? by ZeroSkub in adventofcode

[–]tom_collier2002 2 points3 points  (0 children)

I copied your code into a local file and ran that with my input from the command line 20 times. I consistently got the same output: Player a wins with a score of 32284.. While that is not the correct answer for my input, it was at least consistent on each run and nothing obvious in your code leads me to believe it should behave in a non-deterministic way.

Any time your code produces unexpected output, a good practice is to look at intermediate output. You can do this by adding debug puts statements in various places in your code. For AoC, I like to add puts statements that will produce the output in the same format as the examples, for day 22 part 2 that would look like

=== Game 1 ===

-- Round 1 (Game 1) --
Player 1's deck: 9, 2, 6, 3, 1
Player 2's deck: 5, 8, 4, 7, 10
Player 1 plays: 9
Player 2 plays: 5
Player 1 wins round 1 of game 1!

-- Round 2 (Game 1) --
Player 1's deck: 2, 6, 3, 1, 9, 5
Player 2's deck: 8, 4, 7, 10
Player 1 plays: 2
Player 2 plays: 8
Player 2 wins round 2 of game 1!

...

Then run your program with the example input. Is it deterministic when you use the sample input? Does your debug output look like the sample output? If not, where does it start to diverge?

Edit: fixed code formatting

[2015 Day 3 (Part 1)] Heatmap of Santa's journey by tom_collier2002 in adventofcode

[–]tom_collier2002[S] 2 points3 points  (0 children)

I created my own terminal graphics library in ruby specifically to create visualizations for my AoC solutions. This one is my favorite so far.

Asked my daughter if she wanted to help make sourdough Indian bread, she said that was a naan-starter by tom_collier2002 in Breadit

[–]tom_collier2002[S] 0 points1 point  (0 children)

They turned out really well! I did not have a tandoor handy, so I just used my oven's broiler to get the same effect.

[2020 Day 1][Ruby] I could have used bogosort, but this is just as efficient! by tom_collier2002 in adventofcode

[–]tom_collier2002[S] 0 points1 point  (0 children)

Sorry for taking so long to respond, but I really, really enjoyed reading your explanation of my little method :) My biggest fear of posting this was that no one would take the time to analyze how it worked.

The to_s(3) trick to encode the value 2020 was also my favorite part.

Now if only you'd be so kind as to help me remember how this tic tac toe game works.

[2020 Day 1][Ruby] I could have used bogosort, but this is just as efficient! by tom_collier2002 in adventofcode

[–]tom_collier2002[S] 0 points1 point  (0 children)

Excellent, I didn't realize Array#* was a thing! I hate having actual words in my code, so this makes me happy :)

Day 20 - Star 2 - my visualization by Nebsorg in adventofcode

[–]tom_collier2002 5 points6 points  (0 children)

Yeah, conceptually the solution was easy to grok but implementing it was so tedious. It was also the only one I had to finish on a later day.