oop – python: add the lowest scores in the game yahtzee

I'm coding yahtzee game by looking at this Medium article: https://medium.com/better-programming/interview-questions-write-yahtzee-in-python-72695550d84e.

My question two questions are: how do I add the lowest score as the highest score? How do I add the total score?

my code is a little different from the Media guide:

import random


class Dice:

    def __init__(self):
        self._rolled_dices = ()
        self._picked_dices = ()
        self._new_rolled_dices = ()
        self._turns = 0
        self._upper_score = 0

    def roll(self):
        if self._turns < 3:
            self._rolled_dices.clear()
            for i in range(5):
                value = random.randint(1, 6)
                self._rolled_dices.append(value)
            self._turns += 1
            return self._rolled_dices

    def pick(self):
        dice_user_input = input("Which dices do you want to keep? Use space to differ the numbers. ")
        dice_input_split = dice_user_input.split()

        if dice_user_input == "":
            return self._rolled_dices
        else:
            for number in dice_input_split:
                self._picked_dices.append(int(number))
                self._rolled_dices.remove(int(number))
            return self._rolled_dices

    def roll_again(self):
        if self._turns < 3:
            for i in range(len(self._rolled_dices)):
                val = random.randint(1, 6)
                self._new_rolled_dices.append(val)
            self._turns += 1
            self._rolled_dices = self._new_rolled_dices
            return self._rolled_dices
        else:
            print('already rolled three times')

    def all_picked_dices(self):
        return self._picked_dices

# DICE COMBINATIONS

    def upper_section(self, upper_rolled):
        """ if at least two dices are equals.
        the score is the sum of all the dice showing the specific number.
        """
        for number in self._rolled_dices:
            if number == upper_rolled:
                self._upper_score += number
        return self._upper_score

    def one_pair(self):
        """ if two dices are equal.
        the score is the sum of the pair. """
        self._picked_dices.sort()
        if self._picked_dices(0) == self._picked_dices(1):
            return self._picked_dices(0) + self._picked_dices(1)
        elif self._picked_dices(1) == self._picked_dices(2):
            return self._picked_dices(1) + self._picked_dices(2)
        elif self._picked_dices(2) == self._picked_dices(3):
            return self._picked_dices(2) + self._picked_dices(3)
        elif self._picked_dices(3) == self._picked_dices(4):
            return self._picked_dices(3) + self._picked_dices(4)
        else:
            return 0

    def two_pairs(self):
        """ if two different pairs of dices are equal.
        the score is the sum of both of the pairs. """
        self._picked_dices.sort()
        if self._picked_dices(0) == self._picked_dices(1) and self._picked_dices(2) == self._picked_dices(3):
            return self._picked_dices(0) + self._picked_dices(1) + self._picked_dices(2) + self._picked_dices(3)
        elif self._picked_dices(0) == self._picked_dices(1) and self._picked_dices(3) == self._picked_dices(4):
            return self._picked_dices(0) + self._picked_dices(1) + self._picked_dices(3) + self._picked_dices(4)
        elif self._picked_dices(1) == self._picked_dices(2) and self._picked_dices(3) == self._picked_dices(4):
            return self._picked_dices(1) + self._picked_dices(2) + self._picked_dices(3) + self._picked_dices(4)
        else:
            return 0

    def three_of_a_kind(self):
        """ if three dices are equal.
        the score is the sum of all five dices. """
        self._picked_dices.sort()
        if self._picked_dices(0) == self._picked_dices(2) or self._picked_dices(1) == self._picked_dices(3) 
                or self._picked_dices(2) == self._picked_dices(4):
            return sum(self._picked_dices)

    def four_of_a_kind(self):
        """ if four dices are equal.
        the score is the sum of all five dices. """
        self._picked_dices.sort()
        if self._picked_dices(0) == self._picked_dices(3) or self._picked_dices(1) == self._picked_dices(4):
            return sum(self._picked_dices)

    def small_straight(self):
        """ if the five dices show all the numbers from one to five.
        the score is 30 points. """
        self._picked_dices.sort()
        if self._picked_dices(0) == 1 and self._picked_dices(1) == 2 and self._picked_dices(2) == 3 
                and self._picked_dices(3) == 4 and self._picked_dices(4) == 5:
            return 30

    def large_straight(self):
        """ if the five dices show all the numbers from two to six.
        the score is 40 points. """
        self._picked_dices.sort()
        if self._picked_dices(0) == 2 and self._picked_dices(1) == 3 and self._picked_dices(2) == 4 
                and self._picked_dices(3) == 5 and self._picked_dices(4) == 6:
            return 40

    def full_house(self):
        """ if two dices and three other dices are equal.
        the score is 25 points. """
        self._picked_dices.sort()
        if (self._picked_dices(0) == self._picked_dices(2) and self._picked_dices(3) == self._picked_dices(4)) 
                or (self._picked_dices(0) == self._picked_dices(1) and self._picked_dices(2) == self._picked_dices(4)):
            return 25

    def chance(self):
        """ the score is the sum of all five dices. """
        return sum(self._picked_dices)

    def yatzy(self):
        """ if all the dices are the same.
        the score is 50 points. """
        if len(set(self._picked_dices)) == 1:
            return 50
        else:
            return 0

class Score:

    def __init__(self):
        self._score_board = {}
        self._upper_score = 0
        self._lower_score = 0
        self._upper_bonus = 0
        self._count_total_score = 0

    def add_rolled_ones(self, rolled, value):
        """ adds the rolled dices to the score board. """
        self._score_board(rolled) = value

    def add_upper_score(self, value):
        """ adds the value to upper section """
        self._upper_score += value

    def add_lower_score(self, value):
        """ **!!HELP ME!!** """
        pass

    def get_upper_score(self):
        """ returns the upper score. """
        return self._upper_score

    def add_upper_bonus(self):
        """ adds the upper bonus points if the upper section's score is at least 63 points. """
        if self._upper_score >= 63:
            self._score_board("Upper Bonus") = 50
            self._upper_bonus += 50
        else:
            self._score_board("Upper Bonus") = 0

    def add_total_score(self):
        """ adds the total score to the score_board. 
        **!! HELP ME !!** """
        pass

Beginner – Multiplayer Card Game "Hearts" with OOP in Python

To practice object-oriented Python and learn how to write tests, I found an exercise and solved it as follows (all classes are placed in a code block to make the question a little more readable):

import sys
import random
from typing import List, Tuple, Dict, Optional
from abc import ABC, abstractmethod

class Card:
    SUITS = "♠ ♡ ♢ ♣".split()
    RANKS = "2 3 4 5 6 7 8 9 10 J Q K A".split()

    def __init__(self, suit: str, rank: str) -> None :
        self.suit = suit
        self.rank = rank

    @property
    def suit(self) -> str:
        return self.__suit

    @property
    def rank(self) -> str:
        return self.__rank

    @suit.setter
    def suit(self, suit):
        if suit not in self.__class__.SUITS:
            raise ValueError("Invalid Card Suit")
        self.__suit = suit

    @rank.setter
    def rank(self, rank):
        if rank not in self.__class__.RANKS:
            raise ValueError("Invalid Card Rank")
        self.__rank = rank

    def __repr__(self) -> str :
        return f"{self.__suit}{self.__rank}"

    def __hash__(self):
        return hash((self.__suit, self.__rank))

    def __eq__(self, second) -> bool:
        return self.__suit == second.suit and self.__rank == second.rank

    def __gt__(self, second) -> bool:
        """
            Specifies whether this card is greater than another card
            NOTICE: if the suits are different, returns False.
        """
        rankNums = { rank: num for (num, rank) in zip(range(2,15),list("23456789")+("10")+list("JQKA")) }
        if second.suit == self.__suit:
            if rankNums(self.__rank) > rankNums(second.rank):
                return True
        return False

