Compare commits
3 Commits
9edf9bfb24
...
7d087a80cb
| Author | SHA1 | Date | |
|---|---|---|---|
|
7d087a80cb
|
|||
|
d6175bb84a
|
|||
|
b45a77f76d
|
217
src/game.zig
217
src/game.zig
@@ -1,78 +1,181 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
const Direction = enum {
|
const Direction = enum {
|
||||||
up,
|
up,
|
||||||
down,
|
down,
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
|
|
||||||
|
fn vector(self: Direction) Vec2 {
|
||||||
|
return switch (self) {
|
||||||
|
Direction.up => Vec2{ 0, -1 },
|
||||||
|
Direction.down => Vec2{ 0, 1 },
|
||||||
|
Direction.left => Vec2{ -1, 0 },
|
||||||
|
Direction.right => Vec2{ 1, 0 },
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// x, y
|
/// x, y
|
||||||
const Vec2 = @Vector(2, u32);
|
const Vec2 = @Vector(2, i32);
|
||||||
|
|
||||||
const Element = struct {
|
const State = enum {
|
||||||
position: Vec2,
|
running,
|
||||||
|
lost,
|
||||||
prev: ?Element,
|
won,
|
||||||
next: ?Element,
|
|
||||||
|
|
||||||
pub fn hasPrev(self: Element) bool {
|
|
||||||
return self.prev != null;
|
|
||||||
}
|
|
||||||
pub fn hasNext(self: Element) bool {
|
|
||||||
return self.next != null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const GameState = struct {
|
const Game = struct {
|
||||||
playFieldSize: Vec2,
|
playFieldSize: Vec2,
|
||||||
|
|
||||||
food: Vec2,
|
food: Vec2,
|
||||||
|
direction: Direction,
|
||||||
|
body: std.ArrayList(Vec2),
|
||||||
|
state: State,
|
||||||
|
|
||||||
headDirection: Direction,
|
pub fn createWithSize(allocator: std.mem.Allocator, bodySize: u8) !Game {
|
||||||
|
var body = try std.ArrayList(Vec2).initCapacity(allocator, 1000);
|
||||||
|
|
||||||
head: Element,
|
const startPos: u8 = 10;
|
||||||
tail: Element,
|
for (0..bodySize) |i| {
|
||||||
|
const index = std.math.cast(i32, i) orelse unreachable;
|
||||||
pub fn create() GameState {
|
try body.append(Vec2{ startPos - index, 10 });
|
||||||
const pos1 = Element{
|
|
||||||
.position = Vec2{ 10, 10 },
|
|
||||||
.prev = null,
|
|
||||||
.next = null,
|
|
||||||
};
|
|
||||||
const pos2 = Element{
|
|
||||||
.position = Vec2{ 9, 10 },
|
|
||||||
.prev = pos1,
|
|
||||||
.next = null,
|
|
||||||
};
|
|
||||||
const pos3 = Element{
|
|
||||||
.position = Vec2{ 8, 10 },
|
|
||||||
.prev = pos2,
|
|
||||||
.next = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
pos1.next = pos2;
|
|
||||||
pos2.next = pos3;
|
|
||||||
|
|
||||||
return GameState{
|
|
||||||
.playFieldSize = Vec2{ 20, 20 },
|
|
||||||
.food = Vec2{ 2, 5 },
|
|
||||||
.headDirection = Direction.left,
|
|
||||||
.head = pos1,
|
|
||||||
.tail = pos3,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick() void {}
|
|
||||||
|
|
||||||
fn calculateSnakePositions(self: GameState, allocator: std.Allocator) []Vec2 {
|
|
||||||
var array = std.ArrayList(u8).initCapacity(allocator, 1000);
|
|
||||||
|
|
||||||
var current = self.head;
|
|
||||||
while (current.hasNext()) {
|
|
||||||
array.add(current.position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return Game{
|
||||||
|
.playFieldSize = Vec2{ 20, 20 },
|
||||||
|
.food = Vec2{ 2, 5 },
|
||||||
|
.direction = Direction.right,
|
||||||
|
.body = body,
|
||||||
|
.state = State.running,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(allocator: std.mem.Allocator) !Game {
|
||||||
|
return createWithSize(allocator, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Game) void {
|
||||||
|
self.body.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setDirection(self: *Game, newDirection: Direction) void {
|
||||||
|
if (self.direction == newDirection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headPos = self.body.items[0];
|
||||||
|
const firstBodyPart = self.body.items[1];
|
||||||
|
|
||||||
|
if (std.meta.eql(headPos + newDirection.vector(), firstBodyPart)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.direction = newDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(self: *Game) !void {
|
||||||
|
if (self.state != State.running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newHead = self.body.items[0] + self.direction.vector();
|
||||||
|
if (newHead[0] == 0 or newHead[0] == self.playFieldSize[0] or
|
||||||
|
newHead[1] == 0 or newHead[1] == self.playFieldSize[1])
|
||||||
|
{
|
||||||
|
self.state = State.lost;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.body.items) |pos| {
|
||||||
|
if (std.meta.eql(pos, newHead)) {
|
||||||
|
self.state = State.lost;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.body.insert(0, newHead);
|
||||||
|
_ = self.body.pop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test "should initialize game" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
var game = try Game.create(allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
const actual = game.body.items;
|
||||||
|
const expected = [_]Vec2{ Vec2{ 10, 10 }, Vec2{ 9, 10 }, Vec2{ 8, 10 } };
|
||||||
|
|
||||||
|
try testing.expectEqualSlices(Vec2, &expected, actual);
|
||||||
|
try testing.expectEqual(Direction.right, game.direction);
|
||||||
|
try testing.expectEqual(Vec2{ 20, 20 }, game.playFieldSize);
|
||||||
|
try testing.expectEqual(State.running, game.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "should move down" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
var game = try Game.create(allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
|
||||||
|
game.setDirection(Direction.down);
|
||||||
|
try testing.expectEqual(Direction.down, game.direction);
|
||||||
|
|
||||||
|
try game.tick();
|
||||||
|
const expected = [_]Vec2{ Vec2{ 10, 11 }, Vec2{ 10, 10 }, Vec2{ 9, 10 } };
|
||||||
|
try testing.expectEqualSlices(Vec2, &expected, game.body.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "should not be able to change direction to the previous position" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
var game = try Game.create(allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
|
||||||
|
game.setDirection(Direction.left);
|
||||||
|
try testing.expectEqual(Direction.right, game.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "should loose if exiting playField right" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
var game = try Game.create(allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
|
||||||
|
for (0..10) |_| {
|
||||||
|
try game.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = [_]Vec2{ Vec2{ 19, 10 }, Vec2{ 18, 10 }, Vec2{ 17, 10 } };
|
||||||
|
try testing.expectEqualSlices(Vec2, &expected, game.body.items);
|
||||||
|
|
||||||
|
try testing.expectEqual(State.lost, game.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "should loose if touching tail" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
var game = try Game.createWithSize(allocator, 4);
|
||||||
|
defer game.deinit();
|
||||||
|
|
||||||
|
game.setDirection(Direction.down);
|
||||||
|
try game.tick();
|
||||||
|
game.setDirection(Direction.left);
|
||||||
|
try game.tick();
|
||||||
|
try testing.expectEqual(State.running, game.state);
|
||||||
|
game.setDirection(Direction.up);
|
||||||
|
try game.tick();
|
||||||
|
try testing.expectEqual(State.lost, game.state);
|
||||||
|
|
||||||
|
const expected = [_]Vec2{ Vec2{ 9, 11 }, Vec2{ 10, 11 }, Vec2{ 10, 10 }, Vec2{ 9, 10 } };
|
||||||
|
try testing.expectEqualSlices(Vec2, &expected, game.body.items);
|
||||||
|
|
||||||
|
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" {}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const rl = @import("raylib");
|
const rl = @import("raylib");
|
||||||
|
comptime {
|
||||||
|
_ = @import("game.zig");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() anyerror!void {
|
pub fn main() anyerror!void {
|
||||||
const alloc = std.heap.page_allocator;
|
const alloc = std.heap.page_allocator;
|
||||||
@@ -25,7 +28,3 @@ pub fn main() anyerror!void {
|
|||||||
rl.drawRectangle(10, 10, 10, 10, .black);
|
rl.drawRectangle(10, 10, 10, 10, .black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "should initialize game" {
|
|
||||||
try std.testing.expect(42 == 42);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user