const Cache = std.ArrayList([]CardType);
const RecursiveCombat = struct {
p1: std.ArrayList(CardType),
p2: std.ArrayList(CardType),
p1prev: Cache,
p2prev: Cache,
fn play(self: *@This(), allocator: std.mem.Allocator) anyerror!u1 {
if (self.p2.items.len == 0) {
return 0;
}
if (self.p1.items.len == 0) {
return 1;
}
// Infinite check
for (self.p1prev.items) |item| {
if (std.mem.eql(CardType, item, self.p1.items)) return 0;
}
for (self.p2prev.items) |item| {
if (std.mem.eql(CardType, item, self.p2.items)) return 0;
}
// Add current decks to previous decks
const tmp1 = try self.p1.clone();
const tmp2 = try self.p1.clone();
defer tmp1.deinit();
defer tmp2.deinit();
try self.p1prev.append(tmp1.items);
try self.p2prev.append(tmp2.items);
// Start the round with drawing
const p1 = self.p1.orderedRemove(0);
const p2 = self.p2.orderedRemove(0);
var winner: ?u1 = null;
// Check recursion
if (p1 <= self.p1.items.len and p2 <= self.p2.items.len) {
var rc = RecursiveCombat{
.p1 = try std.ArrayList(CardType).initCapacity(allocator, p1),
.p2 = try std.ArrayList(CardType).initCapacity(allocator, p2),
.p1prev = Cache.init(allocator),
.p2prev = Cache.init(allocator),
};
defer {
rc.p1.deinit();
rc.p2.deinit();
rc.p1prev.deinit();
rc.p2prev.deinit();
}
rc.p1.appendSliceAssumeCapacity(self.p1.items[0..p1]);
rc.p2.appendSliceAssumeCapacity(self.p2.items[0..p2]);
winner = try rc.play(allocator);
}
// Without recursion winner is null, set it
if (winner == null) {
if (p1 > p2) winner = 0 else winner = 1;
}
if (winner.? == 0) {
try self.p1.append(p1);
try self.p1.append(p2);
} else {
try self.p2.append(p2);
try self.p2.append(p1);
}
return try self.play(allocator);
}
};