class Trick:
        HEARTS_ALLOWED: bool = False

        def __init__(self, cards: Optional(Tuple(Card, ...))=None):
            self.__cards: Tuple(Card,...) = cards

        @property
        def cards(self) -> Tuple(Card,...):
            return self.__cards

        def get_points(self):
            points = 0
            for card in self.__cards:
                if card.suit == "♡":
                    points += 1
                elif card.suit == "♠" and card.rank == "Q":
                    points += 13
            return points

        def add_card(self, card: Card):
            if self.cards and len(self.cards) >= 4:
                raise ValueError("More than 4 cards cannot be added to a trick")
            if self.cards and card in self.cards:
                raise ValueError("The same card cannot be added to a trick twice")
            if self.__cards:
                self.__cards = (*self.__cards, card)
            else:
                self.__cards = (card,)

        def get_winCard_idx(self) -> int:
            """ returns the turn number in which the winner card of the trick was played """
            winIdx = 0
            maxCard: Card = self.__cards(0)
            for idx, card in enumerate(self.__cards):
                if card > maxCard:
                    winIdx = idx
                    maxCard = card
            return winIdx

class Deck:
    def __init__(self, **kwargs) -> None :
        """ 
        possible keyword arguments:
            cards: Optional(List(Card))=None
            shuffle: bool=False
        """
        self.cards_setter(kwargs)

    def cards_getter(self) -> List(Card):
        return self.__cards

    def cards_setter(self, kwargs):
        cards = kwargs("cards") if "cards" in kwargs else None
        shuffle = kwargs("shuffle") if "shuffle" in kwargs else False

        if not cards:
            cards = (Card(s, r) for r in Card.RANKS for s in Card.SUITS)
        if shuffle:
            random.shuffle(cards)
        self.__cards: List(Card) = cards

    cards = property(cards_getter, cards_setter)

    def __iter__(self) -> Card:
        yield from self.cards

    def deal(self) -> Tuple("Deck", "Deck", "Deck", "Deck") :
        """Deal the cards in the deck into 4 hands"""
        cls = self.__class__
        return tuple(cls(cards=self.__cards(i::4)) for i in range(4))

class Player(ABC):
    def __init__(self, name: str, hand: Deck) -> None:
        self.name: str = name
        self.hand: Deck = hand
        self.tricksPointsSum: int = 0
        self.roundsPointsSum: int = 0

    @property
    def name(self) -> str:
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @property
    def hand(self) -> Deck:
        return self._hand

    @hand.setter
    def hand(self, cards: Deck):
        self._hand = cards

    @property
    def tricksPointsSum(self) -> int:
        return self.__tricksPointsSum

    @tricksPointsSum.setter
    def tricksPointsSum(self, tricksPointsSum: int):
        self.__tricksPointsSum = tricksPointsSum

    @property
    def roundsPointsSum(self) -> int:
        return self.__roundsPointsSum

    @roundsPointsSum.setter
    def roundsPointsSum(self, roundsPointsSum: int):
        self.__roundsPointsSum = roundsPointsSum

    def play_card(self, trick: Trick) -> Trick:
        if Card("♣","2") in self._hand:
            yield self.__play_this(Card("♣","2"), trick)
        while True:
            playable = self.__get_playable_cards(trick)
            chosen_card = self._prompt_choice(playable)
            yield self.__play_this(chosen_card, trick)

    def __play_this(self, card: Card, trick: Trick) -> Trick:
        trick.add_card(card)
        print(f"{self.__name} -> {card}")
        self._hand.cards.remove(card)
        return trick

    def __get_playable_cards(self, trick: Trick) -> List(Card):
        if not trick.cards:
            if Trick.HEARTS_ALLOWED:
                return self._hand.cards
            else:
                lst = list(filter(lambda card: card.suit != "♡" , self._hand))
                if lst:
                    return lst
                else:
                    Trick.HEARTS_ALLOWED = True
                    return self.__get_playable_cards(trick)
        else:
            trickSuit = trick.cards(0).suit
            if self.has_card(trickSuit):
                return list(filter(lambda card: card.suit == trickSuit, self._hand))
            else:
                Trick.HEARTS_ALLOWED = True
                return self._hand.cards

    def has_card(self, suit, rank: Optional(str) = None) -> bool:
        if rank:
            for card in self._hand:
                if card.rank == rank and card.suit == suit:
                    return True
        else:
            for card in self._hand:
                if card.suit == suit:
                    return True
        return False

    @abstractmethod
    def _prompt_choice(self, playable: Deck) -> Card:
        pass

class HumanPlayer(Player):
    def _prompt_choice(self, playable: Deck) -> Card:
        rankNums = {rank: num for (num, rank) in zip(range(2,15),list("23456789")+("10")+list("JQKA"))} 
        sortedPlayable = sorted(playable, key=lambda card: (card.suit, rankNums(card.rank)))

        (print(f"t{idx}: {card} ", end="") for idx, card in enumerate(sortedPlayable))
        print("(Rest: ", end="")
        for nonPlayableCard in list(set(self._hand.cards)-set(playable)):
            print(nonPlayableCard, end="")
            print(" ", end="")
        print(")")
        while True:
            print(f"t{self.name}, choose card: ", end="")
            try:
                choiceCardIdx: int = int(input())
            except ValueError:
                continue
            if choiceCardIdx < len(sortedPlayable):
                break

        return sortedPlayable(choiceCardIdx)

class AutoPlayer(Player):
    def _prompt_choice(self, playable: Deck) -> Card:
        rankNums = {rank: num for (num, rank) in zip(range(2,15),list("23456789")+("10")+list("JQKA"))} 
        sortedPlayable = sorted(playable, key=lambda card: (card.suit, rankNums(card.rank)))
        return sortedPlayable(0)

