From 777e07035b8c36b9189ecf0bae09b6c139f72dcb Mon Sep 17 00:00:00 2001 From: Nathan Anderson Date: Fri, 5 Jul 2024 08:49:59 -0600 Subject: [PATCH] WIP deck methods, added flake, and setup build deps --- .envrc | 1 + .gitignore | 3 + build.zig | 73 ++++++++ build.zig.zon | 17 ++ flake.lock | 92 ++++++++++ flake.nix | 27 +++ nix/zls/flake.lock | 26 +++ nix/zls/flake.nix | 34 ++++ src/deck.zig | 437 +++++++++++++++++++++++++++++++++++++++++++++ src/main.zig | 6 + 10 files changed, 716 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/zls/flake.lock create mode 100644 nix/zls/flake.nix create mode 100644 src/deck.zig create mode 100644 src/main.zig diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0f7a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.direnv/** +.zig-cache/** +zig-out/** diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..6132fb8 --- /dev/null +++ b/build.zig @@ -0,0 +1,73 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{ + .whitelist = &[_]std.Target.Query{ + std.Target.Query{ .cpu_arch = .aarch64, .os_tag = .macos }, + std.Target.Query{ .cpu_arch = .x86_64, .os_tag = .linux }, + }, + }); + + // TODO + // Prefer small size binaries for optimization + const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .Debug }); + + const exe = b.addExecutable(.{ + .name = "genius_deck", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + // Add zap dependency + const zap = b.dependency("zap", .{ + .target = target, + .optimize = optimize, + .openssl = false, + }); + exe.root_module.addImport("zap", zap.module("zap")); + b.installArtifact(exe); + + // Create Check step for zls + const exe_check = b.addExecutable(.{ + .name = "zerver", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + exe_check.root_module.addImport("zap", zap.module("zap")); + const check = b.step("check", "Check if project compiles, used by Zig Language Server"); + check.dependOn(&exe_check.step); + + // Create Run Step + const run_cmd = b.addRunArtifact(exe); + + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Create Test Step + const lib_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }); + + const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_lib_unit_tests.step); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..5471b46 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,17 @@ +.{ + .name = "genius_deck", + .version = "1.0.0", + .minimum_zig_version = "0.13.0", + .dependencies = .{ + .zap = .{ + .url = "https://github.com/zigzap/zap/archive/refs/tags/v0.8.0.tar.gz", + .hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + "README.md", + }, +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..d7fd53e --- /dev/null +++ b/flake.lock @@ -0,0 +1,92 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1719690277, + "narHash": "sha256-0xSej1g7eP2kaUF+JQp8jdyNmpmCJKRpO12mKl/36Kc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2741b4b489b55df32afac57bc4bfd220e8bf617e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1719942202, + "narHash": "sha256-7sP4PzxRsUfRwN8rmFtRvU/nYqTI5YYeIG9P3KJV41g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4b015946c99a5bbe9c7a685e66f165aa44644b7d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "zlsPkg": "zlsPkg" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "zlsPkg": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1, + "narHash": "sha256-5LNEr6ek90U0PwmUjyZta4lCB93maBUr86ikbiwSsoU=", + "path": "./nix/zls", + "type": "path" + }, + "original": { + "path": "./nix/zls", + "type": "path" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b0acde4 --- /dev/null +++ b/flake.nix @@ -0,0 +1,27 @@ +{ + description = "An example project using flutter"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.zlsPkg.url = "path:./nix/zls"; + outputs = { + flake-utils, + nixpkgs, + zlsPkg, + ... + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + }; + zls = zlsPkg.defaultPackage.${system}; + in { + devShell = pkgs.mkShell { + buildInputs = with pkgs; [ + lldb + sqlite + zig + zls + ]; + }; + }); +} diff --git a/nix/zls/flake.lock b/nix/zls/flake.lock new file mode 100644 index 0000000..188887d --- /dev/null +++ b/nix/zls/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1719942202, + "narHash": "sha256-7sP4PzxRsUfRwN8rmFtRvU/nYqTI5YYeIG9P3KJV41g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4b015946c99a5bbe9c7a685e66f165aa44644b7d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/zls/flake.nix b/nix/zls/flake.nix new file mode 100644 index 0000000..64c1ab2 --- /dev/null +++ b/nix/zls/flake.nix @@ -0,0 +1,34 @@ +{ + description = "Zig language server"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = {self, nixpkgs}: { + defaultPackage.x86_64-linux = + with import nixpkgs { system = "x86_64-linux"; }; + + stdenv.mkDerivation rec { + name = "zls-${version}"; + version = "0.13.0"; + src = pkgs.fetchurl { + url = "https://github.com/zigtools/zls/releases/download/${version}/zls-x86_64-linux.tar.xz"; + sha256 = "sha256-7EwbRcr4jivLnrsWxnBgPMWW5PYhuWGE376DeznNhBA="; + }; + + sourceRoot = "."; + + installPhase = '' + install -m755 -D zls $out/bin/zls + ''; + + meta = with lib; { + homepage = "https://github.com/zigtools/zls/releases"; + description = "Zig language server"; + platforms = platforms.linux; + }; + # I still lack stuff here! + }; + }; +} diff --git a/src/deck.zig b/src/deck.zig new file mode 100644 index 0000000..70c8394 --- /dev/null +++ b/src/deck.zig @@ -0,0 +1,437 @@ +const std = @import("std"); +const assert = std.debug.assert; + +pub const DeckError = error{ + DuplicateDiscard, + Overflow, +}; + +pub const Card = struct { suite: Suit, faceValue: Face }; + +pub const Suit = enum(u4) { Diamonds = 0, Clubs = 1, Hearts = 2, Spades = 3 }; + +pub const Face = enum(u4) { + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, + Eight = 8, + Nine = 9, + Ten = 10, + Jack = 11, + Queen = 12, + King = 13, + Ace = 14, +}; + +comptime { + if (@typeInfo(Suit).Enum.fields.len != 4) { + @compileError("Only four suites allowed"); + } + if (@typeInfo(Face).Enum.fields.len != 13) { + @compileError("Only 13 face cards permitted"); + } +} + +const NUM_SUITES = @typeInfo(Suit).Enum.fields.len; +const NUM_CARDS_IN_SUITE = @typeInfo(Face).Enum.fields.len; +const MAX_CARDS = NUM_SUITES * NUM_CARDS_IN_SUITE; +const CARD_STRUCT_SIZE = @sizeOf(Card) / 2; + +/// A Bounded Array with a fixed size to fit 52 `Card` structs inside it. +/// Requires no allocations because of the fixed max size known at compile time. + +// pub fn printCards(cards: CardSlice, options: bufPrintCardOptions) void { +// std.debug.print("Deck with {d} cards\tBuf len: {d}\n", .{ cards.len, cards.buffer.len }); +// std.debug.print("--- Bottom of Deck ---\n", .{}); +// var buf: [18]u8 = undefined; +// for (0..cards.len) |cardIdx| { +// const card = cards.get(cardIdx); +// std.debug.print(" - {d}: {s}\n", .{ cardIdx, bufPrintCard(card, &buf, options) }); +// } +// std.debug.print("--- Top of Deck ---\n", .{}); +// } + +pub fn printDeck(deck: Deck, options: bufPrintCardOptions) void { + std.debug.print("Deck with {d} cards\n", .{deck.num_cards}); + std.debug.print("--- Bottom of Deck ---\n", .{}); + var buf: [18]u8 = undefined; + for (0..deck.num_cards) |cardIdx| { + std.debug.print(" - {d}: {s}\n", .{ cardIdx, bufPrintCard(deck.cards[cardIdx], &buf, options) }); + } + std.debug.print("--- Top of Deck ---\n", .{}); +} + +pub const bufPrintCardOptions = struct { + use_icon: bool = true, +}; +/// Returns a string representation of the card in the `buffer` +pub fn bufPrintCard(card: Card, buffer: []u8, options: bufPrintCardOptions) []const u8 { + // std.debug.print("\n\t{any}", .{card}); + const fv = @tagName(card.faceValue); + const icon = if (options.use_icon) suiteToIcon(card.suite) else @tagName(card.suite); + return std.fmt.bufPrint(buffer, "{s} of {s}", .{ fv, icon }) catch return "*err printing card"; +} + +fn suiteToIcon(s: Suit) []const u8 { + return switch (s) { + .Spades => "󰣑", + .Hearts => "", + .Clubs => "󰣎", + .Diamonds => "󰣏", + }; +} + +pub const Deck = struct { + num_cards: u8 = 0, + num_discards: u8 = 0, + cb1: [MAX_CARDS]Card = [_]Card{Card{ .suite = .Diamonds, .faceValue = .Two }} ** MAX_CARDS, + cb2: [MAX_CARDS]Card = [_]Card{Card{ .suite = .Diamonds, .faceValue = .Two }} ** MAX_CARDS, + cards: []Card = undefined, + discard_pile: []Card = undefined, + + pub fn init(self: *Deck) DeckError!void { + // var cardBuf = [_]Card{Card{ .suite = .Diamonds, .faceValue = .Two }} ** MAX_CARDS; + self.cards = &self.cb1; + // var discardBuf = [_]Card{Card{ .suite = .Diamonds, .faceValue = .Two }} ** MAX_CARDS; + self.discard_pile = &self.cb2; + // Construct the deck + for (0..NUM_SUITES) |suiteIdx| { + const suite: Suit = @enumFromInt(suiteIdx); + for (0..NUM_CARDS_IN_SUITE) |f| { + const faceIdx = NUM_CARDS_IN_SUITE - f + 1; + const face: Face = @enumFromInt(faceIdx); + self.cards[self.num_cards] = Card{ .suite = suite, .faceValue = face }; + self.num_cards += 1; + } + } + assert(self.num_cards == MAX_CARDS); + } + + pub fn deal(self: *Deck) ?Card { + if (self.num_cards == 0) return null; + self.num_cards -= 1; + return self.cards[self.num_cards]; + } + + pub fn peak(self: *Deck) ?Card { + if (self.num_cards == 0) return null; + return self.cards[self.num_cards - 1]; + } + + pub fn discard(self: *Deck, card: Card) DeckError!void { + // Check a duplicate isnt introduced + for (0..self.num_discards) |discardIdx| { + if (std.meta.eql(self.discard_pile[discardIdx], card)) { + return DeckError.DuplicateDiscard; + } + } + self.discard_pile[self.num_discards] = card; + self.num_discards += 1; + } + + pub fn rebuild(self: *Deck) DeckError!void { + const newTotal = self.num_cards + self.num_discards; + assert(newTotal <= MAX_CARDS); + + for (0..self.num_discards) |disIdx| { + self.cards[self.num_cards + disIdx]; + self.num_cards += 1; + } + self.num_discards = 0; + assert(self.num_cards == newTotal); + + try sort(self.cards); + } + + pub fn order_deck(self: *Deck) DeckError!void { + try sort(self.cards); + } + + fn sort(cards: []Card, numCards: u8) DeckError!void { + if (cards.len <= 1) return; + var cb = [MAX_CARDS]?Card{null} ** MAX_CARDS; + var sortedGapsDeck: []?Card = cb[0..MAX_CARDS]; + + for (cards) |card| { + const cardIdx = faceValueIdx(card.faceValue) + suiteValueIdx(card.suite); + sortedGapsDeck[cardIdx] = card; + } + var cb2: [MAX_CARDS]Card = undefined; + var sortedGaplessDeck = cb2[0..numCards]; + var glIdx: u8 = 0; + for (0..sortedGapsDeck.len) |gIdx| { + if (sortedGapsDeck[gIdx] != null) { + sortedGaplessDeck[glIdx] = sortedGapsDeck[gIdx]; + glIdx += 1; + } + } + + var newCards = []Card.init(0) catch return DeckError.Overflow; + for (sortedGaplessDeck) |card| { + newCards.append(card) catch return DeckError.Overflow; + } + } + + fn cloneDeck(deck: *[]Card) DeckError![]Card { + var newDeck = []Card.init(0) catch return DeckError.Overflow; + + for (deck.buffer) |card| { + newDeck.append(card) catch return DeckError.Overflow; + } + return newDeck; + } + + test "Deck.cloneDeck" { + var deck = Deck{}; + try deck.init(); + const clonedCards = try Deck.cloneDeck(&deck.cards); + + try std.testing.expectEqual(deck.cards.len, clonedCards.len); + for (deck.cards, 0..) |card, i| { + try std.testing.expectEqual(card, clonedCards[i]); + } + } + + fn faceValueIdx(f: Face) u8 { + const negIdx: i16 = @intCast(@intFromEnum(f)); + return @intCast(@abs(negIdx - 14)); + } + + test "Deck.faceValueIdx" { + try std.testing.expectEqual(12, faceValueIdx(Face.Two)); + try std.testing.expectEqual(1, faceValueIdx(Face.King)); + } + + fn suiteValueIdx(s: Suit) u8 { + const cards: u8 = @intCast(NUM_CARDS_IN_SUITE); + return @intFromEnum(s) * cards; + } + + // fn mergeSplit(a: *BoundedArrayOfCards, b: *BoundedArrayOfCards, iBegin: u8, iEnd: u8) void { + // if (iEnd - iBegin <= 1) return; + // const iMiddle: u8 = (iBegin + iEnd) / 2; + // mergeSplit(a, b, iBegin, iMiddle); + // mergeSplit(a, b, iMiddle, iEnd); + // merge(b, a, iBegin, iMiddle, iEnd); + // } + + // /// Merges two arrays of cards, deck `a` is merged into deck `b` + // fn merge(a: *BoundedArrayOfCards, b: *BoundedArrayOfCards, iBegin: u8, iMiddle: u8, iEnd: u8) void { + // var i = iBegin; + // var j = iMiddle; + // for (iBegin..iEnd) |k| { + // if (i < iMiddle and (j >= iEnd or gt(a.get(j), a.get(i)))) { + // b.set(k, a.get(i)); + // i = i + 1; + // } else { + // b.set(k, a.get(j)); + // j = j + 1; + // } + // } + // } + + /// Greater than comparison function for two cards + /// A card is considered greater, if it is found closer + /// to the top of the deck when set to the default sort order + /// + /// Default Order from Top to Bottom is: + /// Suites: Spades > Hearts > Clubs > Diamonds + /// FaceValue: 2 > 10 > Jack > Queen > King > Ace + /// 2 of Spades is on top, Ace of Diamonds is the bottom card + fn gt(l: Card, r: Card) bool { + const lSuite: u4 = @intFromEnum(l.suite); + const lFace: u4 = @intFromEnum(l.faceValue); + const rSuite: u4 = @intFromEnum(r.suite); + const rFace: u4 = @intFromEnum(r.faceValue); + + if (lSuite != rSuite) { + return lSuite > rSuite; + } + // reverse comparison for face value, because 3 (3) is > ace (14) + return lFace < rFace; + } + + test "Deck.gt" { + const twoHearts = Card{ .suite = .Hearts, .faceValue = .Two }; + const kingSpades = Card{ .suite = .Spades, .faceValue = .King }; + const aceSpades = Card{ .suite = .Spades, .faceValue = .Ace }; + + try std.testing.expect(Deck.gt(kingSpades, twoHearts)); + try std.testing.expect(Deck.gt(kingSpades, aceSpades)); + try std.testing.expect(!Deck.gt(aceSpades, aceSpades)); + } +}; + +test "Deck.init" { + var deck = Deck{}; + try deck.init(); + + try std.testing.expectEqual(MAX_CARDS, deck.num_cards); + try std.testing.expectEqual(Card{ .suite = .Diamonds, .faceValue = .Ace }, deck.cards[0]); + try std.testing.expectEqual(Card{ .suite = .Spades, .faceValue = .Two }, deck.cards[51]); +} + +test "Deck.deal" { + var deck = Deck{}; + try deck.init(); + + try std.testing.expectEqual(deck.deal(), Card{ .suite = .Spades, .faceValue = .Two }); + try std.testing.expectEqual(51, deck.num_cards); + + try std.testing.expectEqual(deck.deal(), Card{ .suite = .Spades, .faceValue = .Three }); + try std.testing.expectEqual(50, deck.num_cards); + + for (0..50) |_| { + _ = deck.deal(); + } + + try std.testing.expectEqual(0, deck.num_cards); + try std.testing.expectEqual(null, deck.deal()); +} + +test "Deck.peak" { + var deck = Deck{}; + try deck.init(); + + try std.testing.expectEqual(Card{ .suite = .Spades, .faceValue = .Two }, deck.peak()); + try std.testing.expectEqual(MAX_CARDS, deck.num_cards); + + // Deal out 20 cards + for (0..20) |_| { + _ = deck.deal(); + } + + try std.testing.expectEqual(deck.peak(), Card{ .suite = .Hearts, .faceValue = .Nine }); + try std.testing.expectEqual(deck.num_cards, 32); + + // Try to peak empty deck + for (0..32) |_| { + _ = deck.deal(); + } + try std.testing.expectEqual(null, deck.peak()); +} + +test "Deck.discard" { + var deck = Deck{}; + try deck.init(); + + const twoSpadesCard = deck.deal(); + try std.testing.expect(twoSpadesCard != null); + try std.testing.expect(twoSpadesCard.?.suite == .Spades); + try std.testing.expect(twoSpadesCard.?.faceValue == .Two); + + // Deal out 13 cards + for (0..12) |_| { + _ = deck.deal(); + } + const twoHeartsCard = deck.deal(); + try std.testing.expect(twoHeartsCard != null); + try std.testing.expect(twoHeartsCard.?.suite == .Hearts); + try std.testing.expect(twoHeartsCard.?.faceValue == .Two); + + // Discard two cards + try deck.discard(twoSpadesCard.?); + try deck.discard(twoHeartsCard.?); + + try std.testing.expectEqual(2, deck.num_discards); + try std.testing.expectEqual(twoSpadesCard.?, deck.discard_pile[0]); + + // Fails to add duplicate card + try std.testing.expectError(DeckError.DuplicateDiscard, deck.discard(twoSpadesCard.?)); +} + +test "Deck.rebuild" { + var deck = Deck{}; + try deck.init(); + var buf1 = [_]?Card{null} ** 5; + var buf2 = [_]?Card{null} ** 5; + var buf3 = [_]?Card{null} ** 5; + var playerOneHand: []?Card = &(buf1); + var playerTwoHand: []?Card = &(buf2); + var playerThreeHand: []?Card = &(buf3); + + // Alternate dealing player one and two hands + for (0..10) |i| { + if (i % 2 == 0) try playerOneHand.append(deck.deal().?) else try playerTwoHand.append(deck.deal().?); + } + + try std.testing.expectEqual(5, playerOneHand.len); + try std.testing.expectEqual(5, playerTwoHand.len); + + // Discard top 10 cards from deck + for (0..10) |_| { + try deck.discard(deck.deal().?); + } + + for (0..5) |i| { + playerThreeHand[i] = deck.deal().?; + } + + try std.testing.expectEqual(5, playerThreeHand.len); + + try std.testing.expectEqual(10, deck.discard_pile.len); + try std.testing.expectEqual(27, deck.cards.len); + + for (0..15) |i| { + switch (i % 3) { + 0 => try deck.discard(playerThreeHand.pop()), + 1 => try deck.discard(playerOneHand.pop()), + 2 => try deck.discard(playerTwoHand.pop()), + else => unreachable, + } + } + try std.testing.expectEqual(25, deck.discard_pile.len); + + try deck.rebuild(); + + try std.testing.expectEqual(0, deck.discard_pile.len); + try std.testing.expectEqual(52, deck.cards.len); + + try std.testing.expectEqual(Card{ .suite = .Diamonds, .faceValue = .Ace }, deck.cards[0]); + try std.testing.expectEqual(Card{ .suite = .Spades, .faceValue = .Two }, deck.cards[51]); +} + +// test "Deck.rebuild with missing cards" { +// var deck = Deck{}; +// try deck.init(); +// // var playerOneHand = []Card.init(0) catch unreachable; +// // var playerTwoHand = []Card.init(0) catch unreachable; + +// // Alternate dealing player one discarding cards +// for (0..52) |i| { +// switch (i % 4) { +// 0 => try playerTwoHand.append(deck.deal().?), +// 1 => try deck.discard(deck.deal().?), +// 2 => try playerOneHand.append(deck.deal().?), +// 3 => { +// _ = deck.deal(); +// }, +// else => unreachable, +// } +// } + +// try std.testing.expectEqual(13, playerOneHand.len); +// try std.testing.expectEqual(13, playerTwoHand.len); +// try std.testing.expectEqual(13, deck.discard_pile.len); +// try std.testing.expectEqual(0, deck.cards.len); + +// for (0..26) |i| { +// switch (i % 2) { +// 0 => try deck.discard(playerOneHand.pop()), +// 1 => try deck.discard(playerTwoHand.pop()), +// else => unreachable, +// } +// } +// try std.testing.expectEqual(39, deck.discard_pile.len); + +// try deck.rebuild(); + +// try std.testing.expectEqual(0, deck.discard_pile.len); +// try std.testing.expectEqual(39, deck.cards.len); + +// try std.testing.expectEqual(Card{ .suite = .Diamonds, .faceValue = .Ace }, deck.cards[0]); +// try std.testing.expectEqual(Card{ .suite = .Spades, .faceValue = .Two }, deck.cards[38]); +// } diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..8fd460e --- /dev/null +++ b/src/main.zig @@ -0,0 +1,6 @@ +const std = @import("std"); +const deck = @import("deck.zig"); + +pub fn main() !void { + std.debug.print("It works!\n", .{}); +}