#How does one properly handle user-input?

1 messages · Page 1 of 1 (latest)

plain sandal
#

So as a simple exercise to familiarize myself with Zig, I have decided to write a simple game ov hangman.

The first thing I want to do, before anything, is make sure I have a well-functioning user-input system; however, for some reason, my code takes input once and gets stuck printing that, when it is actually supposed to be taking input every loop iteration.

This is my program so far:

const GPAllocConfig = std.heap.GeneralPurposeAllocatorConfig;
const GPAllocator   = std.heap.GeneralPurposeAllocator;
const HangmanGame   = @import("hangman.zig").HangmanGame;
const Reader        = std.fs.File.Reader;
const Writer        = std.fs.File.Writer;
const std           = @import("std");

pub fn main() !void {
  var allocator = GPAllocator(.{}).init;
  defer _ = allocator.deinit();
  
  var stdout_buf:[256]u8 = undefined;
  var stdin_buf:[256]u8 = [_]u8 {0} ** 256;
  
  var stdout:Writer = std.fs.File.stdout().writer(&stdout_buf);
  var stdin:Reader = std.fs.File.stdin().reader(&stdin_buf);
  
  try stdout.interface.writeAll("Welcome to hangman- in Zig!\n");
  try stdout.interface.flush();
  
  var allocating_writer = std.Io.Writer.Allocating.init(allocator.allocator());
  defer allocating_writer.deinit();
  
  while (true) {
    _ = stdin.interface.streamDelimiter(&allocating_writer.writer, '\n') catch { continue; };
    try allocating_writer.writer.flush();
    
    try stdout.interface.writeAll(allocating_writer.written());
    try stdout.interface.writeByte('\n');
    try stdout.interface.flush();
  }
}

If I write "test", it just spams "test" (with a newline).
If I add defer allocating_writer.writer.end = 0 to the loop and write "test", a bunch ov blank lines are printed instead ov what is inputted.

My hypothesis is that the error is related to the buffer contained by allocating_writer.writer, and I am guessing the solution is to clear the buffer, but I am not quite sure what the best way to do that – with respect to the other facets ov the API – is.

sturdy thorn
#

The usual way to print something using writers is to use print

brisk herald
#

"ov hangman" > "of hangman"

sturdy thorn
#

Also, you can send the input of the reader directly to the stdout writer

plain sandal
#

However, I would have the same bug anyway.

#

No?

sturdy thorn
plain sandal
#

Thank you for the correction, though.

#

I appreciate your tentativeness.

sturdy thorn
#

My guess would be probably not though

plain sandal
sturdy thorn
plain sandal
brisk herald
#

it spams "test" because youve told it to write stdin to stdout while true

plain sandal
#

That doesn't explain why it doesn't get new input.

brisk herald
#

oh I see

#

I think it's something to do with streamDelimiter, I think theres another function you have to use

#

I remember having a similar issue a while ago

winged marten
#

it doesnt get new input because you never clear the allocating writer.
you also need to remove the new line from the reader otherwise the next time it tries to read a line it finds it immediately and writes 0 data to the writer.

plain sandal
sturdy thorn
plain sandal
winged marten
#

you can do that with toss(1)

plain sandal
sturdy thorn
plain sandal
sturdy thorn
#

So, it lives in the buffer

plain sandal
#

I see. So, I suppose: what is my code missing?

sturdy thorn
winged marten
# winged marten it doesnt get new input because you never clear the allocating writer. you also ...

you can clear the allocating writer with clearRetainCapacity to reuse the allocation, or clearAndFree if you want it free the allocation.

you remove the delimiter with toss(1), which skips the next n bytes in the buffer.
the \n is never written, thats the problem, the reader still thinks it is un read so it keeps it in the buffer, so the next streamDelimiter immediately finds it resulting in a 0 length line

plain sandal
#

you can clear the allocating writer with clearRetainCapacity
Interesting. I had seen that but didn't know if it was related because it had Capacity, and that threw me off somehow. 🤷

you can clear the allocating writer with clearRetainCapacity to reuse the allocation, or clearAndFree if you want it free the allocation.
Interesting.

plain sandal
# plain sandal

(I am realizing I misread your previous message. - I apologize for that.)

trim leaf
#

I've never had a user for clearAndFree

#

either I want to deinit the array, or keep using it.

#

Now that I think about it, what even use is clearAndFree?

winged marten
#

the capacity is the total size of the allocation, ie it tells the writer how much space it has before it has to reallocate

plain sandal
#

Right.

#

I understand capacity.

#

But I thought it would do something with the capacity.

#

Like how some methods do on resizable types in languages like Rust or Java.

trim leaf
#

When you make an array, it guesses how many slots/memory locations you need. That is the capacity.

winged marten
winged marten
plain sandal
#

I imagine the latter.

#

(If you wanted to do something more interesting.)

winged marten
# trim leaf When you make an array, it guesses how many slots/memory locations you need. Tha...

please use more accurate terminology, in zig an array is fixed size and on the stack.
allocating writer/array list, doesnt guess when you make it. It starts with 0 allocated memory. unless you use initCapacity in which case it doesn't guess it allocates the amount you specify.

when it grows, i wouldnt say it guesses how much you need, rather it basically doubles its size (its a little more complicated), since its pretty reasonable to think if you've needed this much data already you probably need just as much more.

it does have a minimum growth amount, calulated based the element type size, to skip over the small allocations since you probably dont need a dynamic collection if you only have a few things to store.

winged marten
plain sandal
#

I see.

#

Does this look good? It seems to work fine for me:

while (true) {
    defer {
        stdin.interface.toss(1);
        allocating_writer.clearRetainingCapacity();
    }
    
    _ = stdin.interface.streamDelimiter(&allocating_writer.writer, '\n') catch { continue; };
    
    try stdout.interface.print("{s}\n", .{allocating_writer.written()});
    try stdout.interface.flush();
}