{"id":22273516,"url":"https://github.com/dfleta/yatzy-refactoring-kata","last_synced_at":"2026-02-05T09:38:29.966Z","repository":{"id":94648514,"uuid":"447588056","full_name":"dfleta/yatzy-refactoring-kata","owner":"dfleta","description":"Yatzy refactoring kata ","archived":false,"fork":false,"pushed_at":"2025-01-09T11:02:52.000Z","size":30,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-09T12:20:54.000Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfleta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-01-13T12:17:49.000Z","updated_at":"2025-01-09T11:02:57.000Z","dependencies_parsed_at":"2024-01-18T10:30:57.055Z","dependency_job_id":"f1260b45-33a9-47b3-b52c-f113cc7ed965","html_url":"https://github.com/dfleta/yatzy-refactoring-kata","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fyatzy-refactoring-kata","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fyatzy-refactoring-kata/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fyatzy-refactoring-kata/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfleta%2Fyatzy-refactoring-kata/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfleta","download_url":"https://codeload.github.com/dfleta/yatzy-refactoring-kata/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236369124,"owners_count":19138053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-03T13:13:01.744Z","updated_at":"2026-02-05T09:38:29.958Z","avatar_url":"https://github.com/dfleta.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# Yatzy Refactoring Kata\n\n**Kata readme by [Emily Bache](https://github.com/emilybache)** Thanks!! :clap::clap:\n\n[Emily Bache kata repo](https://github.com/emilybache/Yatzy-Refactoring-Kata)\n\n*Designed by Jon Jagger. It's available in his Cyber-Dojo. [Blog post](http://jonjagger.blogspot.co.uk/2012/05/yahtzee-cyber-dojo-refactoring-in-java.html)*\n\n## Kata: Yatzy rules\n\nThe game of Yatzy is a simple dice game. Each player\nrolls five six-sided dice. They can re-roll some or all\nof the dice up to three times (including the original roll).\n\nFor example, suppose a players rolls:\n\n    3,4,5,5,2\n    \nThey hold (-,-,5,5,-) and re-roll (3,4,-,-,2):\n\n    5,1,5,5,3\n\nThey hold (5,-,5,5,-) and re-roll (-,1,-,-,3):\n\n    5,6,5,5,2\n\nThe player then places the roll in a category, such as ones,\ntwos, fives, pair, two pairs etc (see below). If the roll is\ncompatible with the category, the player gets a score for the\nroll according to the rules. If the roll is not compatible\nwith the category, the player scores zero for the roll.\n\nFor example, suppose a player scores 5,6,5,5,2 in the fives\ncategory they would score 15 (three fives). The score for\nthat go is then added to their total and the category cannot\nbe used again in the remaining goes for that game.\nA full game consists of one go for each category. Thus, for\ntheir last go in a game, a player must choose their only\nremaining category.\n\nYour task is to score a GIVEN roll in a GIVEN category.\nYou do NOT have to program the random dice rolling.\nThe game is NOT played by letting the computer choose the\nhighest scoring category for a given roll.\n  \n## Kata: Yatzy Categories and Scoring Rules\n\n### Chance\n\nThe player scores the sum of all dice, no matter what they read.\nFor example:\n  \n- 1,1,3,3,6 placed on \"chance\" scores 14 (1+1+3+3+6)\n- 4,5,5,6,1 placed on \"chance\" scores 21 (4+5+5+6+1)  \n\n### Yatzy\n\nIf all dice have the same number, the player scores 50 points.\nFor example:\n  \n- 1,1,1,1,1 placed on \"yatzy\" scores 50\n- 1,1,1,2,1 placed on \"yatzy\" scores 0\n\n### Ones, Twos, Threes, Fours, Fives, Sixes\n\nThe player scores the sum of the dice that reads one, two, three, four, five or six, respectively.For example:\n\n- 1,1,2,4,4 placed on \"fours\" scores 8 (4+4)\n- 2,3,2,5,1 placed on \"twos\" scores 4  (2+2)\n- 3,3,3,4,5 placed on \"ones\" scores 0\n\n### Pair\n\nThe player scores the sum of the two highest matching dice.\nFor example, when placed on \"pair\":\n  \n- 3,3,3,4,4 scores 8 (4+4)\n- 1,1,6,2,6 scores 12 (6+6)\n- 3,3,3,4,1 scores 6 (3+3)\n- 3,3,3,3,1 scores 6 (3+3)\n\n### Two pairs\n\nIf there are two pairs of dice with the same number, the player scores the sum of these dice. For example, when placed on \"two pairs\":\n  \n- 1,1,2,3,3 scores 8 (1+1+3+3)\n- 1,1,2,3,4 scores 0\n- 1,1,2,2,2 scores 6 (1+1+2+2)\n\n### Three of a kind\n\nIf there are three dice with the same number, the player\nscores the sum of these dice.\n\nFor example, when placed on \"three of a kind\":\n\n- 3,3,3,4,5 scores 9 (3+3+3)\n- 3,3,4,5,6 scores 0\n- 3,3,3,3,1 scores 9 (3+3+3)\n\n### Four of a kind\n\nIf there are four dice with the same number, the player scores the sum of these dice.\n\nFor example, when placed on \"four of a kind\":\n  \n- 2,2,2,2,5 scores 8 (2+2+2+2)\n- 2,2,2,5,5 scores 0\n- 2,2,2,2,2 scores 8 (2+2+2+2)\n\n### Small straight\n\nWhen placed on \"small straight\", if the dice read\n\n   1,2,3,4,5,\n\nthe player scores 15 (the sum of all the dice).\n\n### Large straight\n\nWhen placed on \"large straight\", if the dice read\n\n    2,3,4,5,6,\n\nthe player scores 20 (the sum of all the dice).\n\n### Full house\n\nIf the dice are two of a kind and three of a kind, the player scores the sum of all the dice.\n\nFor example, when placed on \"full house\":\n\n- 1,1,2,2,2 scores 8 (1+1+2+2+2)\n- 2,2,3,3,4 scores 0\n- 4,4,4,4,4 scores 0\n\n---\n\n## Métodos de clase en Python: `@staticmethod` vs `@classmethod`\n\nLee el código en [`yatzy_refactored.py`](./src/yatzy_refactored.py)\n\n### Objetivo 🎯\n\nExplicar, con ejemplos prácticos sacados de `src/yatzy_refactored.py`, cuándo y por qué usar `@staticmethod` y `@classmethod` en Python.\n\n---\n\n### Resumen breve ✅\n\n- `@staticmethod`: función ligada a la clase por SRP; **no recibe** ni `self` ni `cls`. Útil para operaciones puramente funcionales relacionadas con la clase que no necesitan acceder al estado de una instancia o de la clase.\n\n- `@classmethod`: método que recibe la **clase** como primer argumento (`cls`). Útil cuando el comportamiento necesita acceder o modificar datos de clase, o cuando queremos que el método sea heredable por subclases.\n\n---\n\n### Diferencias 🔍\n\n- Signatura: `def f(*args)` vs `def f(cls, *args)`\n- Acceso: no puede usar atributos de clase (`staticmethod`) ↔ usa `cls` para acceder/alterar atributos o invocar otros métodos de clase\n- Heredabilidad: `classmethod` respeta la clase que llama; `staticmethod` es independiente de la clase que la contiene\n\n---\n\n### Ejemplos del proyecto 🔧\n\n#### 1- `@staticmethod` — función pura relacionada con la lógica del juego\n\n```python\n@staticmethod\ndef chance(*dice):\n    return sum(dice)\n\n@staticmethod\ndef yatzy(*dice):\n    return Yatzy.FIFTY if len(set(dice)) == 1 else Yatzy.ZERO\n```\n\nPor qué usamos `staticmethod` aquí:\n\n- Estas funciones calculan un resultado a partir de los argumentos (`dice`) y **no necesitan** acceder a la instancia (`self`) ni a la clase (`cls`).\n- Son utilitarias: su comportamiento no cambia si la clase se hereda.\n\n#### 2- `@classmethod` — necesita conocer la clase o usar otros métodos de clase\n\n```python\n@classmethod\ndef pair(cls, *dice):\n    PAIR = Pips.TWO.value\n    pip = cls.__biggest_pip_repeated(dice, PAIR)\n    return pip * PAIR if pip else Yatzy.ZERO\n\n@classmethod\ndef small_straight(cls, *dice):\n    return cls.chance(*dice) if not Pips.minus(Pips.SIX) - set(dice) else Yatzy.ZERO\n```\n\nPor qué usamos `classmethod` aquí:\n\n- `pair` y `small_straight` llaman a otros métodos que pertenecen a la clase (por ejemplo `cls.__biggest_pip_repeated`, `cls.chance`). Usar `cls` permite que una subclase que reimplemente esos métodos conserve el comportamiento correcto.\n- `classmethod` facilita la extensibilidad y la reutilización por herencia.\n\n#### 3- Método de instancia\n\n```python\ndef fours(self):\n    return self.__sum_dice_equals(Pips.FOUR.value)\n```\n\nEste método usa `self.dice`, el estado de una instancia u objeto de la clase, por eso NO puede ser `@staticmethod` ni `@classmethod`.\n\n---\n\n### Buenas prácticas y recomendaciones 💡\n\n- Usa `@staticmethod` para utilidades que no requieren ni `cls` ni `self` (pure functions relacionadas conceptualmente con la clase).\n- Usa `@classmethod` cuando el método **debe conocer la clase** que lo invoca (para acceder a atributos de clase, construir instancias, o apoyar herencia).\n- Preferir `cls.CONSTANT` dentro de `@classmethod` para mantener compatibilidad con subclases.\n- Evitar mezclar responsabilidades: si el método necesita estado de instancia, debe ser un método de instancia.\n\n---\n\n### Preguntas tipo examen (con respuestas) ✅\n\n1. ¿Qué recibe siempre un `@classmethod` como primer argumento? — `cls` (la clase que llama).\n2. ¿Es `@staticmethod` heredable por una subclase? — Sí, pero no obtiene ninguna referencia a la subclase a menos que se le pase explícitamente.\n3. Verdadero/Falso: Un `@classmethod` puede llamar a otros `@classmethod` usando `cls`. — Verdadero.\n\n---\n\n### Conexión con `Pips` (enum) 🧩\n\n`Pips.reversedValues()` y `Pips.minus()` están definidos como `@classmethod` en el `Enum`: eso tiene sentido porque operan sobre los miembros de la clase `Enum` y su comportamiento debe ser coherente con la clase, no con una instancia concreta.\n\n---\n\n### Referencia `cls`\n\n`cls` es el primer parámetro obligatorio de un `@classmethod`: recibe la clase que invoca el método, no una instancia de la clase (`self`).\n\nPermite acceder a atributos y otros métodos de la misma clase, y respeta la herencia (si una subclase llama, cls apunta a esa subclase).\n\n### Ejemplos en `yatzy_refactored.py`\n\n```python\n  @classmethod\n    def pair(cls, *dice):\n        PAIR = Pips.TWO.value\n        pip = cls.__biggest_pip_repeated(dice, PAIR)\n        return pip * PAIR if pip else cls.ZERO\n```\n\n`@classmethod def pair(cls, *dice)` calcula la suma de los dos mayores dados iguales, sino devuelve cero.\n\nReutiliza el método de clase `cls.__biggest_pip_repeated` que devuelve los dos mayores dados que coinciden. Este método encapsula una responsabilidad que es reutilizada por otros métodos de la clase. Tiene visibilidad *privada*.\n\nPara acceder a este método de clase, usamos la referencia `cls` desde los métodos que lo invocan.\n\nAdemás, necesitamos acceder al valor `ZERO`, una constante de la clase, pues es utilizada por otros métodos de la clase para las computaciones de los dados. La refencia a esa constante en la clase es `cls.ZERO`.\n\nSi una subclase redefine `__biggest_pip_repeated`, cls garantiza que se use la versión de la subclase.\n\nEl *helpers* privado `__biggest_pip_repeated` acepta `cls` para poder operar sobre la clase (y sus posibles subclases) al filtrar pips.\n\n### Tipos de referencias\n\n`self` → instancia (estado concreto).\n`cls` → clase: configuración/versión actual de la clase, útil para herencia.\n\nSin `self` ni `cls` → `@staticmethod` o función pura vinculada solo conceptualmente a la clase.\n\n---\n\n### Prompt\n\n`#file:yatzy_refactored.py #file:test_yatzy_from_scratch.py #file:pips.py`\n\nHe resuelto el kata Yatzy sobre refactorización.\n\nUtilizo este kata como introducción a la programación orientada a objetos en Python y, en particular, a los distintos tipos de métodos de clase: `staticmethod` y `classmethod`.\n\nRedacta un fichero markdown para mi alumnado de formación profesional de desarrollo de aplicaciones multiplataforma en el módulo de programación donde expliques los conceptos de programación Python y orientada a objetos sobre los métodos de clase `staticmethod` y `classmethod` utilizando los métodos del fichero #file:yatzy_refactored.py como ejemplo.\ncls\nEl manual de referencia que usamos en el aula es Learning Python de Mark Lutz.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfleta%2Fyatzy-refactoring-kata","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfleta%2Fyatzy-refactoring-kata","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfleta%2Fyatzy-refactoring-kata/lists"}