From 35c058f9543b344790d300b78d8015146613cd0c Mon Sep 17 00:00:00 2001 From: night0721 Date: Tue, 1 Oct 2024 13:40:14 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 + LICENSE | 28 ++++++++ Makefile | 39 +++++++++++ README.md | 20 ++++++ ace.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 ace.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a75b03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +ace +*.o +*.tar.gz diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..10621d3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Night Kaly + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c278ba3 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +.POSIX: +.SUFFIXES: + +CC = cc +VERSION = 1.0 +TARGET = ace +MANPAGE = $(TARGET).1 +PREFIX ?= /usr/local +BINDIR = $(PREFIX)/bin + +# Flags +CFLAGS = -O3 -march=native -mtune=native -pipe -s -std=c99 -flto -pedantic -Wall -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 + +SRC = ace.c + +$(TARGET): $(SRC) + $(CC) $(SRC) -o $@ $(CFLAGS) + +dist: + mkdir -p $(TARGET)-$(VERSION) + cp -R README.md $(TARGET) $(TARGET)-$(VERSION) + tar -cf $(TARGET)-$(VERSION).tar $(TARGET)-$(VERSION) + gzip $(TARGET)-$(VERSION).tar + rm -rf $(TARGET)-$(VERSION) + +install: $(TARGET) + mkdir -p $(DESTDIR)$(BINDIR) + cp -p $(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET) + chmod 755 $(DESTDIR)$(BINDIR)/$(TARGET) + +uninstall: + $(RM) $(DESTDIR)$(BINDIR)/$(TARGET) + +clean: + $(RM) $(TARGET) + +all: $(TARGET) + +.PHONY: all dist install uninstall clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ffc235 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# ace +ace is a game for playing blackjack. + +# Usage +``` +./ace +``` + +# Building +You will need to run these with elevated privilages. +``` +$ make +# make install +``` + +# Contributions +Contributions are welcomed, feel free to open a pull request. + +# License +This project is licensed under the BSD-3-Clause License. See [LICENSE](https://github.com/night0721/ace/blob/master/LICENSE) for more information. diff --git a/ace.c b/ace.c new file mode 100644 index 0000000..53f434a --- /dev/null +++ b/ace.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include + +#define CLEAR_SCREEN() printf("\033[H\033[J") +#define MOVE_CURSOR(x, y) printf("\033[%d;%dH", (x), (y)) +#define RESET_COLOR() printf("\033[0m") + +typedef struct { + int value; /* 1 to 13 (Ace to King) */ + int suit; /* 0 to 3 (Hearts, Spades, Diamonds, Clubs) */ +} card; + +card deal_card(); +int calculate_score(card hand[], int num_cards); +void display_hand(card hand[], int num_cards, int is_player, int total); + +struct termios orig_termios; + +int main() +{ + srand(time(NULL)); + + card player_hand[10], cpu_hand[10]; + int player_num_cards = 0, cpu_num_cards = 0; + char action; + + /* Set terminal to return read syscall without enter */ + struct termios new_termios; + + tcgetattr(STDIN_FILENO, &orig_termios); + new_termios = orig_termios; + + new_termios.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &new_termios); + + + for (int i = 0; i < 2; i++) { + player_hand[player_num_cards++] = deal_card(); + cpu_hand[cpu_num_cards++] = deal_card(); + } + + int player_score; + int cpu_score; + + while (1) { + CLEAR_SCREEN(); + MOVE_CURSOR(1, 1); + printf("You Computer\n"); + + + player_score = calculate_score(player_hand, player_num_cards); + cpu_score = calculate_score(cpu_hand, cpu_num_cards); + + display_hand(player_hand, player_num_cards, 1, player_score); + display_hand(cpu_hand, cpu_num_cards, 0, cpu_score); + + /* Check if the player has busted */ + if (player_score > 21) { + printf("\n\033[38;2;255;0;0mBust! You lose.\033[0m\n"); + break; + } + + printf("\nHit (h) or stand (s)? "); + fflush(stdout); + + char action; + read(STDIN_FILENO, &action, 1); + + if (action == 'h') { + player_hand[player_num_cards++] = deal_card(); + } else if (action == 's') { + break; + } + } + + /* Computer's turn to deal + * Customise here if you want more wins + */ + while (cpu_score < 17) { + cpu_hand[cpu_num_cards++] = deal_card(); + cpu_score = calculate_score(cpu_hand, cpu_num_cards); + } + + CLEAR_SCREEN(); + MOVE_CURSOR(1, 1); + + player_score = calculate_score(player_hand, player_num_cards); + cpu_score = calculate_score(cpu_hand, cpu_num_cards); + + /* Determine win or lose */ + if (player_score > 21) { + printf("\033[38;2;255;0;0mComputer wins!\033[0m\n", cpu_score); + } else if (cpu_score > 21) { + printf("\033[38;2;0;255;0mYou win!\033[0m\n", player_score); + } else if (player_score > cpu_score) { + printf("\033[38;2;0;255;0mYou win!\033[0m\n", player_score); + } else if (player_score < cpu_score) { + printf("\033[38;2;255;0;0mComputer wins!\033[0m\n", cpu_score); + } else { + printf("\033[38;2;255;255;0mDraw!\033[0m\n", player_score); + } + + display_hand(player_hand, player_num_cards, 1, player_score); + display_hand(cpu_hand, cpu_num_cards, 0, cpu_score); + + printf("\n"); + /* Reset terminal */ + tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); + return 0; +} + +card deal_card() +{ + card card; + card.value = rand() % 13 + 1; + card.suit = rand() % 4; + return card; +} + +int calculate_score(card hand[], int num_cards) +{ + int score = 0, num_aces = 0; + + for (int i = 0; i < num_cards; i++) { + if (hand[i].value == 1) { + score += 11; + num_aces++; + } else if (hand[i].value > 10) { + score += 10; + } else { + score += hand[i].value; + } + } + + while (score > 21 && num_aces > 0) { + score -= 10; + num_aces--; + } + + return score; +} + +void display_hand(card hand[], int num_cards, int is_player, int total) +{ + const char *suits[] = {"\033[38;2;255;0;0m♥\033[0m", "\033[38;2;0;0;255m♠\033[0m", "\033[38;2;255;0;255m♦\033[0m", "\033[38;2;0;255;0m♣\033[0m"}; + + if (is_player) { + printf("Cards - "); + } else { + /* Alignment */ + MOVE_CURSOR(2, 28); + printf("Cards - "); + } + + for (int i = 0; i < num_cards; i++) { + /* Bold */ + printf("\033[1m"); + switch (hand[i].value) { + case 1: + printf("A%s ", suits[hand[i].suit]); + break; + case 11: + printf("J%s ", suits[hand[i].suit]); + break; + case 12: + printf("Q%s ", suits[hand[i].suit]); + break; + case 13: + printf("K%s ", suits[hand[i].suit]); + break; + default: + printf("%d%s ", hand[i].value, suits[hand[i].suit]); + } + RESET_COLOR(); + } + + printf("\n"); + if (is_player) { + printf("Total - "); + } else { + MOVE_CURSOR(3, 28); + printf("Total - "); + } + + /* Bold and inverted colors */ + printf("\033[1m\033[47;30m"); + printf(" %d ", total); + RESET_COLOR(); + + printf("\n"); +}