class Game:

    def __init__(self, numOfHumans: Optional(int) = 1, *playerNames: Optional(str)) -> None:
        """Set up the deck and create the 4 players"""
        self.__roundNumber: int = 1
        self.__names: List(str) = (list(playerNames) + "P1 P2 P3 P4".split())(:4)
        self.__players: List(Player) = ( HumanPlayer(name, hand) for name, hand in zip(self.__names(:numOfHumans), (None)*numOfHumans))
        self.__players.extend((AutoPlayer(name, hand) for name, hand in zip(self.__names(numOfHumans:), (None)*(4-numOfHumans)) ))

    def __set_new_round(self):
        deck = Deck(shuffle=True)
        hands = deck.deal()
        for idx, player in enumerate(self.__players):
            player.hand = hands(idx)

    def play(self) -> int:
        """Play the card game"""

        while max(player.roundsPointsSum for player in self.__players) < 100:
            """ while no one has lost the whole game """ 

            self.__set_new_round()

            # continue the round by playing the rest of the tricks
            winnerPlayer: Optional(Player) = None
            while self.__players(0).hand.cards:
                trick = Trick()
                turnOrder = next(self.__player_order(winnerPlayer))
                for player in turnOrder:
                    trick = next(player.play_card(trick))
                winnerIdx = trick.get_winCard_idx()
                winnerPlayer = turnOrder(winnerIdx)
                winnerPlayer.tricksPointsSum += trick.get_points()
                turnOrder = self.__player_order(winnerPlayer)
                print(f"{winnerPlayer.name} wins the trickn{'*'*17}")
            # end of round

            print(f"{'-'*50}nEnd Of Round {self.__roundNumber}n{'-'*50}")

            # save the round scores
            for player in self.__players:
                player.roundsPointsSum += player.tricksPointsSum
                print(f"{player.name}: {player.roundsPointsSum}")
                player.tricksPointsSum = 0

            # finish the round and reset it
            Trick.HEARTS_ALLOWED = False
            self.__roundNumber += 1
            print(f"{'-'*50}n")

        #end of the whole game
        self.__announce_winner()
        return 0

    def __announce_winner(self) -> None:
        winnerName = min(self.__players, key=lambda player: player.roundsPointsSum).name
        print(f"{'*' * 50}n{'*'*16} {winnerName} wins the game {'*'*16}n{'*' * 50}")

    def __player_order(self, startPlayer: Player) -> List(Player):
        """Rotate player order so that start goes first"""
        if not startPlayer:
            for player in self.__players:
                """ find the player that has the ♣2 card """
                if player.has_card("♣", "2"):
                    start_idx = self.__players.index(player)
                    yield self.__players(start_idx:) + self.__players(:start_idx)
                    break
        while True:
            start_idx = self.__players.index(startPlayer)
            yield self.__players(start_idx:) + self.__players(:start_idx)

if __name__ == "__main__":
    try:
        numOfHumans = int(sys.argv(1))
        if numOfHumans > 4 or numOfHumans < 0:
            raise ValueError("Number of human players cannot be less than 0 or more than 4")
        playerNames = sys.argv(2:2+numOfHumans)
    except (IndexError, ValueError):
        print("Number of human players is automatically set to 1")
        numOfHumans = 1
        playerNames = ()

    try:
        game = Game(numOfHumans, *playerNames)
        game.play()
    except EOFError:
        print("nGame Aborted")

Example of use:

python3 hearts.py 0

I know that it is very important to learn how to write tests for any software, so I chose Pytest as the start and wrote these tests also for the public methods of the previous classes:

import pytest
from french_card_game_oo import Card, HumanPlayer, AutoPlayer, Deck, Trick, Game

SUITS = {suit_title: suit_symbol for (suit_title, suit_symbol) in zip(("spades", "hearts", "diamonds", "clubs"), "♠ ♡ ♢ ♣".split())}

def test_invalid_card_suit():
    with pytest.raises(ValueError):
        Card("*",5)

def test_invalid_card_rank():
    with pytest.raises(ValueError):
        Card(SUITS("diamonds"),13)

def test_card_5_diamonds_eq_card_5_diamonds():
    assert Card(SUITS("diamonds"), "5") == Card(SUITS("diamonds"), "5")

def test_card_A_spades_gt_3_spades():
    assert Card(SUITS("spades"), "A") > Card(SUITS("spades"), "3")

def test_card_A_spades_isnt_gt_10_clubs():
    assert not (Card(SUITS("spades"), "A") > Card(SUITS("clubs"), "10"))

@pytest.fixture
def trick_15_points():
    return Trick(
        (
        Card(SUITS('spades'), "Q"),
        Card(SUITS('hearts'), "2"),
        Card(SUITS('hearts'), "3")
        )
    )

def test_get_points_of_trick_of_15_points(trick_15_points):
    assert trick_15_points.get_points() == 15

def test_add_card_to_trick(trick_15_points):
    trick_15_points.add_card(Card(SUITS('hearts'), "4"))
    assert len(trick_15_points.cards) == 4

def test_cannot_add_5th_card_to_a_trick(trick_15_points: Trick):
    with pytest.raises(ValueError):
        trick_15_points.add_card(Card(SUITS('hearts'), "4"))
        trick_15_points.add_card(Card(SUITS('hearts'), "5"))

def test_cannot_add_repeated_card_to_trick(trick_15_points: Trick):
    with pytest.raises(ValueError):
        trick_15_points.add_card(Card(SUITS('hearts'), "3"))

def test_get_winner_card_idx1(trick_15_points: Trick):
    trick_15_points.add_card(Card(SUITS('spades'), "J"))
    assert trick_15_points.get_winCard_idx() == 0

def test_get_winner_card_idx2(trick_15_points: Trick):
    trick_15_points.add_card(Card(SUITS('spades'), "A"))
    assert trick_15_points.get_winCard_idx() == 3

def test_get_winner_card_idx3(trick_15_points: Trick):
    trick_15_points.add_card(Card(SUITS('clubs'), "A"))
    assert trick_15_points.get_winCard_idx() == 0

def test_deck_creation():
    Deck()
    Deck(shuffle=True)
    Deck(cards=(Card(SUITS('clubs'),"A")))
    Deck(cards=(Card(SUITS('clubs'),"K")),shuffle=True)

@pytest.fixture
def deck() -> Deck:
    return Deck(shuffle=True)

def test_can_iterate_in_deck(deck: Deck):
    for card in deck:
        pass

def test_deal_full_deck(deck: Deck):
    hands = deck.deal()
    assert len(hands) == 4
    assert isinstance(hands(0), Deck)
    assert hands(0).cards

@pytest.fixture
def humanPlayer(deck: Deck):
    return HumanPlayer("Joe", deck)

def test_play_card(humanPlayer: HumanPlayer, monkeypatch):
    trick = Trick()
    assert Card(SUITS("clubs"), "2") in next(humanPlayer.play_card(trick)).cards
    monkeypatch.setattr("builtins.input", lambda: 0)
    len(next(humanPlayer.play_card(trick)).cards) == 2

def test_game_all_auto_player():
    game = Game(0)
    assert game.play() == 0

The exercise is done (at least it gives me minimal satisfaction), but now I'm riddled with more OO questions. Since I'm learning on my own, I'll ask them here, but if it's a TLDR for you, just leave a review of my code regardless of my questions.

