Project Name

A brief description of what the project does

Table of Contents

Project Overview

This project is a brief description of the overall purpose and goal of your code. Explain the problem it solves, its main features, and what sets it apart from other similar projects.

How to use the library

You start with creating a mutable CardGameModel variable:


        let mut cgm = CardGameModel::new("MyCardGame");
            

Player

!!! TODO: If the Language-Design is done (edit this how it should look like) !!!
To add Players to the Model (at the moment) you need to give the Model the Player-Names.
It looks like this:


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        // Adding (and Initializing) Players to the Model
        players!("Jimmy", "Timmy", "Kimmy")(&mut cgm.gamedata);
            

The Macros players!(...) is a Closure which takes a &mut GameData and adds the Players to the GameData.
(This structure with Clousres is used for 'almost' every Macros).

Team

Let's say we need Teams in our Game.
And let's also say that nobody likes "Kimmy".
This can be done like this:


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        // Adding (and Initializing) Players to the Model
        players!("Jimmy", "Timmy", "Kimmy")(&mut cgm.gamedata);

        // Adding (and Initializing) 'a' Team to the Model
        team!("TheBestTeam", ("Jimmy", "Timmy"))(&mut cgm.gamedata);
        
        // Adding (and Initializing) 'a' Team to the Model
        team!("TheWorstTeam", ("Kimmy"))(&mut cgm.gamedata);
            

Location

Now we have our Players and Teams. BUT WHERE ARE THE CARDS?
Do we have a Card-Stack? Where are the Players-Cards located?
We first should declare some Locations where Cards can be placed!


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        // Adding (and Initializing) Players to the Model
        players!("Jimmy", "Timmy", "Kimmy")(&mut cgm.gamedata);

        // Adding (and Initializing) 'a' Team to the Model
        team!("TheBestTeam", ("Jimmy", "Timmy"))(&mut cgm.gamedata);
        
        // Adding (and Initializing) 'a' Team to the Model
        team!("TheWorstTeam", ("Kimmy"))(&mut cgm.gamedata);

        // add Location 'hand' to each Player
        location_on!("hand", ("Jimmy", "Timmy", "Kimmy"))(&mut cgm.gamedata);

        // Add a Stack to the Table
        location_on!("stack", table)(&mut cgm.gamedata);
            

Card

Now we have almost everything Set-Up for a Card Game!
But ... where are the Cards?
What kind of Cards do we need?
What is a Card?
A Card in our Game-Context:
// TODO: Add Definition of our Card
- has Attributes:
> For Example:
- Rank: (2, 3, 4, 5, 6, 7, ...)
- Suite: (Clubs, Spades, Hearts, Diamonds)
> Example for a Card:
- CardExample:
Rank = 6
Suite = Clubs

These Atrributes can be completely arbitrary!

Now where do we need Cards for the Set-Up of the Game?
Let's say we have all our Cards in the Stack on the Table:


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        // Adding (and Initializing) Players to the Model
        players!("Jimmy", "Timmy", "Kimmy")(&mut cgm.gamedata);

        // Adding (and Initializing) 'a' Team to the Model
        team!("TheBestTeam", ("Jimmy", "Timmy"))(&mut cgm.gamedata);
        
        // Adding (and Initializing) 'a' Team to the Model
        team!("TheWorstTeam", ("Kimmy"))(&mut cgm.gamedata);

        // add Location 'hand' to each Player
        location_on!("hand", ("Jimmy", "Timmy", "Kimmy"))(&mut cgm.gamedata);

        // Add a Stack to the Table
        location_on!("stack", table)(&mut cgm.gamedata);

        // Create Cards on the Location 'stack'
        card_on!(
            "stack",
            {
                Rank("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"),
                Suite("Diamond", "Hearts"),
                Color("Red")
            },
            {
                Rank("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"),
                Suite("Spades", "Clubs"),
                Color("Black")
            }
        )(&mut cgm.gamedata);
            

card_on!(locname: String, { (key((value: String), *)), *}) computes the Cross-Product of the inside of '{''}'.
In the Example we declare Cards with the Color 'Black' and 'Red' seperately, because of the Cross-Product!

Precedence

Now we have Cards!
For lots Games (e.g. Trick-Taking-Games) the importance of a Card-Precedence is very important.
What we mean with Card-Precedence is: Which Card is higher, lower or the same to another Card?


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        // Adding (and Initializing) Players to the Model
        players!("Jimmy", "Timmy", "Kimmy")(&mut cgm.gamedata);

        // Adding (and Initializing) 'a' Team to the Model
        team!("TheBestTeam", ("Jimmy", "Timmy"))(&mut cgm.gamedata);
        
        // Adding (and Initializing) 'a' Team to the Model
        team!("TheWorstTeam", ("Kimmy"))(&mut cgm.gamedata);

        // add Location 'hand' to each Player
        location_on!("hand", ("Jimmy", "Timmy", "Kimmy"))(&mut cgm.gamedata);

        // Add a Stack to the Table
        location_on!("stack", table)(&mut cgm.gamedata);

        // Create Cards on the Location 'stack'
        card_on!(
            "stack",
            {
                Rank("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"),
                Suite("Diamond", "Hearts"),
                Color("Red")
            },
            {
                Rank("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"),
                Suite("Spades", "Clubs"),
                Color("Black")
            }
        )(&mut cgm.gamedata);

        // Creating a Precedence on the Attribute 'Rank'
        precedence!("Rank", ("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"))(&mut cgm.gamedata);
            

The lowest Precedence is Rank=2 and the highest is Rank=A.

PointMap

