From 4fdacb561d1840f41a6de2e099cf41b1166a3347 Mon Sep 17 00:00:00 2001
From: Dahmane Lynda <lynda.dahmane.etu@118p28.fil.univ-lille.fr>
Date: Wed, 27 Mar 2024 10:26:17 +0100
Subject: [PATCH] Tp8

---
 Tp8/bataille-carte.zip         | Bin 0 -> 5560 bytes
 Tp8/bataille-carte/apl1test.py |  89 +++++++++++++++
 Tp8/bataille-carte/apqueue.py  | 104 +++++++++++++++++
 Tp8/bataille-carte/apstack.py  | 126 +++++++++++++++++++++
 Tp8/bataille-carte/card.py     | 197 +++++++++++++++++++++++++++++++++
 Tp8/bataille-carte/war.py      |  91 +++++++++++++++
 6 files changed, 607 insertions(+)
 create mode 100644 Tp8/bataille-carte.zip
 create mode 100644 Tp8/bataille-carte/apl1test.py
 create mode 100644 Tp8/bataille-carte/apqueue.py
 create mode 100644 Tp8/bataille-carte/apstack.py
 create mode 100755 Tp8/bataille-carte/card.py
 create mode 100644 Tp8/bataille-carte/war.py

diff --git a/Tp8/bataille-carte.zip b/Tp8/bataille-carte.zip
new file mode 100644
index 0000000000000000000000000000000000000000..c80b007b4f8b729e06787f0cc5effd95f1d7383a
GIT binary patch
literal 5560
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
V$_5H=Rt8pvX^adEJfH|-002;(<}UyM

literal 0
HcmV?d00001