The questions:

  • Isn't it bad practice to create classes that are "plural" of another class, if they have different purposes? I mean Deck and Trick which are both more or less Cards.
    I have reasons to create the class cheat, there are points in it, specify the winner of the cheat and, most importantly, it is necessary to maintain the state of the game. It also makes the code much more readable (you give the trick to a player when he wants to play, and you get a trick as output when he finishes playing his card). The class deck is also basically a container for a card list. (Probably I could I get rid of both, but I think I have to use dictionaries that are not as good as using objects.)

  • One argument I've seen a lot in object-oriented analysis is "How do you know you won't subclass that class someday?", But in a real-world scenario, should we really consider this warning for ALL superclasses (and start all of them with abstract interfaces / classes) or just for some of them? I think that sounds reasonable just for some classeg Player -> HumanPlayer & AutoPlayer, but in some cases it seems like overkill, why would the "Trick" class ever be abstract?

  • I'm addicted to hinting at the type. Is it so bad It just gives me so much mental help when I read the code and also the IDE uses these tips and gives me miraculous help!

  • Is the play () method of the Game class long? Maybe it's still a functional approach with just an object-oriented facade? If so, how can I shorten it? (I've seen people say that long methods are signs of wrong or wrong designs.) I had a hard time thinking of any tests, so I simply added a return value of 0 indicating success and checked if the test received that.

  • I have defined "play_card ()" and "play_this ()", because "play_this ()" happened twice in play_card (). Is this a bad choice to separate it? Because it adds one more layer to the call stack and this is a call that is made many times (it does not increase the depth of the call stack, however).

  • Also, the "has_card ()" method does two things, both verify the existence of a card in hand and verify the existence of a card with a certain suit in hand. In my opinion, it's more D-R-Y to write both in one method. But still, it is common advice to write methods that Just one thing. Should I divide it into two methods? E.g. has_card and has_card_with_suit?

  • On paper, sometimes I thought I had two class options to take a method. For example, the "__prompt_choice ()" method sounds a bit irrelevant to the "Player" class semantically (Does it seem much more relevant to the "Game" class probably? Or even a "Screen" class?). But I still thought it was better to put it in the "Player" class because the "play_card ()" method is using it and "play_card ()" is in the Player class. Also, it is not very unnatural if we think about it this way: "the player is reflecting on his own choice".

  • Sometimes what I did on paper needed modifications when I got my code. Now I've seen people explain TDD saying it's a tests first approach (I didn't, I wrote the tests "after" the code). So what happens if you write the tests and then things turn out differently than you initially thought? E.g. you realize you need another public method, or maybe you realize you also need a whole new class.

  • I have used class variables like "HEARTS_ALLOWED", but I think somehow they are doing a global status on the show ... they're not globalist?

PHP MVC OOP design

My coworker gave me an API project to work in the middle of a system created in thin PHP. The project consists of the Models and controllers. When the path is called it calls the controller with the required function in the controller, then queries the data from the database in the model functions and retrieves the response.

I want to know is this the correct way to implement OOP in PHP API applications? If not, what are the changes and components I have to make to make it the OOP MVC app?

User Controller

public function getUser($request, $response, $args)
{
    $user = $request->getAttribute('id');

    $user = $this->User->getUserById($userId);

    if (!$user) {
        return $response->withJSON((
          "error" => true, 
          "message" => "cannot get user info", 
          "data" => null
        )));
    }

    return $response->withJSON((
        "error" => false, 
        "message" => "cannot get user info"
        "data" => $user
    ));
}

User model

public function getUserById($userId)
{
    $sql = "SELECT id, name, email
            FROM users
            WHERE id= :id";

    try {
        $stmt = $this->db->prepare($sql);
        $result = $stmt->execute((
            'id' => $userId
        ));
        if ($result && $stmt->rowCount() == 1) {
            return $stmt->fetchAll()(0);
        } else {
            return false;
        }
    } catch (PDOException $e) {
        $this->logger->info("cannot get user by id from DB " . $e);
        return false;
    }
}

object oriented – Chrome Dinosaur Game in C ++ OOP application

I am gaining a lot of interest in game development.
I created the Chorme Dinosaur game in C ++.

I haven't paid much attention to UI / UX, I'm just trying to see if I can apply some OOP in game programming.

Since I'm a newbie, I'm not sure if I'm using good code design and logic.

Could use some code reviews and tips. Before getting my hands dirty in game programming.

The code is also on github https://github.com/ankushTripathi/DinoBIT.

Here I define all my constants, to make the code configurable from a single file.

#pragma once
#define MAX_FRAME_RATE 400
#define CONSOLE_EXIT_KEY 'q'
#define CONSOLE_JUMP_KEY ' '
#define TREE_SYMBOL 'T'
#define DINO_SYMBOL 'x'
#define BLANK_SYMBOL '-'
#define INITAL_PADDING 2

#define PLAY_AREA_SIZE  22
#define MAX_TREE_DISTANCE  5
#define FRAME_RATE_REDUCTION 50
#define LEVEL_UP_FACTOR  3

#define PLAYER_START_POSITION 0
#define PLAYER_SPEED 1
#define PLAYER_JUMP_SPAN 3

abstract class, I understood that consoles are handled differently on different operating systems. Implement the console class for the required operating system.

#pragma once
#include "Config.h"

class Console
{
protected:

    int frame_rate;
    char input_value;
    static const char exit_key = CONSOLE_EXIT_KEY;
    static const char jump_key = CONSOLE_JUMP_KEY;
    std::string output;

public:

    virtual void ClearScreen() = 0;
    virtual void Display(const std::string& str = "") = 0;
    virtual void Sleep() = 0;

    virtual void WaitForInput() = 0;
    virtual bool KeyPressed() = 0;
    virtual bool IsExitKey() = 0;
    virtual bool IsJumpKey() = 0;

    virtual void SetOutput(std::string) = 0;
    virtual void DecrementFameRate() = 0;
};

32-bit Windows console class extension.

#pragma once
#ifdef _WIN32

#include
#include 
#include
#include
#include 

#include "Console.h"

class Win32Console : public Console
{

public :

    Win32Console();

    void ClearScreen();
    void Display(const std::string& str);
    void Sleep();

    void SetOutput(std::string output);
    void DecrementFameRate();

    void WaitForInput();
    bool KeyPressed();
    bool IsExitKey();
    bool IsJumpKey();

    ~Win32Console();
};

#endif // _WIN32

Implementation of the previous class

#ifdef _WIN32
#include "Config.h"
#include "Win32Console.h"

Win32Console::Win32Console()
{
    frame_rate = MAX_FRAME_RATE;
    input_value = '';
    output = "";
}

void Win32Console::ClearScreen()
{
    std::cout << "33(2J33(1;1H" << std::flush;
}

void Win32Console::Display(const std::string& str)
{
    if (!str.length())
        std::cout << output << "n";
    else
        std::cout << str << "n";
}

void Win32Console::Sleep()
{
    std::this_thread::sleep_for(std::chrono::milliseconds(frame_rate));
}

void Win32Console::SetOutput(std::string output)
{
    this->output = output;
}

void Win32Console::DecrementFameRate()
{
    this->frame_rate -= FRAME_RATE_REDUCTION;
}

void Win32Console::WaitForInput()
{
    std::cin.get(input_value);
}

bool Win32Console::KeyPressed()
{
    bool result = _kbhit();
    if (result) input_value = _getch();
    return result;
}

bool Win32Console::IsExitKey()
{
    return (input_value == exit_key);
}

bool Win32Console::IsJumpKey()
{
    return (input_value == jump_key);
}


Win32Console::~Win32Console()
{
}

#endif // _WIN32

Console class extension for Windows 64-bit

#pragma once
#ifdef _WIN64

#include "Win32Console.h"

class Win64Console :
    public Win32Console
{
public :
    void ClearScreen() override;
};