However, we might want to give arbitrary values and maybe multiple values!
For this we use a PointMap!
A PointMap assigns a Vector of Values to an Attribute.
In 'Black Jack' the Ace can have 1 or 11 as a Value!


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        ...

        // We create a PointMap (for the Special case 'Black Jack')
        pointmap!(
            "BlackJackRank",
            nested: {  
                "Rank", (
                "2" => [2],
                "3" => [3],
                "4" => [4],
                "5" => [5],
                "6" => [6],
                "7" => [7],
                "8" => [8],
                "9" => [9],
                "T" => [10],
                "J" => [10],
                "Q" => [10],
                "K" => [10],
                "A" => [11, 1]
                )
            },
        )(&mut cgm.gamedata);
            

There is also another way to declare this PointMap:


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        ...

        // We create a PointMap (for the Special case 'Black Jack')
        pointmap!(
            "BlackJackRank",
            list: {  
                ("Rank", "2") => [2],
                ("Rank", "3") => [3],
                ("Rank", "4") => [4],
                ("Rank", "5") => [5],
                ("Rank", "6") => [6],
                ("Rank", "7") => [7],
                ("Rank", "8") => [8],
                ("Rank", "9") => [9],
                ("Rank", "T") => [10],
                ("Rank", "J") => [10],
                ("Rank", "Q") => [10],
                ("Rank", "K") => [10],
                ("Rank", "A") => [1, 11],
            },
        )(&mut cgm.gamedata);
            

You can also combine these two:


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        ...

        // We create a PointMap (for the Special case 'Black Jack')
        pointmap!(
            "BlackJackRank",
            nested: {  
                "Rank", (
                "2" => [2],
                "3" => [3],
                "4" => [4],
                "5" => [5],
                "6" => [6],
                "7" => [7],
                "8" => [8],
                "9" => [9],
                "T" => [10],
                "J" => [10],
                "Q" => [10],
                "K" => [10],
                "A" => [11, 1]
                )
            },
            list: {  
                ("Suite", "Clubs")    => [10],
                ("Suite", "Spades")   => [1],
                ("Suite", "Hearts")   => [1],
                ("Suite", "Diamonds") => [1],
            },
        )(&mut cgm.gamedata);
            

Another use of PointMap would be to declare a Special Point-Distribution (e.g. in a Trick).
In the German Game 'Skat', we have a distribution like this:
7, 8, 9 => [0]
J => [2]
Q => [3]
K => [4]
T => [10]
A => [11]

This assigning of Points is not Possible with Precedence!

Card-Combination

In some Card-Games you have to look at multiple Cards to identify a Card-Combination.
In Poker (Texas hold'em) there is a 'Flush'.
Out of the 7 Cards we check if at least 5 Cards have the same 'Suite'.
We can declare a Combination for our model:


        // Initializing the Model
        let mut cgm = CardGameModel::new("MyCardGame");

        ...

        combo!("Flush", (
            filter!(
                (same "Suite"),
                ("and"),
                (size ">=" 5))
            )
        )(&mut cgm.gamedata);
            

We can 'save' this Combo in our GameData and the call it by the name "Flush" when we need it!
What is this 'filter!(...)' and how can we declare it?

// TODO: Memory and other missing things in Set-Up

The filter!(...) is a Macros that takes a Vector of Cards (and also a GameData, because that is where the Cards are in the Game) and
applies the filter!(...) on the Cards. If the filter!(...) cannot find a fitting subset of the Cards that satisfy it, then it will be empty.
(For further information on how the filter!(...)-Macros works look in the code. There is a detailed description on how it works.)


        // same Attribute
        filter!(same (attr_name: &str));

        // Example:
        filter!(same "Rank");

        // adjacent Attribute using Precedence
        filter!(adjacent (attr_name: &str) using (prec_name: &str));

        // Example
        precedence!("RankPrecedence", ("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"))(&mut cgm.gamedata);
        filter!(adjacent "Rank" using "RankPrecedence");

        // size comparison value
        filter!(size (comparison: &str) value);

        // Example
        filter!(size ">" 3);

        // Attribute "==" Attribute-Value
        filter!((attr_key: &str) "==" (attr_value: &str));

        // Example
        filter!("Rank" "==" "A");

        // Attribute "!=" Attribute-Value
        filter!((attr_key: &str) "!=" (attr_value: &str));

        // Example
        filter!("Rank" "!=" "A");

        // combo
        filter!((comboname: &str));

        // Example
        filter!("MyCombo");

        // not combo
        filter!(not (comboname: &str));

        // Example
        filter!(not "MyCombo");

        // Combined filter with 'and'
        // Example:
        filter!(
            (same "Suite"),
            ("and"),
            (size ">=" 5)
        );

        // Combined filter with 'or'
        // Example:
        filter!(
            (same "Suite"),
            ("or"),
            (size ">=" 5)
        );
            

This wraps up the Set-Up for our Card Game.

RuleSet

We now know how to Set-Up a Card Game!
Let's get to the core of any Card Game:
The Rules!

We can define a rough structure of Rules with 'Stages'.
A 'Stage' is an useful tool for decalring the Rules.
We can declare different Rules and Game-Cycles with it which makes creating a Game more flexible.

However, we first need to understand the Rules and the tools that we are working with.

Rules

Conditional-Rule:
case (b: bool):
'Rule'
case (b: bool):
'Rule'
case (b: bool):
'Rule'
...

If-Rule:
if (b: bool) then
'Rule'

Optional-Rule:
'Rule'

Choose-Rule:
'Rule'
OR:
'Rule'
OR:
'Rule'
OR:
...

Trigger-Rule:
'Rule'

Action-Rule:
'Action'