[PYTHON] Graphic programming

Let's write a program with pictures

Write the following image (picntu.png).

image

You can analyze and run this image. The upper side is the parts storage area. Run the bottom side. Go from top left to right and move down. Like Python, it is indented to represent a block. Like turtle graphics, it is first in coordinates (x = 0, y = 0) and faces north. You can move it with a command.

Run sample

bash


docker run -it --rm tsutomu7/picntu ./picntu picntu.png
>>>
0 0
0 2
2 2
2 0

Part description

--go: Take one step. (First at (0, 0).) --back: Go back one step. --left: Turn to the left. (First facing north.) --right: Turn to the right. --def Number: Defines a number subroutine. The scope of the definition is determined by indentation. --run Number: Executes a number subroutine. --lop Number: Repeat for the number. The range of repetition is determined by the indentation. --pri Number: Outputs a number. --if = number: Determines if the number is equal to the value in memory. The range is determined by indentation. --if <number: Determines if the number exceeds the value in memory. --if> Number: Determines if the number is less than the value in memory. --set Number: Sets a number in memory. --add Number: Adds a number to memory. --sub Number: Subtracts a number from memory. --If you leave the number blank, the memory value will be used. You can only have one number in memory. --Numbers are from 0 to 9, and 10 returns to 0. --Instead of numbers, you can also use the following literals.

literal

--Numbers: Numbers range from 0 to 9 and 10 returns to 0. --i, j: lop counter. The first loop is i and the second loop is j. --x, y: Represents coordinates. --r: Indicates the orientation. North = 0, East = 1. South = 2, West = 3.

Sample description

sample


def 0 | pri x | pri y
lop 4 | run 0
      | lop 2 | go
      | right

Description

--The following is subroutine 0 --Output x and y --Repeat the following 4 times --Call Subroutine 0 --Twice forward (2 steps forward) --Look to the right

Run any image

If you put the image file in / tmp, you can do the following: You can change the size of the picture, but do not change the position of the parts.

bash


docker run -it --rm -v /tmp:/tmp tsutomu7/picntu ./picntu /tmp/Image file name

If you specify some second argument, you can see the python created from the image.

bash


docker run -it --rm tsutomu7/picntu ./picntu picntu.png 0
>>>
i, j, x, y, r, c = 0, 0, 0, 0, 0, 0
dx, dy = [0, 1, 0, 9], [1, 0, 9, 0]
def f0():
    print("\n%d" % x, end="");print(" %d" % y, end="");
for i in range(4):
    f0();
    for j in range(2):
        globals()["x"], globals()["y"] = (x + dx[r]) % 10, (y + dy[r]) % 10;
    globals()["r"] = (r + 1) % 4;

0 0
0 2
2 2
2 0

Run in browser

Do the following, specify the file and press "run".

bash


docker run -it -d -p 5000:5000 tsutomu7/picntu
firefox localhost:5000

image

Analysis program

picntu.py


import cv2, sys, unionfind

if len(sys.argv) <= 1:
    print('%s image_file' % sys.argv[0][:-3])
    exit()
im = cv2.imread(sys.argv[1])
imtop = im[5:13, 4:86] # top of card
r1 = cv2.matchTemplate(im[160:], imtop, cv2.TM_CCOEFF_NORMED)
scom = 'go back lop if_eq set ' \
       'left right else if_lt add ' \
       'def run pri if_gt sub'.split()
slit = '0 1 i 2 3 j 4 5 x 6 7 y 8 9 r'.split()
coms = [] # command list
for y, x in [(i, j) for i, p in enumerate(r1 >= 0.999)
                    for j, q in enumerate(p) if q]:
    imcom = im[y+173:y+197,x+9:x+49]
    r2 = cv2.matchTemplate(im[:150,:460], imcom, cv2.TM_CCOEFF_NORMED)
    _, v, _, (x2, y2) = cv2.minMaxLoc(r2)
    if v < 0.999:
        continue
    i = (x2+33)//92 + (y2+8)//52*5
    arg = 'c'
    if i > 7 or (i+1)%6 > 2:
        r3 = cv2.matchTemplate(im[9:147,465:545], im[y+173:y+193,x+53:x+70],
                               cv2.TM_CCOEFF_NORMED)
        _, v, _, (x3, y3) = cv2.minMaxLoc(r3)
        if v >= 0.999:
            arg = slit[(x3+8)//26 + (y3+7)//25*3]
    coms.append([-1, -1, scom[i], arg, x, y])

n = len(coms)
ux = unionfind.unionfind(n)
uy = unionfind.unionfind(n)
for i in range(n):
    coi = coms[i]
    for j in range(i+1, n):
        coj = coms[j]
        if abs(coi[4] - coj[4]) < 12:
            ux.unite(i, j)
        if abs(coi[5] - coj[5]) < 12:
            uy.unite(i, j)
for i, g in enumerate(sorted(ux.groups(), key=lambda g: coms[g[0]][4])):
    for j in g:
        coms[j][1] = i
for i, g in enumerate(sorted(uy.groups(), key=lambda g: coms[g[0]][5])):
    for j in g:
        coms[j][0] = i

ex = []
ex.append('i, j, x, y, r, c = 0, 0, 0, 0, 0, 0\n')
ex.append('dx, dy = [0, 1, 0, 9], [1, 0, 9, 0]\n')
pr, s, lp = 0, ' ', []
for v, t, com, a, _, _ in sorted(coms):
    if v > pr or s[-1] == ':':
        ex.append('\n' + '    '*t)
    if com == 'go':
        s = 'globals()["x"], globals()["y"] = (x + dx[r]) % 10, (y + dy[r]) % 10;'
    elif com == 'back':
        s = 'globals()["x"], globals()["y"] = (x + dx[(r + 2) % 4]) % 10, (y + dy[(r + 2) % 4]) % 10;'
    elif com == 'left':
        s = 'globals()["r"] = (r + 3) % 4;'
    elif com == 'right':
        s = 'globals()["r"] = (r + 1) % 4;'
    elif com == 'def':
        s = 'def f%s():' % a
    elif com == 'run':
        s = 'f%s();' % a
    elif com == 'lop':
        while lp and lp[-1] >= t:
            lp.pop()
        s = 'for %s in range(%s):' % ('ijklmn'[len(lp)], a)
        lp.append(t)
    elif com == 'else':
        s = 'else:'
    elif com == 'pri':
        s = 'print("%s%%d" %% %s, end="");' % (' ' if v == pr and s[0] == 'p' else '\\n', a)
    elif com == 'if_eq':
        s = 'if c == %s:' % a
    elif com == 'if_lt':
        s = 'if c < %s:' % a
    elif com == 'if_gt':
        s = 'if c > %s:' % a
    elif com == 'set':
        s = 'globals()["c"] = %s;' % a
    elif com == 'add':
        s = 'globals()["c"] += %s;' % a
    elif com == 'sub':
        s = 'globals()["c"] -= %s;' % a
    ex.append(s)
    pr = v
if len(sys.argv) > 2:
    print(''.join(ex))
exec(''.join(ex))
print()

reference: Playing with turtles in turtle graphics (Part 1) "Cubetto" where even 3-year-olds can learn programming with toys