#endif
#ifdef _WIN64

#include "Win64Console.h"

void Win64Console::ClearScreen()
{
    std::cout << std::string(100, 'n');
}

#endif // _WIN64

Factory standard to get the compatible architecture and operating system console.

#pragma once
#include "Win32Console.h"
#include "Win64Console.h"

class ConsoleFactory
{
public:
    static Console* GetConsole();
};
#include "ConsoleFactory.h"

Console* ConsoleFactory::GetConsole()
{
#ifdef __unix
    return new Console();
#endif // __unix
#ifdef __APPLE__
    return new Console();
#endif // __APPLE__
#ifdef _WIN64 
    return new Win64Console();
#endif  //_WIN64
#ifdef _WIN32 
    return new Win32Console();
#endif // _WIN32 
}

The instance of this class represents Dino.

#pragma once
#include "Config.h"

class Player
{
protected:

    int position;
    int speed;
    int jump_span;
    int score;
    static int high_score;

public :

    Player();

    int GetPosition();
    int GetJumpSpan();

    void Run();
    void Jump();

    int GetScore();
    void SetScore(int);

    int GetHighScore();

    ~Player();
};
#include "Player.h"

int Player::high_score = 0;

Player::Player() :
    position(PLAYER_START_POSITION),
    speed(PLAYER_SPEED),
    jump_span(PLAYER_JUMP_SPAN),
    score(0)
{
}

int Player::GetPosition()
{
    return position;
}

int Player::GetJumpSpan()
{
    return jump_span;
}

void Player::Run()
{
    position += speed;
    SetScore(position);
}

void Player::Jump()
{
    position += jump_span;
}

int Player::GetScore()
{
    return score;
}

void Player::SetScore(int score)
{
    this->score = score;
    high_score = (high_score > score)? high_score : score;
}

int Player::GetHighScore()
{
    return high_score;
}

Player::~Player()
{
}

The main class for this game.

#pragma once
#include 
#include 
#include

#include "Player.h"
#include "ConsoleFactory.h"
#include "Config.h"


class Game
{

private:

    static Console* console;
    static Player player;

    static bool jump_flag;
    static int last_frame;
    static int last_tree_position;
    static const int play_area_size = PLAY_AREA_SIZE;
    static std::deque play_area;

    static std::mt19937 eng;

    static bool GameOverConditions();

    static bool IsLevelUp();
    static void LevelUp();

    static bool ShouldPlaceTree(int);
    static void Move();
    static std::string GenerateFrame();

    static bool Run();

public:

    static void Start();
    static void Loop();
    static bool ShouldRestart();
    static void Restart();

    static void End();
};
#include "Game.h"

Console* Game::console = ConsoleFactory::GetConsole();
Player Game::player = Player();

std::mt19937 Game::eng{ std::random_device{}() };

bool Game::jump_flag = false;
int Game::last_frame = Game::play_area_size - 1;
int Game::last_tree_position = 0;
std::deque Game::play_area(Game::play_area_size, false);

std::string Game::GenerateFrame()
{

    std::string str = "Current Score :" + std::to_string(player.GetScore()) + "t High Score :" + std::to_string(player.GetHighScore()) + "n";
    std::string result = "";
    for (auto it = play_area.begin(); it != play_area.end(); it++)
    {
        result += (*it) ? TREE_SYMBOL : BLANK_SYMBOL;
    }

    result(0) = DINO_SYMBOL;
    result = std::string(INITAL_PADDING, BLANK_SYMBOL) + result;
    return str + result;
}

void Game::Start()
{
    console->ClearScreen();
    console->Display("Welcome To DinBIT (press (space) to jump ..)");
    console->WaitForInput();

    for (int i = 1;i < play_area_size; i++)
    {
        if (ShouldPlaceTree(i))
        {
            play_area(i) = true;
            last_tree_position = i;
        }
    }

    console->SetOutput(GenerateFrame());
}

void Game::Loop()
{
    while (1)
    {

        console->ClearScreen();
        console->Display();
        console->Sleep();

        if (!Run())
        {
            if (ShouldRestart())
                Restart();
            else
                break;
        }
    }
}

bool Game::ShouldRestart()
{
    console->ClearScreen();
    console->Display();
    console->WaitForInput();

    console->ClearScreen();
    console->Display("Press (Enter) to restart, 'q' to quit..");

    console->WaitForInput();

    return !(console->IsExitKey());
}

void Game::Restart()
{
    Game::console = ConsoleFactory::GetConsole();
    Game::player = Player();

    Game::jump_flag = false;
    Game::last_frame = Game::play_area_size - 1;
    Game::last_tree_position = 0;
    Game::play_area = std::deque(Game::play_area_size, false);

    Game::Start();
}

void Game::End()
{
    console->ClearScreen();
    console->Display();

    console->WaitForInput();

    delete console;
}

All Game Logic is implemented here.

#include "Game.h"

bool Game::GameOverConditions()
{
    return (play_area(0) || play_area(1));
}

bool Game::IsLevelUp()
{
    return !((last_frame + 1) % (LEVEL_UP_FACTOR * play_area_size));
}


void Game::LevelUp()
{
    console->DecrementFameRate();
}

bool Game::Run()
{
    jump_flag = false;

    if(console->KeyPressed() && console->IsJumpKey())
    {
        jump_flag = true;
        player.Jump();
    }


     if (IsLevelUp())
    {
         Game::LevelUp();
    }


    Move();

    std::string str = GenerateFrame();
    if (jump_flag) str += "n JUMPED !";

    if (GameOverConditions())
    {
        str += "nGame Over";
        console->SetOutput(str);
        return false;
    }

    console->SetOutput(str);
    return true;
}


bool Game::ShouldPlaceTree(int frame)
{
    if (frame - last_tree_position >= MAX_TREE_DISTANCE)
        return std::uniform_int_distribution{0,1}(eng);

    return false;
}

void Game::Move()
{
    if (!jump_flag)
        player.Run();

    play_area.pop_front();
    last_frame++;

    if (ShouldPlaceTree(last_frame))
    {
        play_area.push_back(true);
        last_tree_position = last_frame;
    }
    else
        play_area.push_back(false);

    if (jump_flag)
    {
        int j = player.GetJumpSpan();

        while (--j)
        {
            play_area.pop_front();
            last_frame++;

            if (ShouldPlaceTree(last_frame))
            {
                play_area.push_back(true);
                last_tree_position = last_frame;
            }
            else
                play_area.push_back(false);
        }
    }
}
#include "Game.h"

int main()
{
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    std::cout.tie(NULL);

    Game::Start();
    Game::Loop();
    Game::End();
}

There is a mini readme file https://github.com/ankushTripathi/DinoBIT/blob/master/README.md

object oriented – File system – OOP

I have added an object oriented file system. I'm looking for suggestions on how I could improve it further.

Thank you.

package oopdesign.fileSystem;

public abstract  class Entry {

    protected Directory parent;
    protected long created;
    protected long lastUpdated;
    protected long lastAccessed;
    protected String name;

    public Entry(String n, Directory p){
        name = n;
        parent = p;
        created = System.currentTimeMillis();
        lastUpdated = System.currentTimeMillis();
        lastAccessed = System.currentTimeMillis();
    }