diff --git a/Tp8/bataille-carte/apl1test.py b/Tp8/bataille-carte/apl1test.py
new file mode 100644
index 0000000..8533cca
--- /dev/null
+++ b/Tp8/bataille-carte/apl1test.py
@@ -0,0 +1,89 @@
+import thonnycontrib
+from thonnycontrib.backend.evaluator import Evaluator
+import thonnycontrib.backend.l1test_backend
+from thonny.plugins.cpython_backend.cp_back import MainCPythonBackend
+import thonnycontrib.backend.doctest_parser 
+from thonnycontrib.backend.doctest_parser import ExampleWithExpected, ExampleWithoutExpected
+import thonnycontrib.backend.ast_parser
+from thonnycontrib.backend.ast_parser import L1DocTest
+import thonnycontrib.backend.verdicts
+from thonnycontrib.backend.verdicts.ExceptionVerdict import ExceptionVerdict 
+
+import inspect
+import tempfile
+import os
+import sys
+        
+class MockBackend(MainCPythonBackend):
+    """
+    Fake backend.
+    """
+    def __init__(self):
+        ...
+
+    def send_message(self, msg) -> None:
+        ...
+
+# register backend
+thonnycontrib.backend.l1test_backend.BACKEND = MockBackend()
+
+def l1test_to_org(filename: str, source: str=""):
+    """
+    Return an org abstract of the tests presents in `filename` file.
+    """
+    abstract = {'total': 0,
+                'success': 0,
+                'failures': 0,
+                'errors': 0,
+                'empty': 0}
+
+    if source == "":
+        with open(filename, 'rt') as fin:
+            source = fin.read()
+    evaluator = Evaluator(filename=filename,
+                          source=source)
+    tests = evaluator.evaluate()
+    n = len(tests)
+    abstract['total'] = n
+    res = ""
+    for test in tests:
+        examples = test.get_examples()
+        res_examples = ""
+        nb_test, nb_test_ok = 0, 0
+        empty = True
+        for example in examples:
+            verdict = test.get_verdict_from_example(example)
+            if isinstance(example, ExampleWithExpected):
+                nb_test += 1
+                if verdict.isSuccess():
+                    nb_test_ok += 1
+                    abstract['success'] += 1
+                else:
+                    abstract['failures'] += 1
+                empty = False
+            if isinstance(verdict, ExceptionVerdict):
+                abstract['errors'] += 1
+                empty = False
+            res_examples += f"** {verdict}\n\n"
+            if not verdict.isSuccess():
+                res_examples += f"   {verdict.get_details()}\n\n"
+        if not empty: 
+            res += f"* {test.get_name()} ~ {nb_test_ok}/{nb_test} réussis\n\n"
+        else:
+            abstract['empty'] += 1
+            res += f"* {test.get_name()}\n\n Aucun test trouvé !\n\n"
+        res += res_examples
+    res = f"Tests exécutés : {abstract['total']}\nSuccès: {abstract['success']}, \
+Echecs: {abstract['failures']}, Erreurs: {abstract['errors']}, \
+Vide: {abstract['empty']}\n\n" + res
+    return res
+
+
+def testmod(modulename: str):
+    """
+    mimic the doctest.testmod function
+    for `modulename` module
+    """
+    print(l1test_to_org(modulename))
+
+
diff --git a/Tp8/bataille-carte/apqueue.py b/Tp8/bataille-carte/apqueue.py
new file mode 100644
index 0000000..cdc44f7
--- /dev/null
+++ b/Tp8/bataille-carte/apqueue.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`apqueue` module
+
+:author: `FIL - Faculté des Sciences et Technologies -
+          Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2015, september
+:last revision: 2024, March
+
+A module for queue data structure.
+
+:Provides:
+
+* class ApQueue
+
+and methods
+
+* `enqueue`
+* `dequeue`
+* `is_empty`
+"""
+from typing import TypeVar
+T = TypeVar('T')
+
+class ApQueueEmptyError(Exception):
+    """
+    Exception for empty stacks
+    """
+    def __init__(self, msg):
+        self.message = msg
+
+
+class ApQueue():
+    """
+    $$$ ap_queue = ApQueue()
+    $$$ ap_queue.is_empty()
+    True
+    $$$ ap_queue.enqueue(1)
+    $$$ ap_queue.is_empty()
+    False
+    $$$ ap_queue.enqueue(2)
+    $$$ str(ap_queue)
+    '→2|1→'
+    $$$ ap_queue.dequeue()
+    1
+    $$$ ap_queue.dequeue()
+    2
+    $$$ ap_queue.is_empty()
+    True
+    $$e ap_queue.dequeue()
+    ApQueueEmptyError
+    """
+    ARROW = chr(0x2192)
+
+    def __init__(self):
+        """
+        build  a new empty queue
+        precondition: none
+        """
+        self.__content = []
+
+    def enqueue(self, elt: T):
+        """
+        insert an element at the begining of the queue
+        precondition: none
+        """
+        self.__content.insert(0, elt)
+
+    def dequeue(self) -> T:
+        """
+        return the element on top of self
+        Side effect: self contains an element less
+        precondition: self must be non empty
+        """
+        if len(self.__content) > 0:
+            res = self.__content.pop()
+        else:
+            raise ApQueueEmptyError('empty queue, nothing to dequeue')
+        return res
+
+    def is_empty(self) -> bool:
+        """
+        return:
+          * ``True`` if s is empty
+          * ``False`` otherwise
+        precondition: none
+        """
+        return self.__content == []
+
+    def __str__(self) -> str:
+        """
+        return the string representation of this queue.
+        """
+        return ApQueue.ARROW + \
+            "|".join(str(el) for el in self.__content) + \
+            ApQueue.ARROW
+
+
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('apqueue.py')
diff --git a/Tp8/bataille-carte/apstack.py b/Tp8/bataille-carte/apstack.py
new file mode 100644
index 0000000..d9a5121
--- /dev/null
+++ b/Tp8/bataille-carte/apstack.py
@@ -0,0 +1,126 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`stack` module
+
+:author: `FIL - Faculté des Sciences et Technologies - 
+          Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2015, september
+:last revision: 2017, october
+
+A module for stack data structure.
+
+:Provides:
+
+* class ApStack
+
+and methods
+
+* `push`
+* `pop`
+* `top`
+* `is_empty`
+
+:Examples:
+"""
+from typing import TypeVar
+T = TypeVar('T')
+
+class ApStackEmptyError(Exception):
+    """
+    Exception for empty stacks
+    """
+    def __init__(self, msg):
+        self.message = msg
+
+
+class ApStack():
+    """
+    $$$ stak = ApStack()
+    $$$ stak.is_empty()
+    True
+    $$$ stak.push(1)
+    $$$ stak.is_empty()
+    False
+    $$$ stak.push(2)
+    $$$ stak.top()
+    2
+    $$$ stak.pop()
+    2
+    $$$ stak.top()
+    1
+    $$$ stak.pop()
+    1
+    $$$ stak.is_empty()
+    True
+    $$e stak.pop()
+    ApStackEmptyError
+    """
+    
+    def __init__(self):
+        """
+        build a new empty stack
+        précondition : none
+        """
+        self.__content = []
+        
+    def push(self, el: T):
+        """
+        add el on top of the stack.
+        précondition : none
+        """
+        self.__content.append(el)
+
+    def pop(self) -> T:
+        """
+        return the element on top of self
+        
+        Side effect: self contains an element less
+        
+        précondition : self must be non empty
+        """
+        if len(self.__content) == 0:
+            raise ApStackEmptyError('empty stack, nothing to pop')
+        return self.__content.pop()
+
+    def top(self) -> T:
+        """
+        return the element on top of self without removing it
+        
+        précondition : self must be non empty
+        """
+        if len(self.__content) == 0:
+            raise ApStackEmptyError('empty stack, nothing to pop')
+        return self.__content[-1]
+
+    def is_empty(self) -> bool:
+        """
+        return:
+           * ``True`` if s is empty
+           * ``False`` otherwise
+                précondition : none
+        """
+        return self.__content == []
+
+    def __str__(self) -> str:
+        """
+        return a stack representation 
+        """
+        mlen = 1
+        if not self.is_empty():
+            mlen = max(len(str(el)) for el in self.__content)
+        res = []
+        for el in self.__content:
+            pad = mlen - len(str(el))
+            left = pad // 2
+            right = pad - left
+            res.insert(0, "|" + " " * left + str(el) + " " * right + "|")
+        res.append("+" + "-" * mlen + "+")
+        return "\n".join(res)
+
+
+if (__name__ == '__main__'):
+    import apl1test
+    apl1test.testmod('apstack.py')
diff --git a/Tp8/bataille-carte/card.py b/Tp8/bataille-carte/card.py
new file mode 100755
index 0000000..ce1e8e1
--- /dev/null
+++ b/Tp8/bataille-carte/card.py
@@ -0,0 +1,197 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`card` module 
+
+:author: `FIL - Faculté des Sciences et Technologies - 
+         Univ. Lille <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2017, september.
+:last revision: 2024, march
+
+"""
+from __future__ import annotations
+import random
+
+
+
+class Card(object):
+    """
+    Cards are defined by a value and a color.
+    Possible values and colors are listed in ``Card.VALUES`` and ``Card.COLORS``.
+
+    $$$ c1 = Card("Ace", "heart")
+    $$$ c1.color
+    'heart'
+    $$$ c1.value
+    'Ace'
+    $$$ c1
+    Card("Ace", "heart")
+    $$$ c2 = Card("King", "spade")
+    $$$ c2.value in Card.VALUES
+    True
+    $$$ c2.color in Card.COLORS
+    True
+    $$$ c1 == c1
+    True
+    $$$ c1 != c1
+    False
+    $$$ c1 < c1
+    False
+    $$$ c1 <= c1
+    True
+    """
+
+    ## tuple of possible values and colors in ascending order
+    VALUES = ("Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Knight", "Queen", "King")
+    COLORS = ("spade", "heart", "diamond", "club")
+
+    def __init__(self, value: str, color: str):
+        """
+        creates a card with value and color
+
+        précondition : value in VALUES and color in COLORS
+        """
+        self.value=value
+        self.color=color
+                        
+
+    def __hash__(self) -> int:
+        """
+        Renvoie un haché de self.
+        """
+        return hash((self.color,self.value))
+
+    def __repr__(self) -> str:
+        """
+        return a string representation of the card
+    
+        $$$ repr(Card('Ace', 'heart'))
+        'Card("Ace", "heart")'
+        """
+        return f"Card('{self.value}','{self.color}')"
+
+    def compare(self, card: Card) -> int:
+        """
+        compares cards.
+
+        Order on cards is defined  by order on values
+
+        return: 
+          
+           * a positive number if self is greater than card
+           * a negative number if self is lower than card
+           * 0 if self is the same than card
+
+        précondition: none
+        exemples: 
+
+        $$$ c1 = Card('Ace', 'heart')
+        $$$ c2 = Card('King', 'heart')
+        $$$ c3 = Card('Ace','spade')
+        $$$ c1bis = Card('Ace','heart')
+        $$$ c1.compare(c2) < 0
+        True
+        $$$ c2.compare(c1) > 0
+        True
+        $$$ c1.compare(c3) == 0
+        True
+        """
+        self_index=self.VALUES.index(self.value)
+        Card_index=self.VALUES.index(Card.value)
+        return self_index-card_index
+    
+    
+    @staticmethod
+    def deck(n_card: int) -> list[Card]:
+        """
+        return a list of `n_card` randomly chosen cards
+
+        precondition: n_card > 0 and n_card <= 4*13
+
+        Exemples:
+
+        $$$ cartes = Card.deck( 10 )
+        $$$ len(cartes) == 10
+        True
+        $$$ all( isinstance(c, Card) for c in cartes)
+        True
+        $$$ len(set(cartes))
+        len(cartes)
+        """
+        deck=[]
+        for i in range(n_Card):
+            value=random.choice(Card.VALUES)
+            color=random.choice(Card.COLORS)
+            card=Card(value,color)
+            deck.append(card)
+        return deck
+
+    def __eq__(self, card: Card) -> bool:
+        """
+        return True if self equals card
+               False otherwise
+        """
+        if self.value==card.value and self.color==card.color:
+            return True
+        else:
+            return False
+
+    def __neq__(self, card: Card) -> bool:
+        """
+        return True if self don't equal card
+               False otherwise
+        """
+        if self.value!=card.value and self.color!=card.color:
+            return True
+        else:
+            return False
+
+
+    def __lt__(self, card: Card) -> bool:
+        """
+        return True if self is strictly inferior to card
+               False otherwise
+        """
+        if self.VALUES.index(self.value) < self.VALUES.index(card.value):
+              return True
+        else:
+            return False
+
+
+    def __le__(self, card: Card) -> bool:
+        """
+        return True if self is inferior or equal to card
+               False otherwise
+        """
+        if self.VALUES.index(self.value) <= self.VALUES.index(card.value):
+              return True
+        else:
+            return False
+
+    def __gt__(self, card: Card) -> bool:
+        """
+        return True if self is strictly superior to card
+               False otherwise
+        """
+        if self.VALUES.index(self.value) > self.VALUES.index(card.value):
+              return True
+        else:
+            return False
+
+    def __ge__(self, card: Card) -> bool:
+        """
+        return True if self is superior or equal to card
+               False otherwise
+        """
+        if self.VALUES.index(self.value) >= self.VALUES.index(card.value):
+              return True
+        else:
+            return False
+
+
+if (__name__ == '__main__'):
+    import apl1test
+    apl1test.testmod('card.py')
+
diff --git a/Tp8/bataille-carte/war.py b/Tp8/bataille-carte/war.py
new file mode 100644
index 0000000..e1acacc
--- /dev/null
+++ b/Tp8/bataille-carte/war.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`war` game
+
+:author: `FIL - Faculté des Sciences et Technologies -
+         Univ. Lille <http://portail.fil.univ-lille1.fr>`
+
+:date: 2021, april.
+:last revision: 2024, march.
+"""
+
+from card import Card
+from apqueue import *
+from apstack import *
+
+
+def distribute(n_card: int) -> tuple[ApQueue, ApQueue]:
+    """
+    renvoie un couple (m1, m2) constitué de deux files,
+    contenant pour chacune `n_card` cartes
+
+    precondition : n_card > 0
+    exemples :
+
+    $$$ m1, m2 = distribute( 4 )
+    $$$ len(m1) == 4
+    True
+    $$$ len(m2) == 4
+    True
+    $$$ type(m1) == ApQueue
+    True
+    $$$ type(m2) == ApQueue
+    True
+    $$$ carte = m1.dequeue()
+    $$$ isinstance(carte, Card)
+    True
+    """
+    ...
+
+def gather_stack(main: ApQueue, pile: ApStack) -> None:
+    """
+    ajoute les carte de la pile dans la main
+
+    exemples :
+
+    $$$ cartes = Card.deck(4)
+    $$$ main = ApQueue()
+    $$$ pile = ApStack()
+    $$$ for c in cartes:
+    ...     pile.push(c)
+    $$$ gather_stack( main, pile )
+    $$$ len( main ) == 4
+    True
+    $$$ all( main.dequeue() == cartes[ 3 - i ] for i in range(3))
+    True
+    """
+    ...
+
+def play_one_round(m1: ApQueue, m2: ApQueue, pile: ApStack) -> None:
+    """
+    Simule une étape du jeu :
+    `j1`` et ``j2`` prennent la première carte de leur
+    main. On compare les deux cartes :
+
+    * Si la carte de ``j1`` est supérieure à celle de ``j2``, alors
+    ``j1`` remporte toutes les cartes de la pile ;
+    * Si la carte de ``j1`` est inférieure à celle de ``j2``, alors
+    ``j2`` remporte toutes les cartes de la pile ;
+    * Si les cartes sont égales, alors elles sont *empilées* sur la
+      pile.
+
+    precondition : m1 et m2 ne sont pas vides
+    """
+    ...
+
+def play(n_card: int, n_round: int) -> None:
+    """
+    simule une partie de bataille
+
+    n_card: le nombre de cartes à distribuer à chaque joueur.
+    n_round: le nombre maximal de tours
+    """
+    ...
+
+
+if __name__ == "__main__":
+    import apl1test
+    apl1test.testmod("war.py")
+
-- 
GitLab