Object-oriented in C: Refactored "○ ✕ game" and ported it to Python

Trigger

I saw @ kei011's "○ ✕ Game". The purpose of beginners is to complete a program that works on their own, so it's great to achieve that and post the results.

However, I was disappointed that the program code is common to beginners.

Refactoring

I refactored it while being aware of object orientation. I myself am refactoring through trial and error, so if you have any other good ideas, I would appreciate it if you could comment.

First, list the things and actors that appear in the "○ ✕ game".

Typedef each one.

In addition, I typedefed the string string_t and the position point_t to put the stone.

C language source code

Here is the refactored C source code.

tictactoe.c


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

#ifdef __GNUC__
#define scanf_s scanf
#endif

#define SIZE (3)                        //Board size (vertical=side)
typedef enum {
    SPACE   = '-',                      //Value when there are no stones on the board
    STONE_A = 'A',
    STONE_B = 'B',
} stone_t;                              //Stone to put on the board
typedef stone_t board_t[SIZE][SIZE];    //Board
typedef int point_t;                    //Board xy position(0 ~ STEP-1)
typedef int step_t;                     //Update diff
typedef const char *string_t;           //String

typedef struct player player_t; //Players (people and computers)
struct player {
    string_t name;
    stone_t stone;
    string_t order;
    void (*play)(player_t *player, board_t board);
    player_t *opponent;
};

//Board display
void show(board_t board)
{
    printf("★ Current table ★\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");
}

//True if there is a place on the board
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;
}

//Returns true if the specified stone follows the board and the row is complete
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;
}

//When the line is completed on the board with the specified stone*py, *Set px and return 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) ||   //side
                 follow(board, other, y, x, INCRESE_Y, STAY_X))) {  //Vertical
                *py = y, *px = x;
                return true;
            }
        }
        point_t x = y;
        if (board[y][x] == first &&
            follow(board, other, y, x, INCRESE_Y, INCRESE_X)) {  //Bottom right
            *py = y, *px = y;
            return true;
        }
        x = SIZE - 1 - y;
        if (board[y][x] == first &&
            follow(board, other, y, x, INCRESE_Y, DECRESE_X)) { //Bottom left
            *py = y, *px = x;
            return true;
        }
    }
    return false;
}

//If you are in reach*px, *Set py and return true
bool reach(board_t board, stone_t stone, point_t *py, point_t *px)
{
    return line(board, SPACE, stone, py, px);
}

//Returns true if in bingo state
bool bingo(board_t board, stone_t stone)
{
    point_t y, x;
    return line(board, stone, stone, &y, &x);
}

//Position input
point_t input(player_t *player, string_t target)
{
    printf("%s:%s(%c)of%Enter s:", 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");  //Discard input
    }
    printf("The value is incorrect.\n\n");
    return -1;
}

//People play(Take a move)
void human(player_t *player, board_t board)
{
    while (true) {
        point_t x = input(player, "side(x)");
        if (x < 0) continue;
        point_t y = input(player, "Vertical(y)");
        if (y < 0) continue;
        if (board[y][x] == SPACE) {
            board[y][x] = player->stone;
            return;
        }
        printf("The specified position is incorrect.\n\n");
    }
}

//Computer play(Take a move)
void computer(player_t *player, board_t board)
{
    point_t y, x;
    if (reach(board, player->stone, &y, &x)) {
        //Choose your reach
    } else if (reach(board, player->opponent->stone, &y, &x)) {
        //Interfere with the reach of the opponent
    } else {
        y = 1, x = 1;  //middle
        while (board[y][x] != SPACE) {
            y = rand() % SIZE, x = 0;
            while (x < SIZE - 1 && board[y][x] != SPACE) {
                x++;
            }
        }
    }
    board[y][x] = player->stone;
}

//SIZE line-up game
void game() 
{
    player_t player1 = { "you",       STONE_A, "First strike", human    },
             player2 = { "Computer", STONE_B, "Second attack", 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("%s victory!\n", player->name);
            return;
        }
        player = player->opponent;
    }
    printf("draw!\n");
}

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

    game();

    return 0;
}

"Mr. board, are you somewhere?" "Mr. board, are these three stones lined up?" "You, please do one move" "Computer, take a step" Thinking about who you are asking for, that "who" is used as the variable name and the first argument of the function.

Python port

I ported the C source code to Python, an object-oriented language. If you can read C language, you can read Python as it is. "Who" is defined as a class. Each function is assigned to a class considering who the job is. Since "who" is "self" when viewed from inside the class, the first argument is the variable name self. When you want to call a function in a class, write it in the order of "who.function name (argument)", and it will be converted to "function in the corresponding class (who, argument)" and called. .. So, let self be the first argument. If you have a Python3 interpreter, you can run it by typing python tictactoe.py at the command prompt. I wanted to keep the C language as it is, so I avoid Python-like writing as much as possible.

tictactoe.py


from random import randint

SPACE = '-'    #Value when there are no stones on the board


class Board(list):  # typedef char board_t[3][3]; (list is an array)

    #Board initialization (special name determined by Python)
    def __init__(self):
        super().__init__([ [ SPACE, SPACE, SPACE ],
                           [ SPACE, SPACE, SPACE ],
                           [ SPACE, SPACE, SPACE ] ])

    #Board display
    def show(self):  # void show(board_t board)
        print("★ Current table ★\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]))

    #Return true if there is a place on the board
    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

    #If the specified three stones are lined up on the board, the coordinates are returned, if not lined up, None
    def line(self, stone1, stone2, stone3):  #Python can return multiple values as a return value>Argument reduction with
        for y in range(3):
            for x in range(3):
                if (self[y][x] == stone1 and
                    ((self[y][(x + 1) % 3] == stone2 and  #Side by side
                      self[y][(x + 2) % 3] == stone3) or
                     (self[(y + 1) % 3][x] == stone2 and  #Vertically
                      self[(y + 2) % 3][x] == stone3))):
                    return (y, x)
            if (self[(y + 0) % 3][(y + 0) % 3] == stone1 and  #Bottom right
                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  #Bottom left
                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

    #Returns position if reach, None if not
    def reach(self, stone):
        return self.line(SPACE, stone, stone)

    #Returns true if in bingo state
    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):

    #Position input
    def input(self, target):
        try:
            point = int(input("%s:%s(%c)of%Enter s:" % (self.order, self.name, self.stone, target)))
            if 0 <= point <= 2:
                return point
        except ValueError:
            pass
        print("The value is incorrect.\n")
        return -1

    #To play(Take a move)
    def play(self, board):
        while True:
            x = self.input("side(x)")
            if x < 0: continue
            y = self.input("Vertical(y)")
            if y < 0: continue
            if board[y][x] == SPACE:
                board[y][x] = self.stone
                return
            print("The specified position is incorrect.\n")


class Computer(Player):

    #To play(Take a move)
    def play(self, board):
        position = board.reach(self.stone)  #Your reach choice
        if position is None:
            position = board.reach(self.opponent.stone)  #Interfering with the reach of the other party
        if position is None:
            y, x = 1, 1  #middle
            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


#Tic-tac-toe game
def main():
    player1 = Human("you", 'A', "First strike")
    player2 = Computer("Computer", 'B', "Second attack")
    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("%s victory!" % player.name)
            return
        player = player.opponent
    print("draw!")
    return

if __name__ == '__main__':
    main()

Recommended Posts

Object-oriented in C: Refactored "○ ✕ game" and ported it to Python
How to generate permutations in Python and C ++
Try to make it using GUI and PyQt in Python
How to wrap C in Python
How to install OpenCV on Cloud9 and run it in Python
Implement FIR filters in Python and C
Write O_SYNC file in C and Python
How to use is and == in Python
How to use the C library in Python
What is "functional programming" and "object-oriented" in Python?
POST JSON in Python and receive it in PHP
To represent date, time, time, and seconds in Python
How to plot autocorrelation and partial autocorrelation in python
Sorting AtCoder ARC 086 C hashes to solve in Ruby, Perl, Java and Python
[Python] How to name table data and output it in csv (to_csv method)
Next Python in C
Note that cibuildwheel builds python bwheel (including C ++ module) in bulk with CI and uploads it to PyPI
C API in Python 3
Convert timezoned date and time to Unixtime in Python2.7
Try to make a Python module in C language
Write tests in Python to profile and check coverage
[Python] How to sort dict in list and instance in list
Deep nesting in Python makes it hard to read
How to use Decorator in Django and how to make it
I was able to repeat it in Python: lambda
Go language to see and remember Part 7 C language in GO language
A Python script that crawls RSS in Azure Status and posts it to Hipchat
I want to replace the variables in the python template file and mass-produce it in another file.
It is easy to execute SQL with Python and output the result in Excel
Script to count and stop up to 5 seconds in Python in Blender
[C / C ++] Pass the value calculated in C / C ++ to a python function to execute the process, and use that value in C / C ++.
To flush stdout in Python
Temporarily save a Python object and reuse it in another Python
How to swap elements in an array in Python, and how to reverse an array.
Application to display and search local memos (diary) in Python
Login to website in Python
Solve word counts (equivalent to paiza rank C) in Python
Consider If Programming Was An Anime in Python and C
[Introduction to Udemy Python 3 + Application] 36. How to use In and Not
Display numbers and letters assigned to variables in python print
Tips for coding short and easy to read in Python
Recursively get the Excel list in a specific folder with python and write it to Excel.
Binary search in Python / C ++
A standard way to develop and distribute packages in Python
I tried to illustrate the time and time in C language
Useful tricks related to list and for statements in Python
[Python] I installed the game from pip and played it
Comparison of how to use higher-order functions in Python 2 and 3
Stack and Queue in Python
Speech to speech in python [text to speech]
The process of making Python code object-oriented and improving it
Read json in C # and convert to dictionary type (forced)
Introduction to Effectiveness Verification Chapters 4 and 5 are written in Python
Unittest and CI in Python
How to develop in Python
How to execute external shell scripts and commands in python
Install CaboCha in Ubuntu environment and call it with Python.
Just try to receive a webhook in ngrok and python
I tried to implement blackjack of card game in Python
An easy way to view the time taken in Python and a smarter way to improve it
Solve Fizz Buzz (equivalent to paiza rank C) in Python