    public boolean delete(Entry entry){
        if(parent == null) return false;
        return parent.deleteEntry(this);
    }

    public abstract int size();

    public String getFullPath(){
        if( parent == null ) return name;
        else return parent.getFullPath() + "/" + name;
    }

    /* Getter and setter */
    public long getCreationTime() { return created; }
    public long getLastUpdatedTime() { return lastUpdated; }
    public long getLastAccessed() { return lastAccessed; }
    public void changeName(String n) { name = n; }
    public String getName() { return name; }
}







package oopdesign.fileSystem;

public class File extends Entry {

    private String content;
    private int size;

    public File(String entryName, Directory directory, int size) {
        super(entryName, directory);
        this.content = content;
        this.size = size;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public int size() {
        return size;
    }

}

oopdesign.fileSystem package;

import java.util.ArrayList;

public class Directory extends Entry {

    ArrayList fileList;

    public Directory(String entryName, Directory directory) {
        super(entryName, directory);
        fileList = new ArrayList();
    }

    public int size() {
        int size = 0;
        for (Entry e: fileList) {
            size += e.size();
        }
        return size;
    }

    public int numberOfFiles() {
        int count = 0;
        for(Entry e : fileList){
            if(e instanceof Directory){
                count ++;
                Directory d = (Directory) e;
                count += d.numberOfFiles();
            }else if(e instanceof File){
                count ++;
            }
        }

        return count;
    }

    public void addEntry(Entry entry){
        fileList.add(entry);
    }

    public boolean deleteEntry(Entry entry){
       return fileList.remove(entry);
    }

    protected ArrayList getContents() { return fileList; }
}

python – Simulating an OOP coffee machine

Today I learned the basics of OOP. I have tried to apply them to this coffee machine project. However I am still a beginner, and I think my code can be improved. Are there any tips, tricks, or other tips I can follow to improve the look, runtime, readability, or get the most out of OOP?

This code is simulating a coffee machine that requests 4 different actions; buy, fill, remaining and go out.

When you enter to buy, the program asks you what type of coffee you want. Here you can enter 1, 2, 3 or return, if you change your mind about drinking coffee. Each coffee has different requirements for the supplies you need to make a coffee. If there are not enough supplies available, the coffee machine does not prepare coffee and a message appears. If there are enough supplies, the requirements for the selected coffee are deducted from the available supplies and a message appears showing that it was successful.

Fill feature allows you to add supplies to the CoffeeMachine class.

The remainder shows the current supply amounts for each of the materials in the coffee machine. Like water, milk, coffee beans, cups and money.

Exit allows the user to stop the program.

#First OOP Project
class CoffeeMachine:

    running = False

    def __init__(self, water, milk, coffee_beans, cups, money):
        # quantities of items the coffee machine already had
        self.water = water
        self.milk = milk
        self.coffee_beans = coffee_beans
        self.cups = cups
        self.money = money

        #if the machine isnt running then start running
        if not CoffeeMachine.running:
            self.start()

    def start(self):
        self.running = True
        self.action = input("Write action (buy, fill, take, remaining, exit):n")
        print()
        #possible choices to perform in the coffee machine
        if self.action == "buy":
            self.buy()
        elif self.action == "fill":
            self.fill()
        elif self.action == "take":
            self.take()
        elif self.action == "exit":
            exit()
        elif self.action == "remaining":
            self.status()

    def return_to_menu(self): # returns to the menu after an action
        print()
        self.start()

    def available_check(self): # checks if it can afford making that type of coffee at the moment
        self.not_available = "" # by checking whether the supplies goes below 0 after it is deducted
        if self.water - self.reduced(0) < 0:
            self.not_available = "water"
        elif self.milk - self.reduced(1) < 0:
            self.not_available = "milk"
        elif self.coffee_beans - self.reduced(2) < 0:
            self.not_available = "coffee beans"
        elif self.cups - self.reduced(3) < 0:
            self.not_available = "disposable cups"

        if self.not_available != "": # if something was detected to be below zero after deduction
            print(f"Sorry, not enough {self.not_available}!")
            return False
        else: # if everything is enough to make the coffee
            print("I have enough resources, making you a coffee!")
            return True

    def deduct_supplies(self): # performs operation from the reduced list, based on the coffee chosen
        self.water -= self.reduced(0)
        self.milk -= self.reduced(1)
        self.coffee_beans -= self.reduced(2)
        self.cups -= self.reduced(3)
        self.money += self.reduced(4)

    def buy(self):
        self.choice = input("What do you want to buy? 1 - espresso, 2 - latte, 3 - cappuccino, back - to main menu:n")
        if self.choice == '1':
            self.reduced = (250, 0, 16, 1, 4) # water, milk, coffee beans, cups, money
            if self.available_check(): # checks if supplies are available
                self.deduct_supplies() # if it is, then it deducts

        elif self.choice == '2':
            self.reduced = (350, 75, 20, 1, 7)
            if self.available_check():
                self.deduct_supplies()

        elif self.choice == "3":
            self.reduced = (200, 100, 12, 1, 6)
            if self.available_check():
                self.deduct_supplies()

        elif self.choice == "back": # if the user changed his mind
            self.return_to_menu()

        self.return_to_menu()

    def fill(self): # for adding supplies to the machine
        self.water += int(input("Write how many ml of water do you want to add:n"))
        self.milk += int(input("Write how many ml of milk do you want to add:n"))
        self.coffee_beans += int(input("Write how many grams of coffee beans do you want to add:n"))
        self.cups += int(input("Write how many disposable cups of coffee do you want to add:n"))
        self.return_to_menu()

    def take(self): # for taking the money from the machine
        print(f"I gave you ${self.money}")
        self.money -= self.money
        self.return_to_menu()

    def status(self): # to display the quantities of supplies in the machine at the moment
        print(f"The coffee machine has:")
        print(f"{self.water} of water")
        print(f"{self.milk} of milk")
        print(f"{self.coffee_beans} of coffee beans")
        print(f"{self.cups} of disposable cups")
        print(f"${self.money} of money")
        self.return_to_menu()

CoffeeMachine(400, 540, 120, 9, 550) # specify the quantities of supplies at the beginning
            # water, milk, coffee beans, disposable cups, money

Vending Machine Project – Python OOP

I have been working on a vending machine project described below.

After selecting & # 39; b & # 39; In the first menu, I'm having trouble comparing the cost of the selected item with the total amount inside the vending machine (self.total). I have figured out how to reference the selected product through a dictionary (VendingMachine.order_product), however this only works as a string and I cannot subtract the value of the product (product.price) from the self.total – This may be seen at self.total – = {product.price} in VendingMachine.order_product

Once the order has been completed and the product received, I want to subtract 1 product from the item. Stock that can be selected in the first menu in option c – & # 39; Transacciones & # 39 ;. If there are none left in stock, I want to remove the item from the dict using the .remove method I suppose.

I have no coding friends, so it has been difficult to get here! Any comments would be appreciated!

Sorry if I didn't explain it very well.

accepted_coins= (0.05, 0.10, 0.20, 0.50, 1.00, 2.00) 
options = ("a", "b", "c")


class Item:
 def __init__(self, code, name, price, stock):
    self.code = code
    self.name = name
    self.price = price
    self.stock = stock


class VendingMachine:


def __init__(self):
    self.total = 0.00

