Understanding the Verilog Stratified Event Queue
You are correct in saying that the non-blocking assignment(NBA) and continuous  assignment(CA) act like two-step processes, because they are. The problem is what you are calling "the next time-step" is not an advance in time; it is an iteration of the while() loop without advancing time. This is usually referred to as a delta-step. 

When using an NBA, the LHS gets scheduled as an NBA update event, but right after that, the $display is the next active event to execute. It prints the value of y before the NBA update events have a chance to execute. As soon as you introduce a delay, the NBA has a chance to execute before advancing to the next event time.

When using a CA, you are creating a separate process that activates anytime the RHS changes it makes an assignment to the LHS in the same active region. The initial and CA are two independent processes, and the ordering between statements in the active region is non-deterministic. So whether you see the old uninitialized value of y of updated value of y is a race condition. And you will see differences between simulators depending on how they optimize this code.