I made Othello to teach Python3 to children (6) Final episode

Let's explain the Othello class Part 3

"Examine the frame next to X and Y passed to the function and the frame next to it" function

Well, it may be the most difficult, but I will explain it. The Othello class function ʻot_next_onepeace () `explained below is a function with the function " Examine the frame next to X and Y passed to the function and the frame next to it ". This is a function that makes this word very important. I'll say it again. This function only executes ** "Examine the frame next to X and Y passed to the function and the frame next to it" **. Even if the squares of the Othello board are 100x100, this function only executes ** "examine the frame next to X and Y passed to the function and the frame next to it" **. is.

Because it is a "function that you call yourself (recursive function)"!

If you decide that you can place a piece in no small measure, you have to turn over all the directions that can be turned over. For that purpose, is it possible to turn over in eight directions? How far can you turn it over? You have to think about it.

In this function, for example, if ● is placed at a specific coordinate, the X and Y coordinates where it is placed and the key character in the direction you want to check are passed as arguments, and ** "of the X and Y passed to the function. Examine the next frame and the frame next to it "**. (It's persistent!)

The key of the dictionary variable ʻot_direction, which represents the coordinates next to the eight directions, is passed as the third argument. Key strings such as'ul'and'up'. The tuple array [0]that matches that key string contains a number that represents the hand next to the X coordinate. If you are looking to the left, -1 is included. It is 0 if it is directly above or below, +1 if it is to the right, and so on. Similarly, thetuple array [1]contains a number representing the hand next to the Y coordinate. Store thistuple array [0]in a variable called nx and thetuple array [1]in a variable called ny. The method for accessing the dictionary array is ʻot_direction [key character (third argument)] [tuple array subscript]. Don't forget this way. If there is only one value for the key, it is accessed by the same access method as the one-dimensional array ʻot_direction [key character (third argument)] `. This time, it is a tuple array for the key string, so it has the same access method as the two-dimensional array.

        self.ot_direction = { 'ul' : ( -1 , -1 ) ,  #Diagonally above left
                              'up' : (  0 , -1 ) ,  #Right above
                              'ur' : ( +1 , -1 ) ,  #Diagonally above right
                              'lt' : ( -1 ,  0 ) ,  #left
                              'rt' : ( +1 ,  0 ) ,  #right
                              'dl' : ( -1 , +1 ) ,  #Diagonally below left
                              'dn' : (  0 , +1 ) ,  #Directly below
                              'dr' : ( +1 , +1 ) }  #Diagonally below right

The X coordinate ʻot_x and the Y coordinate ʻot_y where the frame is placed are passed to the first and second arguments of this function. On the other hand, by adding the following nx and ny, the frame in the direction to be searched is determined. If you look at the X coordinate ʻot_x passed in that argument and next to and next to the Y coordinate ʻot_y, shift it by one and call your function again. It looks like this in the figure.

スクリーンショット 2020-05-28 0.01.45.png

  1. The first time, check the frame to the left of X = 6, Y = 5, and the frame to the left of it. (○ and ○!)
  2. This function shifts the values passed by ot_x and ot_y by one according to the instructions of the numbers in the tuple array of dictionary variables, and calls its function again.
  3. The arguments of the function called the second time are X = 5, Y = 5. From there, check the frame to the left and the frame to the left. (It's ○ and ○ again !!)
  4. Again, this function shifts the values passed by ot_x and ot_y by one according to the instructions of the numbers in the tuple array of dictionary variables, and calls its function again.
  5. The arguments of the function called the third time are X = 4, Y = 5. From there, check the frame to the left and the frame to the left. (It's ○ and ○ again !!)
  6. Again, this function shifts the values passed by ot_x and ot_y by one according to the instructions of the numbers in the tuple array of dictionary variables, and calls its function again.
  7. The arguments of the function called the fourth time are X = 3, Y = 5. From there, check the frame to the left and the frame to the left. Since a frame continuous with ○ ● appears, store the black position in ʻot_lastposX and ʻot_lastposY as a position where you can turn it over, and this function ends.

Even if the frame to the left and the frame to the left are ○○, if the result of shifting by one and continuing to call yourself does not become ○ ● as shown in the figure below (○ ・)? (End with ○) is judged that it cannot be placed, and the function ends.

スクリーンショット 2020-05-28 0.07.15.png

What do you think? Did you somehow understand the recursive function? To be honest, there are only 8 squares in the vertical and horizontal directions, so it is not necessary to make it a recursive function, but in addition to the fact that the code is likely to be redundant, this idea may be a little difficult considering the point that it can be applied. Tried to use a recursive function.

As an aside, with this function, it may be an ant to make the frame in the specified direction into one character string and search for it with a regular expression with ^ ○ + ● and replace it. I thought about it, but it wasn't fun programmatically, so I dropped it.

    #Processing to put the next move (including processing that cannot be placed)
    def ot_next_onepeace(self,ot_x,ot_y,ot_dir):
        #When the next hand in all directions from your position is the opposite hand and your own hand
        nx = self.ot_direction[ot_dir][0]
        ny = self.ot_direction[ot_dir][1]

        #Judgment that the next move cannot be placed in the first place
        if ( nx < 0 and ot_x == 1 ) or ( ny < 0 and ot_y == 1 ) or ( nx == 1 and ot_x == 8 ) or ( ny == 1 and ot_y == 8 ):
            return -1

        #Get the next one (left and top are in the minus direction when viewed from your hand)
        nextpeace = self.ot_peace(ot_x+nx,ot_y+ny)

        #Judgment that you can not put it if the next hand is your own hand
        if nextpeace == '・' or nextpeace == self.ot_offdef:
            return -1

        #Determine if there is a neighbor next door
        cx = ot_x+(nx*2)
        cy = ot_y+(ny*2)

        #Judged that it cannot be placed if there is no neighbor next to it (if the direction is left or top, judge the left end and the top)
        if ( nx < 0 and cx == 0 ) or ( nx > 0 and cx == 9 ) or ( ny < 0 and cy == 0 ) or ( ny > 0 and cy == 9 ):
            return -1

        #I can get the next one, so look for it
        nextnextpeace = self.ot_peace(cx,cy)

        if nextnextpeace == '・' :
            return -1         #I can't turn it over Notification

        if nextnextpeace == self.ot_offdef:
            #Record the end position that can be turned over
            self.ot_lastposX = cx
            self.ot_lastposY = cy
            return 1         #You can turn it over Notification

        #If your hand and your hand continue, call your function again (recursive)
        return self.ot_next_onepeace(ot_x+nx, ot_y+ny, ot_dir)

A function that flips only one opponent's frame in the specified direction (also a recursive function)

Yes, this function is pretty much the same as the previous one.

We are processing to replace the opponent's frame with your own frame in the direction specified in the third. However, this function also replaces only the frames next to the X and Y coordinates passed as arguments.

Now flip one, shift the values passed by ot_x and ot_y by one according to the instructions of the numbers in the tuple array of dictionary variables, and call your function again. If the coordinates next to it match ot_lastposX and ot_lastposY, the process ends.

    #The process of turning over the hand
    def ot_changepeace(self,ot_x,ot_y,ot_dir):
        #When the next hand in all directions from your position is the opposite hand and your own hand
        nx = self.ot_direction[ot_dir][0]
        ny = self.ot_direction[ot_dir][1]
        #Turn over the next one
        nextpeace = self.ot_peace(ot_x+nx,ot_y+ny,self.ot_offdef)

        #Determine if the next to the next is the final position
        cx = ot_x+(nx*2)
        cy = ot_y+(ny*2)

        #End if next to next is the final position
        if cx == self.ot_lastposX and cy == self.ot_lastposY:
            return
        return self.ot_changepeace(ot_x+nx, ot_y+ny, ot_dir)

I will explain the last two class functions and finish.

The ʻot_peace () `function has two roles.

  1. Returns the frame with the specified coordinates as the return value of the function
  2. If a frame is specified in the third argument, the frame with the specified coordinates will be replaced with the argument frame.

What I found interesting in Python is that you can specify default values for function arguments and omit those arguments. Therefore, when calling ʻot_peace () `, there are cases where there are two arguments and cases where there are three arguments, and the processing changes depending on the above roles.

Now, the last Othello class function is the board display function ʻot_display () `. As I said at the beginning, this function is responsible for displaying the data stored in the ot_bit array in 8X8 squares and for displaying the number of ● and ○.

   #Get the hand at the specified position (and rewrite it as well)
    def ot_peace(self,ot_x,ot_y,ot_chr=None):
        if ot_chr != None:
            self.ot_bit[(ot_y - 1) * 8 + (ot_x - 1)] = ot_chr
        return self.ot_bit[(ot_y-1)*8+(ot_x-1)]

    #Display the board of Othello
    def ot_display(self):
        print("X① ② ③ ④ ⑤ ⑥ ⑦ ⑧")
        for l in range(1,9):
            print("{}".format(l), end='' )
            for c in range(1,9):
                print(" {}".format(self.ot_bit[(l-1)*8+(c-1)]), end='')
            print()
        print("            ○:{} ●:{}".format(self.ot_bit.count('○'),self.ot_bit.count('●')))

How was it? Isn't the seemingly esoteric Othello-class program gradually becoming more meaningful? ** The goodness of this program is that it works for the time being **. And the step to improve programming is to read the source code of others, and to modify it and add elements to play with it.

This is the end of the program explanation, but after a while, I will make a graphical Othello game using PyQt5 and come back here again. Until then, please enjoy playing around with Python! !!

See you again! !!

c u

    print("to be continue...")

Recommended Posts

I made Othello to teach Python3 to children (6) Final episode
I made Othello to teach Python3 to children (4)
I made Othello to teach Python3 to children (2)
I made Othello to teach Python3 to children (5)
I made Othello to teach Python3 to children (3)
I made Othello to teach Python3 to children (1)
I made a password generator to teach Python3 to children (bonus) * Completely remade
I made a Python module to translate comment outs
I made a python library to do rolling rank
I made an action to automatically format python code
I made blackjack with python!
I made a python text
I made blackjack with Python.
Othello made with python (GUI-like)
I made wordcloud with Python.
I made a package to filter time series with python
Introduction to her made with Python ~ Tinder automation project ~ Episode 5
Mayungo's Python Learning Episode 3: I tried to print numbers with print
I made an animation to return Othello stones with POV-Ray
I made a library to easily read config files with Python
I made a Line-bot using Python!
I tried to touch Python (installation)
I made my own Python library
I made a fortune with Python.
Othello game development made with Python
I tried to teach Python to those who have no programming experience
I made a library that adds docstring to a Python stub file.
I want to debug with Python
I made a daemon with Python
I made a Docker container to use JUMAN ++, KNP, python (for pyKNP).
[Python] I made a decorator that doesn't seem to have any use.
I made a tool to automatically browse multiple sites with Selenium (Python)
I made a web application in Python that converts Markdown to HTML
Mayungo's Python Learning Episode 6: I tried to convert a character string to a number
Mayungo's Python Learning Episode 2: I tried to put out characters with variables
I tried to discriminate a 6-digit number with a number discrimination application made with python
Environment maintenance made with Docker (I want to post-process GrADS in Python
I made a script in python to convert .md files to Scrapbox format
I made a program to check the size of a file in Python
I refactored "I tried to make Othello AI when programming beginners studied python"
I made a function to see the movement of a two-dimensional array (Python)
I tried to implement permutation in Python
I made a payroll program in Python!
I installed Python 3.5.1 to study machine learning
I tried to implement PLSA in Python 2
Python3 standard input I tried to summarize
I wanted to solve ABC160 with Python
I want to build a Python environment
I want to analyze logs with Python
I want to play with aws with python
I tried to implement ADALINE in Python
I wanted to solve ABC159 in Python
I tried to implement PPO in Python
I made a script to display emoji
I made a Hex map with Python
Mayungo's Python Learning Episode 8: I tried input
[Python] I tried to calculate TF-IDF steadily
I tried to touch Python (basic syntax)
After studying Python3, I made a Slackbot
I made a roguelike game with Python
What I was addicted to Python autorun