Here's a somewhat presentable implementation of part 2 for day 15. it's a bit different from what I described in my previous email, but most of the concepts are the same.
NUM=: '-',~.":i.10 parse=: 0 ". (#~ e.&NUM);._2 prep=: {{ 'S Be'=: _2 j./\ |: (\: 1{"1]) parse y }} mhd=: +/@:|@+.@- edge=: {{ |:(+/,-~/)@+. S(+,.-)j.D=:mhd/prep y }} maybe=: {{~.(j.**&(=<.)**&(0&<)**&(x&>))/(-/,:&,+/)/-:1 _1+"2 y}} filter=: {{ y #~ */D < S mhd/ y }} B=: {{ 4e6#.<.+. filter x maybe edge y }} timespacex'4e6 B input' 0.0143791 723680 'NUM' is characters which I care about: digits, space, the minus sign. 'parse' converts the text of the puzzle into a 4 column array of integers 'prep' further converts that into a row of sensor coordinates and a row of beacon coordinates 'mhd' is manhattan distance Note that I'm representing x,y coordinate pairs as x j. y complex numbers, in 'prep', and I rely on this representation from there on down. ------------------- 'edge' finds the y intercept of the bounding lines corresponding to these sensor/beacon pairs. This array has three dimensions, and one integer for each line. The first dimension is indexed by _1^.slope of the bounding line. (In other words 0 for slope of 1, 1 for slope of _1). The second dimension is indexed by _1^.*y component of becon coordinate - sensor coordinate. (In other words, 0 if the beacon y coordinate is greater than the S y coordinate, _1 if it's less). The final dimension corresponds to the sensor/beacon pair. For example: edge 'Sensor at x=2, y=0: closest beacon is at x=2, y=10;' 12 _8 8 _12 Here, the top two numbers have a positive slope (y increases with x), and the bottom two numbers have a negative slope (y decreases when x increases). The first number of each pair are offset from the sensor in the same direction as the beacon. The second number of each pair is offset in the opposite direction. ------------------- 'maybe' takes these lines and finds points that might be the result we want based on where these lines intersect and which direction the beacon is from the sensor. I add an offset to each y intercept based on its direction from the corresponding sensor, then get potential x coordinates (half of all positive slope values mine half of all negative slope values) and the corresponding potential y coordinates (average of those two values). (I factored out the divide by 2 to happen all at once here). Then I convert these coordinate pairs to complex, forcing obviously invalid values (with non-integer coordinates or where they're outside the search area) to zero, discarding duplicates. A lot of zeros get discarded here (and the remaining zero will be discarded shortly). ------------------- 'filter' discards points which are too close to a sensor. It might be slightly faster if I filtered the result down, one sensor at a time, and I was going to do that (which is why I am assigning the sensor-to-beacon distances to D in 'edge'). But this is probably fast enough already... And, finally, B assembles the result. ------------------- There's a few problem specific quirks here -- for example, I rely on a sensor never having a y coordinate which matches the y coordinate of a beacon. I didn't encounter that issue, so I ignored it as a possibility. So maybe the code itself doesn't entirely make sense. But it was fairly straightforward to put together within these constraints. Anyways, ... maybe this will make sense to someone... Thanks, -- Raul On Thu, Dec 15, 2022 at 3:51 PM Raul Miller <rauldmil...@gmail.com> wrote: > > Yes, after I sent that suggestion, I realized that I could do a better > job of describing the approach. > > So, I sat down and implemented the thing that way. > > My implementation could do with some code cleanup, but as it stands > now, it looks like this performance wise: > > timespacex '4e6 B input' > 0.0232526 1883360 > > This was on a 1.2GHz laptop. > > A rough outline of the code is this: > > (1) Parse the raw text into numbers (four numbers per line), and sort > them (descending order by sensor y value to simplify finding candidate > points). > > (I then combine them in pairs as complex numbers, and work with > coordinates in x j. y format.) > > (2) Find the boundary edges, represent this as a three-column table > slope (1 or _1), y direction from sensor (1 or _1), y intercept > > (3) Find a list of candidate points to consider: > (a) add the y direction to the y intercept to get a y offset > immediately outside the sensor's range > (b) find an intersection point for every pair of edges (difference > of y offsets for x average of y offsets for y) > > There will be duplication here, so toss the duplicates. > > (4) Filter these candidate > (a) discard any candidates with an x or y which is negative > (b) discard any candidates with an x or y which is too large > (c) project each candidate to the y axis using a positive or negative slope > (d) discard any candidate whose positive slope intercept is larger > than the smallest positive slope y intercept for any edge > (e) discard any candidate whose negative slope intercept is smaller > than the largest negative slope y intercept for any edge > > And then: find the Manhattan distance from each remaining candidate to > each sensor and discard those which are too close to any sensor > > Then convert the coordinate to the required index value. > > So, B looked like: > > B=: {{4e6 #.<.+. (x filter candidates) edges y}} > > ('filter' was an adverb with x, m and y as parameters.) > > FYI, > > -- > Raul > > On Thu, Dec 15, 2022 at 1:28 PM Jaume <greenni...@gmail.com> wrote: > > > > I went one way ahead. Increased the range in 1, so the point would be on an > > intersection, fewer points to check. > > > > Ways one could check: > > Go point by point, check if it's the good one. > > Do something like in part 1, checking for an empty space checking line by > > line. > > Check the positions just beyond the range of all the sensors. > > Check around the intersections of the scanning range of all the sensors. > > (your suggestion) > > Check the intersections of an extra range in all the sensors. > > Find sensors with ranges r1 and r2 that are at a distance 1+r1+r2. The > > point should be in the middle. > > > > I implemented them all except the first, last (read about it afterwards) > > and yours. I think they are (roughly) in the correct cpu burning level > > (first the ones that require more computation). > > I had the right point from my 2nd test, but I had a bad calculation. > > > > Missatge de Raul Miller <rauldmil...@gmail.com> del dia dj., 15 de des. > > 2022 a les 19:04: > > > > > I think your approach here, with a slight change, would be superior to > > > the approach I used. > > > > > > In other words, treat the problem as defining a small set of lines > > > bounding the scannable regions. These will all be diagonal lines, > > > though they'll have two different orientations. > > > > > > The point you're looking for has to be adjacent to an intersection of > > > two of those lines. > > > > > > -- > > > Raul > > > > > > On Thu, Dec 15, 2022 at 9:22 AM Jaume <greenni...@gmail.com> wrote: > > > > > > > > Hello all > > > > > > > > Once again with questions, now more on the performance side, mostly > > > because > > > > it's taking too long, and giving me a wrong answer some of the time. > > > > > > > > Talking about part 2. I'll share all of the code, so if you see anything > > > > glaringly wrong please let me know. > > > > read=:{{cutopen 1!:1 <y}} > > > > filter=: 0". 'Sensoratx=,y:clbi'-.~] > > > > init=: 3 : 0 > > > > map=:>filter each read y > > > > sensors=:0 1 {"1 map > > > > beacons=: 2 3{"1 map > > > > $map > > > > ) > > > > With init 'filename' we set up the rest. > > > > In case you don't know we have to find the point thats outside the range > > > of > > > > all the sensors and still inside 0...4000000 in both coordinates. > > > > Let's go to the last approach I took. > > > > sol2=: 4 : 0 > > > > NB. range occ sensor,beacon > > > > cx=:x > > > > cy=:y > > > > sensors= 0 1 {"1 y > > > > beacons= 2 3 {"1 y > > > > distances=:1+sensors d"1 beacons > > > > param=:sensors,.((#distances), 1)$distances > > > > digs=:x diag"1 param > > > > dg=:digs > > > > for_i. i.#digs do. > > > > here=:testdiag dg > > > > if. here do. > > > > ccx=:{.here > > > > ccy=:{:here > > > > ccx,ccy,ccy+ccx*400000 return. > > > > end. > > > > dg=:}.dg > > > > end. > > > > 'none' > > > > ) > > > > d=:[:+/[:|- > > > > union=: ~.@, > > > > unboxedunion=:([: > [) union [: > ] > > > > intersect=: e. # [ > > > > remx=:([ >: [: {."1 ]) *. [ >: [: {:"1 ] > > > > rem0=:(0 <: {."1) (*.) 0 <: {:"1 > > > > remove=: 4 : 0 > > > > mask=:rem0 y > > > > mask=:mask*.x remx y > > > > (>mask)#y > > > > ) > > > > diag=: 4 : 0 > > > > cx=:x > > > > cy=:y > > > > range=:i.>:{:y NB. [2]->3->0 1 2 > > > > egnar=:i.->:{:y NB. [2]->-3->2 1 0 > > > > px=:0{y > > > > py=:1{y > > > > NB. (x-d,y)->(x,y+d) > > > > NB. (x,y+d)->(x+d,y) > > > > NB. (x+d,y)->(x,y-d) > > > > NB. (x,y-d)->(x-d,y) > > > > d1=:(px-egnar),.(py+range) > > > > d2=:(px+range),.(py+egnar) > > > > d3=:(px+egnar),.(py-range) > > > > d4=:(px-range),.(py-egnar) > > > > <~.x remove d1,d2,d3,d4 > > > > ) > > > > testpoint=: 3 : 0 > > > > dc=:1 y&d"1\sensors > > > > *./dc>:distances > > > > ) > > > > testdiag=: 3 : 0 > > > > excl=: }.y > > > > rest=:]F.:unboxedunion excl > > > > interest=:rest intersect > {.y > > > > for_i. i.#interest do. > > > > val=:testpoint i{interest > > > > if.val do. > > > > i{interest return. > > > > end. > > > > end. > > > > 0 > > > > ) > > > > > > > > So I create the limits that are just outside the range of each sensor, > > > > intersect those, examine if the points have all the distances greater > > > than > > > > the distance each sensor reaches, and if so that's the point. > > > > On the test it's blazingly fast: > > > > > > > > 20 sol2 map > > > > > > > > 14 11 5600011 > > > > > > > > But on the real data it's amazingly slow... and according to AoC also > > > wrong. > > > > > > > > 4000000 sol2 map > > > > > > > > 3270298 2638237 1308121838237 NB. too low!!!! > > > > But.. AFAIK this answers checks the marks: > > > > > > > > |: dc > > > > > > > > 4298885 1215898 1684048 845656 3691920 1327934 1042406 682945 599242 > > > > 3471784 3639831 841599 1106070 4582032 3552311 2682122 967943 845585 > > > > 1809437 1835842 1806964 962164 663951 532696 2570491 706217 654163 > > > 1476664 > > > > 2198682 1669886 4144166 985137 1181113 4234... > > > > > > > > distances N.B. 1+ real distance > > > > > > > > 1595477 33564 434944 166994 803986 656108 285496 682945 599242 1465583 > > > > 700194 171415 143036 1694098 1742449 1433018 121373 226445 1150021 > > > > 945766 > > > > 479064 383562 663951 429356 453359 185151 654163 455680 1350302 860094 > > > > 178581 92581 67993 126159 1178851 325282... > > > > > > > > |: dc>:distances > > > > > > > > 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 > > > 1 1 > > > > 1 1 > > > > > > > > > > > > So now I'm lost. I can't see the error and it's too slow to try new > > > > alternatives. > > > > > > > > > > > > I'm attaching my input, but do not give me the numeric answer please, > > > that > > > > would be trivial using any already working solution. > > > > > > > > Can you spot the error and or help me make this go faster? > > > > > > > > Thanks. > > > > ---------------------------------------------------------------------- > > > > For information about J forums see http://www.jsoftware.com/forums.htm > > > ---------------------------------------------------------------------- > > > For information about J forums see http://www.jsoftware.com/forums.htm > > > > > > > > > -- > > The fact that an opinion has been widely held is no evidence whatever that > > it is not utterly absurd. -- Bertrand Russell > > ---------------------------------------------------------------------- > > For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm