Orienté objet en langage C: "○ ✕ game" a été refacturé et porté en Python

Déclencheur

J'ai vu le "[○ ✕ Game] de @ kei011](https://qiita.com/kei011/items/ea7bce8ce690bd56f9ff)". Le but des débutants est de terminer un programme qui fonctionne par eux-mêmes, c'est donc formidable d'y parvenir et d'afficher les résultats.

Cependant, j'ai été déçu que le code du programme soit commun aux débutants.

Refactoring

J'ai refactoré tout en étant conscient de l'orientation de l'objet. Je suis moi-même en train de refactoriser par essais et erreurs, donc si vous avez d'autres bonnes idées, je vous serais reconnaissant si vous pouviez commenter.

Commencez par lister les choses et les acteurs qui apparaissent dans le "○ ✕ jeu".

Tapez chacun d'eux.

De plus, j'ai tapé la chaîne de caractères string_t et la position point_t où la pierre est placée.

Code source du langage C

Voici le code source du langage C refactorisé.

tictactoe.c


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>

#ifdef __GNUC__
#define scanf_s scanf
#endif

#define SIZE (3)                        //Taille de la planche (verticale=côté)
typedef enum {
    SPACE   = '-',                      //Valeur quand il n'y a pas de pierre sur le plateau
    STONE_A = 'A',
    STONE_B = 'B',
} stone_t;                              //Pierre à mettre sur le plateau
typedef stone_t board_t[SIZE][SIZE];    //Planche
typedef int point_t;                    //Position du tableau xy(0 ~ STEP-1)
typedef int step_t;                     //Mettre à jour la différence
typedef const char *string_t;           //Chaîne

typedef struct player player_t; //Joueurs (personnes et ordinateurs)
struct player {
    string_t name;
    stone_t stone;
    string_t order;
    void (*play)(player_t *player, board_t board);
    player_t *opponent;
};

//Affichage du tableau
void show(board_t board)
{
    printf("★ Tableau actuel ★\n"
           "\n  x");
    for (point_t x = 0; x < SIZE; x++) {
        printf(" %2d", x);
    }
    printf("\n y -");
    for (point_t x = 0; x < SIZE; x++) {
        printf("---");
    }
    for (point_t y = 0; y < SIZE; y++) {
        printf("\n%2d| ", y);
        for (point_t x = 0; x < SIZE; x++) {
            printf(" %c ", board[y][x]);
        }
    }
    printf("\n");
}

//Vrai s'il y a une place sur le plateau
bool space(board_t board)
{
    for (point_t y = 0; y < SIZE; y++) {
        for (point_t x = 0; x < SIZE; x++) {
            if (board[y][x] == SPACE) {
                return true;
            }
        }
    }
    return false;
}

//Renvoie vrai si la pierre spécifiée suit le tableau et que la ligne est complète
bool follow(board_t board, stone_t stone, point_t y, point_t x, step_t dy, step_t dx)
{
    for (step_t i = 1; i < SIZE; i++) {
        y = (y + dy + SIZE) % SIZE;
        x = (x + dx + SIZE) % SIZE;
        if (board[y][x] != stone) {
            return false;
        }
    }
    return true;
}

//Lorsque la ligne est terminée sur le plateau avec la pierre spécifiée*py, *Définir px et renvoyer true
bool line(board_t board, stone_t first, stone_t other, point_t *py, point_t *px) {
    const step_t INCRESE_Y = 1, INCRESE_X = 1, DECRESE_X = -1, STAY_Y = 0, STAY_X = 0;
    for (point_t y = 0; y <SIZE ; y++) {
        for (point_t x = 0; x < SIZE; x++) {
            if (board[y][x] == first &&
                (follow(board, other, y, x, STAY_Y, INCRESE_X) ||   //côté
                 follow(board, other, y, x, INCRESE_Y, STAY_X))) {  //Verticale
                *py = y, *px = x;
                return true;
            }
        }
        point_t x = y;
        if (board[y][x] == first &&
            follow(board, other, y, x, INCRESE_Y, INCRESE_X)) {  //En bas à droite
            *py = y, *px = y;
            return true;
        }
        x = SIZE - 1 - y;
        if (board[y][x] == first &&
            follow(board, other, y, x, INCRESE_Y, DECRESE_X)) { //En bas à gauche
            *py = y, *px = x;
            return true;
        }
    }
    return false;
}

//Si vous êtes à portée de main*px, *Définir py et retourner vrai
bool reach(board_t board, stone_t stone, point_t *py, point_t *px)
{
    return line(board, SPACE, stone, py, px);
}

//Renvoie vrai si dans l'état de bingo
bool bingo(board_t board, stone_t stone)
{
    point_t y, x;
    return line(board, stone, stone, &y, &x);
}

//Entrée de position
point_t input(player_t *player, string_t target)
{
    printf("%s:%s(%c)de%Entre dans:", player->order, player->name, player->stone, target);
    point_t point;
    switch (scanf_s("%d", &point)) {
    case EOF:
        exit(1);
    case 1:
        if (0 <= point && point < SIZE) {
            return point;
        }
        break;
    default:
        scanf("%*s");  //Ignorer l'entrée
    }
    printf("La valeur est incorrecte.\n\n");
    return -1;
}

//Les gens jouent(Faites un pas)
void human(player_t *player, board_t board)
{
    while (true) {
        point_t x = input(player, "côté(x)");
        if (x < 0) continue;
        point_t y = input(player, "Verticale(y)");
        if (y < 0) continue;
        if (board[y][x] == SPACE) {
            board[y][x] = player->stone;
            return;
        }
        printf("La position spécifiée est incorrecte.\n\n");
    }
}

//L'ordinateur joue(Faites un pas)
void computer(player_t *player, board_t board)
{
    point_t y, x;
    if (reach(board, player->stone, &y, &x)) {
        //Choisissez votre portée
    } else if (reach(board, player->opponent->stone, &y, &x)) {
        //Interférer avec la portée de l'adversaire
    } else {
        y = 1, x = 1;  //milieu
        while (board[y][x] != SPACE) {
            y = rand() % SIZE, x = 0;
            while (x < SIZE - 1 && board[y][x] != SPACE) {
                x++;
            }
        }
    }
    board[y][x] = player->stone;
}

//Jeu d'alignement SIZE
void game() 
{
    player_t player1 = { "tu",       STONE_A, "Premier coup", human    },
             player2 = { "Ordinateur", STONE_B, "Deuxième attaque", computer },
             *player = &player1;
    player1.opponent = &player2;
    player2.opponent = &player1;
    board_t board;
    for (point_t y = 0; y < SIZE; y++) {
        for (point_t x = 0; x < SIZE; x++) {
            board[y][x] = SPACE;
        }
    }
    show(board);
    while (space(board)) {
        player->play(player, board);
        show(board);
        if (bingo(board, player->stone)) {
            printf("%la victoire!\n", player->name);
            return;
        }
        player = player->opponent;
    }
    printf("dessiner!\n");
}

int main(void)
{
    srand((unsigned int)time(NULL));

    game();

    return 0;
}

«M. Board, êtes-vous quelque part? «M. Board, ces trois pierres sont-elles alignées? "Vous, s'il vous plaît, faites un mouvement" "Ordinateur, faites un pas" En pensant à qui vous demandez, ce "qui" est utilisé comme nom de variable et premier argument de la fonction.

Port Python

J'ai essayé de porter le code source du langage C vers le langage orienté objet Python. Si vous pouvez lire le langage C, vous pouvez lire Python tel quel. «Qui» est défini comme une classe. Chaque fonction est attribuée à une classe en tenant compte de qui est le travail. Puisque "who" est "self" vu de l'intérieur de la classe, le premier argument est le nom de la variable self. Quand vous voulez appeler une fonction dans une classe, écrivez dans l'ordre de "who.function name (argument)", et il sera converti en "who, argument) ʻ dans la classe correspondante et appelé. .. Alors laissez le moi être le premier argument. Si vous avez un interpréteur Python3, vous pouvez l'exécuter en tapantpython tictactoe.py` à l'invite de commande. Je voulais garder l'écriture en langage C telle qu'elle est, donc j'évite autant que possible l'écriture de type Python.

tictactoe.py


from random import randint

SPACE = '-'    #Valeur quand il n'y a pas de pierre sur le plateau


class Board(list):  # typedef char board_t[3][3]; (list est un tableau)

    #Initialisation de la carte (nom spécial déterminé par Python)
    def __init__(self):
        super().__init__([ [ SPACE, SPACE, SPACE ],
                           [ SPACE, SPACE, SPACE ],
                           [ SPACE, SPACE, SPACE ] ])

    #Affichage du tableau
    def show(self):  # void show(board_t board)
        print("★ Tableau actuel ★\n\n"
              "  x 0 1 2\n"
              " y -------")
        for y in range(3):
            print(" %d| %c %c %c" % (y, self[y][0], self[y][1], self[y][2]))

    #Renvoie true s'il y a une place sur le plateau
    def space(self):  # bool_t space(board_t board)
        for y in range(3):
            for x in range(3):
                if self[y][x] == SPACE:
                    return True
        return False

    #Renvoie les coordonnées si les trois pierres spécifiées sont alignées sur le plateau, Aucune si elles ne sont pas alignées
    def line(self, stone1, stone2, stone3):  #Python peut renvoyer plusieurs valeurs comme valeurs de retour>Réduction d'argument avec
        for y in range(3):
            for x in range(3):
                if (self[y][x] == stone1 and
                    ((self[y][(x + 1) % 3] == stone2 and  #Cote à cote
                      self[y][(x + 2) % 3] == stone3) or
                     (self[(y + 1) % 3][x] == stone2 and  #Verticalement
                      self[(y + 2) % 3][x] == stone3))):
                    return (y, x)
            if (self[(y + 0) % 3][(y + 0) % 3] == stone1 and  #En bas à droite
                self[(y + 1) % 3][(y + 1) % 3] == stone2 and
                self[(y + 2) % 3][(y + 2) % 3] == stone3):
                return (y, y)
            if (self[(y + 0) % 3][(2 - y + 3) % 3] == stone1 and  #En bas à gauche
                self[(y + 1) % 3][(1 - y + 3) % 3] == stone2 and
                self[(y + 2) % 3][(0 - y + 3) % 3] == stone3):
                return (y, (2 - y + 3) % 3)
        return None

    #Renvoie la position si atteint, Aucun sinon
    def reach(self, stone):
        return self.line(SPACE, stone, stone)

    #Renvoie vrai si dans l'état de bingo
    def bingo(self, stone):
        return self.line(stone, stone, stone) is not None


class Player:

    def __init__(self, name, stone, order):
        self.name = name
        self.stone = stone
        self.order = order


class Human(Player):

    #Entrée de position
    def input(self, target):
        try:
            point = int(input("%s:%s(%c)de%Entre dans:" % (self.order, self.name, self.stone, target)))
            if 0 <= point <= 2:
                return point
        except ValueError:
            pass
        print("La valeur est incorrecte.\n")
        return -1

    #Jouer(Faites un pas)
    def play(self, board):
        while True:
            x = self.input("côté(x)")
            if x < 0: continue
            y = self.input("Verticale(y)")
            if y < 0: continue
            if board[y][x] == SPACE:
                board[y][x] = self.stone
                return
            print("La position spécifiée est incorrecte.\n")


class Computer(Player):

    #Jouer(Faites un pas)
    def play(self, board):
        position = board.reach(self.stone)  #Votre choix de portée
        if position is None:
            position = board.reach(self.opponent.stone)  #Interférer avec la portée de l'autre partie
        if position is None:
            y, x = 1, 1  #milieu
            while board[y][x] != SPACE:
                y, x = randint(0, 2), 0
                while x < 2 and board[y][x] != SPACE:
                    x += 1
            position = (y, x)
        y, x = position
        board[y][x] = self.stone


#Jeu à trois yeux
def main():
    player1 = Human("tu", 'A', "Premier coup")
    player2 = Computer("Ordinateur", 'B', "Deuxième attaque")
    player = player1
    player1.opponent = player2
    player2.opponent = player1
    board = Board()
    board.show()
    while board.space():
        player.play(board)
        board.show()
        if board.bingo(player.stone):
            print("%la victoire!" % player.name)
            return
        player = player.opponent
    print("dessiner!")
    return

if __name__ == '__main__':
    main()

Recommended Posts

Orienté objet en langage C: "○ ✕ game" a été refacturé et porté en Python
Comment générer une séquence en Python et C ++
Essayez de le faire avec GUI, PyQt en Python
Comment envelopper C en Python
Comment installer OpenCV sur Cloud9 et l'exécuter en Python
Implémenter le filtre FIR en langage Python et C
Ecrire le fichier O_SYNC en C et Python
Comment utiliser is et == en Python
Comment utiliser la bibliothèque C en Python
Qu'est-ce que la «programmation fonctionnelle» et «orientée objet»? Édition Python
POST JSON avec Python et recevez avec PHP
Pour représenter la date, l'heure, l'heure et les secondes en Python
Comment tracer l'autocorrélation et l'autocorrélation partielle avec Python
Résolution avec Ruby, Perl, Java et Python AtCoder ARC 086 C Hash Sorting
[Python] Comment nommer les données de table et les sortir avec csv (méthode to_csv)
Next Python en langage C
Notez que cibuildwheel construit python bwheel (y compris le module C ++) en masse avec CI et le télécharge sur PyPI
API C en Python 3
Convertir la date et l'heure zonées en temps Unixtime dans Python2.7
Essayez de créer un module Python en langage C
Écrire des tests en Python pour profiler et vérifier la couverture
[Python] Comment trier un dict dans une liste et une instance dans une liste
Comment utiliser Decorator dans Django et comment le créer
Python: peut être répété en lambda
Aller à la langue pour voir et se souvenir du langage Partie 7 C en langage GO
Script Python qui explore le flux RSS du statut Azure et le publie sur Hipchat
Je veux remplacer les variables dans le fichier de modèle python et le produire en masse dans un autre fichier
Il est facile d'exécuter SQL avec Python et de générer le résultat dans Excel
Un script qui compte jusqu'à 5 secondes et s'arrête dans le Python de Blender
[C / C ++] Passez la valeur calculée en C / C ++ à une fonction python pour exécuter le processus et utilisez cette valeur en C / C ++.
Pour vider stdout en Python
Comment échanger des éléments dans un tableau en Python et comment inverser un tableau.
Application pour afficher et rechercher des mémos locaux (agenda) en Python
Connectez-vous au site Web en Python
Résoudre le nombre de mots (équivalent au rang C de paiza) en Python
Considérez si la programmation était un anime en Python et C
[Introduction à l'application Udemy Python3 +] 36. Utilisation de In et Not
Afficher les nombres et les caractères affectés aux variables dans l'impression python
Conseils pour coder courts et faciles à lire en Python
Obtenez de manière récursive la liste Excel dans un dossier spécifique avec python et écrivez-la dans Excel.
Recherche binaire en Python / C ++
Un moyen standard de développer et de distribuer des packages en Python
J'ai essayé d'illustrer le temps et le temps du langage C
Astuces utiles liées à la liste et aux instructions en Python
[Python] J'ai installé le jeu depuis pip et j'ai essayé de jouer
Comparaison de l'utilisation des fonctions d'ordre supérieur dans Python 2 et 3
Pile et file d'attente en Python
Parler avec Python [synthèse vocale]
Le processus de création et d'amélioration du code Python orienté objet
Lire json avec C # et convertir en type dictionnaire (forcé)
Introduction à la vérification des effets Rédaction des chapitres 4 et 5 en Python
Unittest et CI en Python
Comment développer en Python
Comment exécuter des commandes et des scripts shell externes en python
Installez CaboCha dans l'environnement Ubuntu et appelez-le avec Python.
Essayez simplement de recevoir un webhook avec ngrok et Python
J'ai essayé d'implémenter le blackjack du jeu Trump en Python
Un moyen simple de visualiser le temps pris en Python et un moyen plus intelligent de l'améliorer
Résoudre Fizz Buzz (équivalent au rang C de paiza) en Python