    self.items = {
       '1' : Item(1, "Tea", 0.50, 10),
       '2' : Item(2, "Coffee", 1.00, 10),
       "3" : Item(3, "Coke", 1.50, 6),
       "4" : Item(4, "Orange Juice", 1.00, 5)
    }



def select_option(self):
    print(" ")
    print("Welcome to My Vending Machine")
    print ("{} Display Products".format(options(0)))
    print ("{} Choose Product".format(options(1)))
    print ("{} Transactions".format(options(2)))
    option = input("Please select option: ")
    if option == options(0):
        VendingMachine.display_items(self)
        VendingMachine.select_option(self)
    elif option == options(1):
        VendingMachine.order_product(self)
    elif option == options(2):
        VendingMachine.display_items(self)
    elif option not in (options):
        print("This option is not recongised")
        VendingMachine.select_option(self)



def display_items(self):
    print (" ")
    print ("All items are currently stocked and available")
    print ("Display items here")



def order_product(self):
    choice = (input("Please insert the item code: "))
    product = self.items(choice)       
    print (f"You have selected {product.name} for ${product.price}. Currently {product.stock} in stock")


    coin = float(input("Please insert your coins: "))
    if float(coin) not in (accepted_coins):
        print ("The Vending Machine accepts only {}" . format(accepted_coins), end = ' ')
    else:
        self.total += coin

    print (f" You have {self.total} in the Machine. You need ${product.price} for {product.name}")

    print("(1) - Confirm")
    print("(2) - Cancel")
    confirm = float(input('Currently there is a total of ${:.2f} in the Machine. Confirm Order?: '.format(self.total)))
    if float(confirm) == 1:
        self.total -= {product.price} #<< HERE IS MY ISSUE, I want to subtract product.price thats referenced above in the sting from the self.total
        print(f'Please take your {product.name} for a total of ${product.price}. Currently there is a total of ${self.total} left in the Vending Machine')
    elif float(confirm) == 2:
        print ("Please take your money. Have a nice Day!")
        self.total = 0.00
        VendingMachine.select_option(self)
    elif float(confirm) != 2:
        print("Incorrect Answer - Please take your money and try again")
        self.total = 0.00
        VendingMachine.order_product(self)


def main():

vending_machine = VendingMachine()
vending_machine.select_option()



return 0


if __name__ == "__main__":
import sys
sys.exit(main())

Does C # support the OOP paradigm?

I mean, does it? Really support for?

Let's say I would like to have a simple type (Scala):

case class Name(first: String, last: String) {
    def full = first + ' ' + last
}

I really doubt it makes sense to do something like that in C # as it is a tremendously painful undertaking see below. It seems like we shouldn't do anything more than VB6 modules a bit of C # code to keep sanity. Based on my industry experience, no one really tries to do anything else anymore.

public class Name : ValueObject
{
    public Name(string first, string last) =>
        (First, Last) = 
        (first, last);

    public string First { get; }
    public string Last { get; }
    public string Full => First + ' ' + Last;

