diff --git a/src/game.zig b/src/game.zig index 3c1fde3..a367df7 100644 --- a/src/game.zig +++ b/src/game.zig @@ -23,15 +23,21 @@ const Vec2 = @Vector(2, i32); const State = enum { running, lost, - won, }; const Game = struct { playFieldSize: Vec2, - food: Vec2, direction: Direction, body: std.ArrayList(Vec2), state: State, + rng: std.Random.DefaultPrng, + + food: Vec2, + grow: bool, + + pub fn score(self: Game) usize { + return self.body.items.len; + } pub fn createWithSize(allocator: std.mem.Allocator, bodySize: u8) !Game { var body = try std.ArrayList(Vec2).initCapacity(allocator, 1000); @@ -42,12 +48,17 @@ const Game = struct { try body.append(Vec2{ startPos - index, 10 }); } + const seed: u64 = @intCast(std.time.nanoTimestamp()); + const prng = std.Random.DefaultPrng.init(seed); + return Game{ .playFieldSize = Vec2{ 20, 20 }, - .food = Vec2{ 2, 5 }, + .food = Vec2{ 11, 13 }, .direction = Direction.right, .body = body, .state = State.running, + .rng = prng, + .grow = false, }; } @@ -95,7 +106,33 @@ const Game = struct { } try self.body.insert(0, newHead); - _ = self.body.pop(); + if (self.grow) { + self.grow = false; + } else { + _ = self.body.pop(); + } + + if (std.meta.eql(newHead, self.food)) { + // TODO: randomize and check for collisions + self.food = self.getEmptySpace(); + self.grow = true; + } + } + + fn getEmptySpace(self: *Game) Vec2 { + outer: while (true) { + const x = self.rng.random().intRangeLessThan(i32, 0, self.playFieldSize[0]); + const y = self.rng.random().intRangeLessThan(i32, 0, self.playFieldSize[1]); + + const potentialResult = Vec2{ x, y }; + for (self.body.items) |pos| { + if (std.meta.eql(pos, potentialResult)) { + continue :outer; + } + } + + return potentialResult; + } } }; @@ -174,8 +211,26 @@ test "should loose if touching tail" { try testing.expectEqual(State.lost, game.state); } -test "should grow if eating food" {} -test "should win if no space is left" {} -test "should tick if running" {} -test "should fail tick if lost" {} -test "should fail tick if won" {} +test "should grow and spawn new food on ate food" { + const allocator = testing.allocator; + + var game = try Game.create(allocator); + defer game.deinit(); + + try testing.expect(std.meta.eql(game.food, Vec2{ 11, 13 })); + + try game.tick(); + game.setDirection(Direction.down); + try game.tick(); + try game.tick(); + try game.tick(); + + const expected = [_]Vec2{ Vec2{ 11, 13 }, Vec2{ 11, 12 }, Vec2{ 11, 11 } }; + try testing.expectEqualSlices(Vec2, &expected, game.body.items); + try testing.expect(!std.meta.eql(game.food, Vec2{ 11, 13 })); + + try game.tick(); + + const expected2 = [_]Vec2{ Vec2{ 11, 14 }, Vec2{ 11, 13 }, Vec2{ 11, 12 }, Vec2{ 11, 11 } }; + try testing.expectEqualSlices(Vec2, &expected2, game.body.items); +}