5 kyu
Blobservation 2: Merge Inert Blobs
38 of 88docgunthrop
Loading description...
Arrays
Algorithms
View
This comment has been reported as {{ abuseKindText }}.
Show
This comment has been hidden. You can view it now .
This comment can not be viewed.
- |
- Reply
- Edit
- View Solution
- Expand 1 Reply Expand {{ comments?.length }} replies
- Collapse
- Spoiler
- Remove
- Remove comment & replies
- Report
{{ fetchSolutionsError }}
-
-
Your rendered github-flavored markdown will appear here.
-
Label this discussion...
-
No Label
Keep the comment unlabeled if none of the below applies.
-
Issue
Use the issue label when reporting problems with the kata.
Be sure to explain the problem clearly and include the steps to reproduce. -
Suggestion
Use the suggestion label if you have feedback on how this kata can be improved.
-
Question
Use the question label if you have questions and/or need help solving the kata.
Don't forget to mention the language you're using, and mark as having spoiler if you include your solution.
-
No Label
- Cancel
Commenting is not allowed on this discussion
You cannot view this solution
There is no solution to show
Please sign in or sign up to leave a comment.
[ [4,0,0,6,0,8] ] -> 'E' result in [ [18] ]
while[ [9,4,6] ] -> 'E' results in [ [0,9,10] ]
?For instance, how would
[ [2, 4, 5] ] -> 'E' result to
?[ [0, 6, 5] ]
?[ [0, 0, 11] ]
?Once again, a excellent Kata from @docgunthrop... Thanks!
javascript- This example. [0,9,10], [8,8,8], [0,0,18] "S" [0,9,10], [8,8,26]
shouldnt result be [0,9,10], [8,8,0] [0,0,26] as "S" moves downwards. 8 merges with 18 downwards and stays there. why does it go 26 to the middle?
Because only rows 1 & 2 are reported. Row 0 becomes [0,0,0] after 'S', and the instructions state that the smallest possible array is reported where any row or col has any element > 0.
This comment has been hidden.
Nice Kata! I figured I'd do this one before attempting Blobservation because that is rated as more difficult, however I was rather surprised at the complexity of this one (getting it to run in roughly O(N) time wasn't quite as trivial as I assumed). The 5 kyu rating for this kata surprised me, compared to other 5 kyu problems. Oh well, off to the next!
I really like this Kata, however there is a small minor point that I found a little bit unclear. If you input a string like "NE", do the blobs move North one step and then east or do they move in a north easterly (diagonal) direction ? I suspect it moves North one step and then east, however it would be great if you could update the question to make it absolutely clear what happens.
While it could be added that only the four 'main' directions are possible, I think the other interpretation doesn't really make sense anyway. If 'NE' would make them move in a north easterly direction, then how would someone compute 'NNESEWWNW'?
Needs updated to Rust 1.49.
Updated
I made this kata even though I recently thought it was impossible. Thanks!
Awesome kata. Definitely worth doing.
This comment has been hidden.
Which one? (btw, I didn't downvote you. You were at -1 when I saw your comment)
Just my own problem,Nothing to do with others. You don’t need to pay attention, I just express my feelings after finishing the kata.
Reserved translations to come:
Want Haskell?
Haskell translation
That one is good.
Approved 🖖
Mention your anti-cheat !!
I was having major problems with
class Blobservation extends Array
; could not figure out where that came from, and ultimately gave up on that idea.I can't even be sure the anti-cheat was the problem, because stuff fails silently with all the fiddling you're doing.
Please, if you fiddle with JS internals, mention such in the description. You don't have to specify every little change, but a general warning means I'll have the idea to test in a pristine environment.
Hi Johan, can you post some barebones code of what you were trying to do? (with spoiler tag, of course)
Was the error you got:
Must call super constructor in derived class before accessing 'this' or returning from derived constructor
?I can look into this and make some edits but some clues would be helpful. If you're on gitter you can DM me the code as well, which would be even better.
I could post the code, though I'd have to recreate it.
That was not the error. I'd have to recreate the exact error. It was weird - something about an
@@iterator
- as if aBlob
was not anArray
despite the inheritance.I'm not asking to lift restrictions until my code would work. I am asking to mention the fact that there are restrictions at all.
I can just do a fork with the
class Blobservation extends Array
thing without the restrictions ( I hope. if the problem was the restrictions after all ). That will give you the code as well, but again, I'm not asking for lifting restrictions. I see the use of restrictions; I'm just wary of having to code with restrictions I don't know. ( I tend to use some valid features other people probably won't, and that might also be used for cheating. )Let me get on that fork.
I forked my solution twice, once with massive breakage ( and the debug logging to show it ), and once without (?!?), because
Blob.map(fn)
barfs, butArray.from(blob,fn)
works as expected.In summary: it's not the anti-cheat. If anything, it's the argument format: I have terrible difficulty getting
new Blob([...grid])
to work; based on separate testing,new Blob(...grid)
would work just fine ( that is nativenew Array
argument formatting ).I wouldn't worry too much about dialing back the anti-cheat - but I still consider it an
Issue
to have it existing at all in secrecy.Also, JS is weird.
Thanks for your input, Johan. I'll leave the issue up so nobody accidentally approves the kata. In the meantime, I'll look into making some tweaks that address the issue (without invalidating the already submitted solutions).
Ok, so I had a chance to test out your code. Confirming that it's not the anti-cheat that is causing the issues; I disabled all anti-cheats, ran your 2nd fork solution (which, if I'm not mistaken, is the solution you initially attempted) on just the sample tests and got the following error message:
TypeError: Found non-callable @@iterator
Also, a note was added to the Description stating that
Object
andObject.prototype
are frozen.Array
is frozen, butArray.prototype
is not. However, the existing methods onArray.prototype
are not configurable nor writable, so, while new methods can be added toArray.prototype
, existing methods cannot be altered. This should resolve the issue.Having the functionality in a
class
adds nothing. A class is useful when there is state, but there is no state. Having an input as the state adds nothing but boilerplate.You could just as easily ask for a function
slide(grid,instructions)
which returns a new grid.Actually,
slide(grid,instruction)
( note single instruction ) would allowslide(grid,instructions) = instructions.reduce(slide,grid)
, so even handling multiple instructions doesn't add much of anything.I'd suggest asking for
slide(grid,instruction)
.Having the functionality in a class allows for greater flexibility in some cases.
For example (in JS):
A user does not need restrict themselves to an array as a data structure, much less an
m x n
array. Actually, I'm glad you brought this up because it reminded me to make some updates to the tests.I'm going to mark this suggestion as resolved, but I'm open to continuing this discussion for the sake of improving the kata.
new Blob(grid).read("NES").read("WW").read("NWNSE")
?That would be the functionally identical to
read(read(read(grid,"NES"),"WW"),"NWNSE")
though, and that can be reduced to["NES","WW","NWNSE"].reduce(read,grid)
. But that's functional instead of OO, which is a valid choice not to make.["NES","WW","NWNSE"].reduce( (grid,tilt) => grid.read(tilt) , grid )
would reduce the OO form. I like the functional form better, and it's shorter, but I'll grant most people would write the OO form.The first line can evaluate to a
Blob
which can have avalueOf()
that returns anArray
. It might even be aBlob
that inherits from anArray
, effectively being anArray
. ( I was trying to achieve this at first. ) It might even strictly be anArray
if we define a mutating methodArray.prototype.read
. ( And that might go explicitly against your restrictions - though it might not either. )Internal representation would not be fixed, neither with
read(grid,tilt)
nor withgrid.read(tilt)
; you could use anything that takes your fancy. Even if you internally represent as anArray
, but not asm x n
, you could still usevalueOf
to externally present as anm x n Array
.In the case of
class Blob extends Array
you are simply optimising for this external presentation but in doing so fixingArray
( andm x n
) internally as well. A differentBlob
might not extendArray
, or even its external representation, if that's not convenient, but thisBlob
can be written to this kata's specs.It seems to boil down to a preference of functional vs. object-oriented. There doesn't seem to be a compelling reason against the latter approach, so I'll just leave it as is.
Aside from that, some minor additions have been made:
state
is called again@JohanWiltink In haskell, this typechecks
Should there really be a typeclass in the initial code? Keeping in mind that a) it has no effect and can be deleted without any other changes as per above code b) haskell's typeclass isn't the same concept as javascript/whatever's class, sharing only the word "class". in terms of Rust, there are classes and traits, and a typeclass is a trait, not a class
It's wrapping things up in a class to no benefit. Three methods are asked for, but the kata only describes one significant action:
(Grid, Direction) -> Grid
It's not object-oriented, it's wrapped up in do-nothingness.
The benefit is not changing the description.
Also, I don't speak Rust, and I agree with you guys.
Haven't you ever done useless things before, because your sensei, for no good reason, asked for it ?
Sorry, I'm talking about two things.
One of them is that I agree with you on that the class isn't doing anything in a language-agnostic sense.
The other is that haskell typeclasses are unrelated to classes. If we were to get closer to having a mutable blob with sequenced actions then that would be involving monads (writer monad?) But this isn't a 3-2kyu kata so that doesn't fit, it's already one of the hardest 5kyu katas. And also it would be super contrived since there's only one significant action, not three, but the other languages already have that problem.
I agree with you. Doc doesn't - see above.
And rankings can't be changed ( except when they can ).
@natan - This kata was written for languages that support the OO-paradigm. The Haskell translation was requested by the translator and it was accepted (as long as it adhered to the intent of the kata so as to maintain consistency). If you take issue with the implementation of the Haskell translation, then that's a conversation to be had with the translator. As for Rust, it uses structs, which would be the equivalent of a class in other languages.
@JohanWiltink - we've had an extensive conversation about this before where I commented:
It sounds like @natan is talking about the very things I mentioned.
That's just what happens when you specify implementation instead of ( or in addition to ) behaviour. And I don't think that's a problem, actually.
It can be done differently in JavaScript as well, and the black boxes would also behave the same.
It's not so much hammering a round peg into a square hole as it is doing it with the back of an axe, or with the back of a screwdriver. But it will put the peg in the hole.
Okay. Thank you for being willing to respond to this and filling me in despite having already been there.
@docgunthrop if @johan is willing, could we drop the typeclass in the initial haskell code?
The task isn't about calling convention! Is it? It's about blobs sloshing around. And it would still be the case that the user defines some object of undefined shape that has three operations.
I understand that you might have been reaching for something involving sequencing these operations, but that isn't what you caught when you closed your fist. There's an input operation, and an output operation, and a do-something operation. This is already how a function behaves. There's input, something happens, there's output. This is morally a single function. Both me and Johan implemented the input and output functions as identity functions
(x) => x
for this reason.I'm harsh, I'm sorry. I do want this very nice puzzle to be lifted out to the front.
You could use something else as input and output functions, and have a different internal representation. Then you'd have all three operations actually doing work. The API is defined to have three operations. It could have specified some external format you didn't want as an internal format, and it's no more than a lucky coincidence it didn't.
If the input / output format had been specified as a separated or unseparated one-dimensional list ( and a separate width in case of no separators ), would you have worked with the external format as the internal format? I think you'd have felt fortunate to have the possibility to remodel your data.
You're comparing this to something like
Vector.fromList
,Vector.reverse
,Vector.toList
It fits the description without the typeclass. If it goes poof it looks a lot less scary and makes all sorts of sense. Test code stays 99% same (remove the import of Blobservation)Yes? Yes.
Hi doc,
It seems there might be something wrong in your ref solution. That or some explanations are missing from the description, I believe:
tho, from what I can grasp of the description (which is a bit convoluted, since you essentially rely on the examples to actually give hint about the underlying logic... Not really fond of that... ;/ )
Other than that, two suggestions:
printState
rather begetState
orcurrentState
? (nothing is printed and the output isn't a string)cheers, B4B
Makes sense; I'll make some updates to the kata. Putting it back in Draft in the meantime.
There was a tiny bug in the reference solution but it should be fixed now.
Other changes:
printState
method renamed tostate
Let me know your thoughts on the updates, thanks!
To address the following:
Within a common
describe
block,it
blocks execute beforedescribe
blocks regardless of order. Changing the order in the sample tests might add confusion so it was left as is.:+1: issue resolved.
about the sample tests, why not separate the describe blocks at the top level?
I'll probably update the sample tests since they don't affect the submitted solutions. Thanks for giving this one a shot!
EDIT: updated sample tests; now there are two separate
describe
blocks and now the unit tests precede the integration tests.After
E
:After
W
:Where I could be wrong?
Ok, I'll take some time to check this. Thanks for mentioning this; temporarily reverting back to Draft for the moment.
Should be fixed now; can you give it another try?
Thanks for a cool kata.
Thanks for trying it out 🖖