    protected override IEnumerable EqualityCheckAttributes =>
        new object() { First, Last };

}    

public abstract class ValueObject : IEquatable>
     where T : ValueObject
{
    protected abstract IEnumerable EqualityCheckAttributes { get; }

    public override int GetHashCode() =>
        EqualityCheckAttributes
            .Aggregate(0, (hash, a) => unchecked(hash * 31 + (a?.GetHashCode() ?? 0)));

    public override bool Equals(object obj) =>
        Equals(obj as ValueObject);

    public virtual bool Equals(ValueObject other) =>
        other != null &&
        GetType() == other.GetType() &&
        EqualityCheckAttributes.SequenceEqual(other.EqualityCheckAttributes);

    public static bool operator ==(ValueObject left, ValueObject right) =>
        Equals(left, right);

    public static bool operator !=(ValueObject left, ValueObject right) =>
        !Equals(left, right);
}

oop – Plugin architecture question: how to avoid the use of transients

I am creating an internal plugin that will offer a filtering mechanism using AJAX for any type of post depending on the settings, which I have stored in a JSON.

When the plugin loads I need to configure the callback for the AJAX call, and I configured it right away (I'm left with OOP):

$gfb = FilterBuilder::get_instance();
$action_filter_reg_instance = new ActionFilterRegistration();
$action_filter_reg_instance->add_action( 'wp_ajax_process_filters', $gfb, 'process_filters_callback' );

That sets the callback and it works fine … but that instance of $ gbf is lost when the page displaying posts is loaded and I need to set more properties when the template loads.

For example, when the page displaying the posts loads, I create a new FilterBuilder object and pass it the query arguments which are then stored in the instance as a property of the class.

When the callback is invoked, it is its own instance of a FilterBuilder, so everything I defined in the template does not exist in this class instance.

This makes me a little tricky because I would like to have access to the query arguments that were defined when that particular instance was created.

For the moment, I have resorted to using transients so that I can have a common place to access the query arguments that the template instance defined from the callback function, but this just feels bad. Also, I think the transients have a maximum length and therefore this could explode if that limit is reached.

What other options are there? Maybe serialize the template class instance into a JSON and load it from the callback? That also sounds … a little meh.

I don't want to use global variables … interested in what you think would be a fancy approach to get around this problem.

Thanks for taking the time to read this! 👍🏽

design patterns – How to structure multiple OOP calculations?

I am currently working on a project that requires a series (almost 86) of calculations to be run based on user input. The problem is that each calculation has a series of requirements:

  • I should be able to hold a version variable to distinguish the changes in each implementation of the calculation algorithm. In this way, every time we modify an algorithm, we know which version was used in the specific calculation.
  • It must be able to load specific data from other modules within the application (that is, we have 8 entities) so that each one can choose the necessary information for its operation.
  • You should be able to determine if it is "executable", and by which we would write a function (?) which verifies that the extracted data (from the previous requirement) meets some custom criteria for each calculation that guarantees that the algorithm will execute correctly.
  • Each must have a different algorithm implementation.
  • Generate and store a series of execution metrics (logs), such as data fetch time, algorithm runtime, and sampleSize This refers to the amount of data loaded to execute each specific calculation.

Currently what I have done is: create an abstract class Calculation with this structure:

abstract class Calculation {
  /**
 * Logging Variables.
   */
  private initialDataFetchTime: Date;
  private finalDataFetchTime: Date;
  private initialAlgorithmTime: Date;
  private finalAlgorithmTime: Date;

  // Final result holding variable.
  private finalResult: T;

  // The coverage status for this calculation.
  private coverage: boolean;

  // Data to use within the algorithm.
  private data: F;

  // The version of the Calculation.
  public abstract version: string;

  // The form data from the User to be used.
  public static formData: FormData;

  /**
 * This is the abstract function to be implemented with
 * the operation to be performed with the data. Always
 * called after `loadData()`.
   */
  public abstract async algorithm(): Promise;

  /**
 * This function should implement the data fetching
 * for this particular calculation. This function is always
 * called before `calculation()`.
   */
  public abstract async fetchData(): Promise;

  /**
 * This is the abstract function that checks
 * if enough information is met to perform the
 * calculation. This function is called always
 * after `loadData()`.
   */
  public abstract async coverageValidation(): Promise;

  /**
 * This is the public member function that is called
 * to perform the data-fetching operations of the
 * calculation. This is the first function to call.
   */
  public async loadData(): Promise {
    // Get the initial time.
    this.initialDataFetchTime = new Date();

    /**
     * Here we run the data-fetching implementation for
     * this particular calculation.
     */
    this.data = await this.fetchData();

    // Store the final time.
    this.finalDataFetchTime = new Date();
  }

  /**
 * This is the public member function that is called
 * to perform the calculation on this field. This is
 * the last function to be called.
   */
  public async calculation(): Promise {
    // Get the initial time.
    this.initialAlgorithmTime = new Date();

    /**
     * Here we run the algorithmic implementation for
     * this particular calculation.
     */
    this.finalResult = await this.algorithm();

    // Store the final time.
    this.finalAlgorithmTime = new Date();

    // Return the result.
    return this.finalResult;
  }

  /**
 * This is the public member function that is called
 * to perform the coverage-checking of this calculation.
 * This function should be called after the `loadData()`
 * and before `calculation()`.
   */
  public async coverageCheck(): Promise {
    // Execute the check function.
    this.coverage = await this.coverageValidation();

    // Return result.
    return this.coverage;
  }

  /**
 * Set FormData statically to be used across calculations.¡
   */
  public static setFormData(formData: FormData): FormData {
    // Store report.
    this.formData = formData;

    // Return report.
    return this.formData;
  }

  /**
 * Get the coverage of this calculation.
   */
  public getCoverage(): boolean {
    return this.coverage;
  }

  /**
 * Get the data for this calculation.
   */
  public getData(): F {
    return this.data;
  }

  /**
 * Get the result for this calculation.
   */
  public getResult(): T {
    return this.finalResult;
  }

  /**
   * Function to get the class name.
   */
  private getClassName(): string {
    return this.constructor.name;
  }

  /**
   * Function to get the version for this calculation.
   */
  private getVersion(): string { return this.version; }

  /**
   * Get all the Valuation Logs for this Calculation.
   */
  public async getValuationLogs(): Promise {
    // The array of results.
    const valuationLogs: CreateValuationLogDTO() = ();

    // Log the time the algorithm took to execute.
    valuationLogs.push({
      report: Calculation.formData,
      calculation: this.getClassName(),
      metric: 'Algorithm Execution Time',
      version: this.getVersion(),
      value:
        this.initialAlgorithmTime.getTime() - this.finalAlgorithmTime.getTime(),
    });

    // Log the time to fetch information.
    valuationLogs.push({
      report: Calculation.formData,
      calculation: this.getClassName(),
      metric: 'Data Fetch Load Time',
      version: this.getVersion(),
      value:
        this.initialDataFetchTime.getTime() - this.finalDataFetchTime.getTime(),
    });

    // Sample size is calculated and not an issue for this matter.

    // Return the metrics.
    return valuationLogs;
  }
}

And then, created subsequent classes for each calculation that extend the previous class, like:

export class GeneralArea extends Calculation {
  /**
   * Versioning information.
   * These variable hold the information about the progress done to this
   * calculation algorithm. The `version`  field is a SemVer field which
   * stores the version of the current algorithm implementation.
   *
   * IF YOU MAKE ANY MODIFICATION TO THIS CALCULATION, PLEASE UPDATE THE
   * VERSION ACCORDINGLY.
   */
  public version = '1.0.0';

  // Dependencies.
  constructor(private readonly dataSource: DataSource) {
    super();
  }

  // 1) Fetch Information
  public async fetchData(): Promise {
    // Query the DB.
    const dataPoints = this.dataSource.getInformation(/**  **/);

    // Return the data object.
    return {
      mortgages: dataPoints,
    };
  }

  // 2) Validate Coverage.
  public async coverageValidation(): Promise {
    // Load data.
    const data: GeneralAreaData = this.getData();

    // Validate to be more than 5 results.
    if (data.mortgages.length < 5) {
      return false;
    }

    // Everything correct.
    return true;
  }

  // 3) Algorithm
  public async algorithm(): Promise {
    // Load data.
    const data: GeneralAreaData = this.getData();

    // Perform operation.
    const result: number = await Math.min.apply(
      Math,
      data.mortgages.map(mortgage => mortgage.price),
    );

    // Return the result.
    return result;
  }
}

/**
 * Interface that holds the structure of the data
 * used for this implementation.
 */
export interface GeneralAreaData {
  // Mortages based on some criteria.
  mortages: SomeDataEntity;
}

The idea is to allow ourselves to carry out three basic operations:

  1. Load the data for each calculation.
  2. Validate coverage for each calculation.
  3. If the previous step returns a general "true", run calculations.

However, this pattern has posed some problems since FormData (the information that the user loads) is stored inactively, which means if some calculation is already running and another user loads, I can't configure FormData because it will make the other user's calculations go crazy. However passing the FormData For each function constructor it seems like a lot of work (if you think this should be the way, I'm not afraid to write code;))

Maybe it's this quarantine, however am I not seeing something here? Currently, the final run looks like this:


public performCalculation(formData: FormData): Promise {
  // Set general form data.
  Calculation.setFormData(formData); // <--- Error in subsequent requests :(

  // Instance Calculations.
  const generalAreaCalculation: GeneralAreaCalculation = new GeneralAreaCalculation(/** data service **/);
  // 85 more instantiations...

  // Load data for Calculations.
  try {
    await Promise.all((
      generalAreaCalculation.loadData(),
      // 85 more invocations...
    ));
  } catch(dataLoadError) { /** error handling **/ }

  // Check for coverage.
  const coverages: boolean() = await Promise.all((
    generalAreaCalculation.coverageCheck(),
    // 85 more coverage checks...
  ));

  // Reduce coverage.
  const covered: boolean = coverages.reduce((previousValue, coverage) => coverage && previousValue, true);

  // Check coverage.
  if (!covered) { /** Throw exception **/ }

  // Perform calculations!
  const result: FormDataWithCalculations = new FormDataWithCalculations(formData);

  try {
    result.generalAreaValue = generalAreaCalculation.calculation();
    // 85 more of this.
  } catch (algorithmsError) { /** error handling ***/ }

  /*
   (( Here should go the log collecting and storing, for each of the 85 calculations ))
  */

  // Return processed information.
  return result;
}

I'm not afraid to write too much code if that means it is reusable, maintainable, and most importantly capable of being testable (oh yes, test each calculation to make sure it does what it is supposed to do in normal cases and extremes is why classes were my focus, so each would have attached a test), however I am completely overwhelmed by writing this tremendous amount of code instead of just writing 85 functions (which is what was already used ) and call each one of them.

Is there a pattern? Guide? Advice? Reference? Study material? I can't seem to shrink this code anymore, but I wanted to ask in case someone knows a better pattern for this kind of problem and, in case it's useful, TypeScript code (NodeJS with NestJS API) to understand how everything works . be connected

Thanks in advance and apologies for my horrible English!