├── README.md
├── african_head_diffuse.tga
├── chess.py
├── chess_lesson1.py
├── face.obj
├── fire.py
├── images
├── chess.png
├── fire.gif
├── lesson4.png
├── lesson5.png
└── sokoban.png
├── lesson3.py
├── lesson4.py
├── lesson5.py
├── sokoban.py
└── sokoban_config.py
/README.md:
--------------------------------------------------------------------------------
1 | # PythonLessons
2 | **lesson3.py**, **lesson4.py**, **lesson5.py** - low-level pixel-by-pixel rendering. It's shown how to draw a line, a triangle, paint over a polygon, impose a texture, etc.
3 |
4 |
5 | 
6 |
7 | ---
8 |
9 | **chess.py** - a chess bot plays with itself. There are only pawns, rooks and kings, but you can add other pieces. This is an example how the bot thinks ahead and chooses the best move
10 |
11 | 
12 |
13 | ---
14 |
15 | **sokoban.py** is a telegram bot that plays Sokoban with you (https://en.wikipedia.org/wiki/Sokoban). Do not program like this - it's a hack in a certain way. I made it for small size only.
16 |
17 | ☿ - a warehouse keeper
18 | ◯ - a box
19 | ◉ - a box on a storage location
20 |
21 | 
22 |
23 | ---
24 |
25 | **fire.py** run it in console and get fire
26 |
27 | 
28 |
--------------------------------------------------------------------------------
/african_head_diffuse.tga:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ef-end-y/PythonLessons/5195fa7f11e559f19f72aca085306283a1bc410d/african_head_diffuse.tga
--------------------------------------------------------------------------------
/chess.py:
--------------------------------------------------------------------------------
1 | #! -*- coding: utf-8 -*-
2 | from abc import abstractmethod, ABCMeta
3 |
4 |
5 | THINKING_DEPTH = 4
6 |
7 |
8 | class Color(object):
9 | BLACK = 1
10 | WHITE = 2
11 | EMPTY = 0
12 |
13 | @classmethod
14 | def invert(cls, color):
15 | if color == cls.EMPTY:
16 | return color
17 | return cls.BLACK if color == cls.WHITE else cls.WHITE
18 |
19 |
20 | class Chessboard(object):
21 | SPACE_COLOR_WHITE = 209
22 | SPACE_COLOR_BLACK = 94
23 |
24 | board = None
25 |
26 | def fill(self):
27 | board = self.board = [[EmptyCell() for x in range(8)] for y in range(8)]
28 | black = Color.BLACK
29 | white = Color.WHITE
30 | # simple start position on the board
31 | board[1][0] = ChessmanPawn(black)
32 | board[1][1] = ChessmanPawn(black)
33 | board[1][2] = ChessmanPawn(black)
34 | board[1][3] = ChessmanKing(black)
35 | board[3][1] = ChessmanPawn(white)
36 | board[3][3] = ChessmanKing(white)
37 | board[2][2] = ChessmanRook(white)
38 |
39 | def clone(self):
40 | cb = Chessboard()
41 | cb.board = [self.board[i][:] for i in range(8)]
42 | return cb
43 |
44 | def get_chessman(self, x, y):
45 | return self.board[y][x]
46 |
47 | def get_color(self, x, y):
48 | return self.get_chessman(x, y).color
49 |
50 | def get_chessman_moves(self, x, y):
51 | return self.get_chessman(x, y).get_moves(self, x, y)
52 |
53 | def move_chessman(self, xy_from, xy_to):
54 | captured = self.board[xy_to[1]][xy_to[0]]
55 | self.board[xy_to[1]][xy_to[0]] = self.board[xy_from[1]][xy_from[0]]
56 | self.board[xy_from[1]][xy_from[0]] = EmptyCell()
57 | return captured
58 |
59 | def is_empty(self, x, y):
60 | return self.get_chessman(y, x).CODE == 'empty'
61 |
62 | def rate(self, color):
63 | res = 0
64 | pawn_x_position = []
65 | for y in range(8):
66 | for x in range(8):
67 | if self.get_color(x, y) != color:
68 | continue
69 | chessman = self.get_chessman(x, y)
70 | res += chessman.rate(self, x, y)
71 | if chessman.CODE == 'pawn':
72 | pawn_x_position.append(x)
73 | # double pawns reduce the rate
74 | p = pawn_x_position
75 | res += 2 * (len(set(p)) - len(p))
76 | # alone pawn reduce the rate
77 | for i in range(1, 6):
78 | if i in p and (i-1) not in p and (i+1) not in p:
79 | res -= 2
80 | return res
81 |
82 | def __str__(self):
83 | res = " a b c d e f g h\n"
84 | for y in range(8):
85 | res += "\033[0m" + str(8 - y)
86 | for x in range(8):
87 | color = self.SPACE_COLOR_BLACK if (x + y) % 2 else self.SPACE_COLOR_WHITE
88 | res += '\033[48;5;%sm%s ' % (color, self.board[y][x])
89 | res += "\n"
90 | res += "\033[0m"
91 | return res
92 |
93 |
94 | class EmptyCell(object):
95 | CODE = 'empty'
96 | color = Color.EMPTY
97 |
98 | def get_moves(self, board, x, y):
99 | raise Exception('Error!')
100 |
101 | def rate(self, board, x, y):
102 | raise Exception('Error!')
103 |
104 | def __str__(self):
105 | return ' '
106 |
107 |
108 | class Chessman(object):
109 | __metaclass__ = ABCMeta
110 |
111 | CODE = None
112 | VALUE = None
113 | WHITE_IMG = None
114 | BLACK_IMG = None
115 |
116 | color = None
117 |
118 | def __init__(self, color):
119 | self.color = color
120 |
121 | @abstractmethod
122 | def get_moves(self, board, x, y):
123 | return []
124 |
125 | @abstractmethod
126 | def rate(self, board, x, y):
127 | return 0
128 |
129 | def enemy_color(self):
130 | return Color.invert(self.color)
131 |
132 | def __str__(self):
133 | return self.WHITE_IMG if self.color == Color.WHITE else self.BLACK_IMG
134 |
135 |
136 | class ChessmanPawn(Chessman):
137 | CODE = 'pawn'
138 | VALUE = 10
139 | WHITE_IMG = '♙'
140 | BLACK_IMG = '♟'
141 |
142 | def get_moves(self, board, x, y):
143 | moves = []
144 | y += -1 if self.color == Color.WHITE else 1
145 | if y == -1 or y == 8:
146 | return moves
147 | if x > 0 and board.get_color(x-1, y) == self.enemy_color():
148 | moves.append([x-1, y])
149 | if x < 7 and board.get_color(x+1, y) == self.enemy_color():
150 | moves.append([x+1, y])
151 | if board.is_empty(x, y):
152 | moves.append([x, y])
153 | if self.color == Color.WHITE and y == 5 and board.is_empty(x, y-1):
154 | moves.append([x, y-1])
155 | if self.color == Color.BLACK and y == 2 and board.is_empty(x, y+1):
156 | moves.append([x, y+1])
157 | return moves
158 |
159 | def rate(self, board, x, y):
160 | return self.VALUE + 1 * (8-y if self.color == Color.WHITE else y)
161 |
162 |
163 | class ChessmanKing(Chessman):
164 | CODE = 'king'
165 | VALUE = 0
166 | WHITE_IMG = '♔'
167 | BLACK_IMG = '♚'
168 |
169 | def get_moves(self, board, x, y):
170 | moves = []
171 | for j in (y-1, y, y+1):
172 | for i in (x-1, x, x+1):
173 | if i == x and j == y:
174 | continue
175 | if 0 <= i <= 7 and 0 <= j <= 7 and board.get_color(i, j) != self.color:
176 | moves.append([i, j])
177 | return moves
178 |
179 | def rate(self, board, x, y):
180 | return self.VALUE
181 |
182 |
183 | class ChessmanRook(Chessman):
184 | CODE = 'rook'
185 | VALUE = 50
186 | WHITE_IMG = '♖'
187 | BLACK_IMG = '♜'
188 |
189 | def get_moves(self, board, x, y):
190 | moves = []
191 | for j in (-1, 1):
192 | i = x + j
193 | while 0 <= i <= 7:
194 | color = board.get_color(i, y)
195 | if color == self.color:
196 | break
197 | moves.append([i, y])
198 | if color != Color.EMPTY:
199 | break
200 | i += j
201 | for j in (-1, 1):
202 | i = y + j
203 | while 0 <= i <= 7:
204 | color = board.get_color(x, i)
205 | if color == self.color:
206 | break
207 | moves.append([x, i])
208 | if color != Color.EMPTY:
209 | break
210 | i += j
211 | return moves
212 |
213 | def rate(self, board, x, y):
214 | return self.VALUE
215 |
216 |
217 | class AI(object):
218 | def __init__(self, my_color, depth):
219 | self.my_color = my_color
220 | self.enemy_color = Color.invert(my_color)
221 | self.depth = depth
222 |
223 | def do(self, board, depth=0):
224 | enemy = bool(depth % 2)
225 | color = self.enemy_color if enemy else self.my_color
226 | if depth == self.depth:
227 | return board.rate(self.my_color) - board.rate(self.enemy_color)*1.1
228 | rates = []
229 | for y in range(8):
230 | for x in range(8):
231 | if board.get_color(x, y) != color:
232 | continue
233 | xy_from = [x, y]
234 | for xy_to in board.get_chessman_moves(x, y):
235 | new_board = board.clone()
236 | target_cell = new_board.move_chessman(xy_from, xy_to)
237 | captured = target_cell.CODE != 'empty'
238 | if captured and target_cell.CODE == 'king':
239 | rate = -1000 if enemy else 1000 # king capturing
240 | else:
241 | rate = self.do(new_board, depth + 1)
242 | if rate is None:
243 | continue
244 | if captured and not enemy:
245 | rate += self.depth - depth # a little more aggression
246 | if depth:
247 | rates.append(rate)
248 | else:
249 | rates.append([rate, xy_from, xy_to])
250 | if not depth:
251 | return rates
252 | if not rates:
253 | return None
254 | rate = min(rates) if enemy else max(rates)
255 | return rate
256 |
257 |
258 | class Game(object):
259 | @staticmethod
260 | def clear_screen():
261 | print "\033[2J\033[1;3H\033[14;0m"
262 |
263 | def __init__(self):
264 | cb = Chessboard()
265 | cb.fill()
266 |
267 | self.clear_screen()
268 | print cb
269 |
270 | color = Color.WHITE
271 | for i in range(22):
272 | max_rate = -9999
273 | xy_from = xy_to = None
274 | rates = AI(color, THINKING_DEPTH).do(cb)
275 | for rate in rates:
276 | if rate[0] < max_rate:
277 | continue
278 | max_rate, xy_from, xy_to = rate
279 | if not xy_from:
280 | print 'end'
281 | exit()
282 | cb.move_chessman(xy_from, xy_to)
283 | color = Color.invert(color)
284 | self.clear_screen()
285 | print cb
286 |
287 | Game()
288 |
--------------------------------------------------------------------------------
/chess_lesson1.py:
--------------------------------------------------------------------------------
1 | #! -*- coding: utf-8 -*-
2 |
3 |
4 | class Color(object):
5 | EMPTY = 0
6 | BLACK = 1
7 | WHITE = 2
8 |
9 |
10 | class Empty(object):
11 | color = Color.EMPTY
12 |
13 | def get_moves(self, board, x, y):
14 | raise Exception('Error !')
15 |
16 | def __str__(self):
17 | return '.'
18 |
19 |
20 | class ChessMan(object):
21 | IMG = None
22 |
23 | def __init__(self, color):
24 | self.color = color
25 |
26 | def __str__(self):
27 | return self.IMG[0 if self.color == Color.WHITE else 1]
28 |
29 |
30 | class Pawn(ChessMan):
31 | IMG = ('♙', '♟')
32 |
33 | def get_moves(self, board, x, y):
34 | moves = []
35 | if self.color == Color.BLACK and y < 7 and board.get_color(x, y+1) == Color.EMPTY:
36 | moves.append([x, y+1])
37 | return moves
38 |
39 |
40 | class King(ChessMan):
41 | IMG = ('♔', '♚')
42 |
43 | def get_moves(self, board, x, y):
44 | moves = []
45 | return moves
46 |
47 |
48 | class Board(object):
49 | def __init__(self):
50 | self.board = [[Empty()] * 8 for y in range(8)]
51 | self.board[1][2] = Pawn(Color.BLACK)
52 | self.board[0][3] = King(Color.BLACK)
53 | self.board[7][3] = King(Color.WHITE)
54 |
55 | def get_color(self, x, y):
56 | return self.board[y][x].color
57 |
58 | def get_moves(self, x, y):
59 | return self.board[y][x].get_moves(self, x, y)
60 |
61 | def move(self, xy_from, xy_to):
62 | self.board[xy_to[1]][xy_to[0]] = self.board[xy_from[1]][xy_from[0]]
63 | self.board[xy_from[1]][xy_from[0]] = Empty()
64 |
65 | def __str__(self):
66 | res = ''
67 | for y in range(8):
68 | res += ''.join(map(str, self.board[y])) + "\n"
69 | return res
70 |
71 |
72 | b = Board()
73 | print b
74 | m = b.get_moves(2, 1)
75 | b.move([2,1], m[0])
76 | print b
77 |
--------------------------------------------------------------------------------
/fire.py:
--------------------------------------------------------------------------------
1 | from random import randint
2 | from time import sleep
3 |
4 | flame = ' .,:;=<*i%IHM#'
5 |
6 | fw = 128 # fire width
7 | fh = 60 # fire height
8 |
9 | fire = []
10 |
11 | for y in range(fh):
12 | fire.append([0] * fw)
13 |
14 | a = b = 0
15 | f = len(flame) - 1
16 |
17 | for i in range(500):
18 | print("\033[2J\033[0;0H")
19 |
20 | for y in range(fh):
21 | print(''.join([flame[fire[fh - y - 1][x]] for x in range(fw)]))
22 |
23 | for x in range(fw):
24 | fade0 = int(0.15 * x * abs(x - fw)) + 1
25 | for y in range(1, fh):
26 | x1 = max(min(x + randint(0, 5) - 2, fw - 1), 0)
27 | fade = int(fw/randint(1, fade0))
28 | fire[y][x] = max(fire[y - 1][x1] - fade, 0)
29 |
30 | sleep(0.07)
31 |
32 | for x in range(0, randint(0, fw)):
33 | fire[0][x] = f if (x > a < b) or (x < a > b) else 0
34 | a += 1 if a < b else -1
35 | if a == b:
36 | b = randint(0, int(fw/2))
37 |
38 |
39 |
--------------------------------------------------------------------------------
/images/chess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ef-end-y/PythonLessons/5195fa7f11e559f19f72aca085306283a1bc410d/images/chess.png
--------------------------------------------------------------------------------
/images/fire.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ef-end-y/PythonLessons/5195fa7f11e559f19f72aca085306283a1bc410d/images/fire.gif
--------------------------------------------------------------------------------
/images/lesson4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ef-end-y/PythonLessons/5195fa7f11e559f19f72aca085306283a1bc410d/images/lesson4.png
--------------------------------------------------------------------------------
/images/lesson5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ef-end-y/PythonLessons/5195fa7f11e559f19f72aca085306283a1bc410d/images/lesson5.png
--------------------------------------------------------------------------------
/images/sokoban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ef-end-y/PythonLessons/5195fa7f11e559f19f72aca085306283a1bc410d/images/sokoban.png
--------------------------------------------------------------------------------
/lesson3.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import random
3 | from PIL import Image
4 | import re
5 |
6 | scr_x = 800 # Ширина картинки
7 | scr_y = scr_x # Высота картинки
8 | img = Image.new('RGB', (scr_x, scr_y), 'black') # Создадим картинку с черным цветом фона
9 | canvas = img.load() # Через эту переменную у нас есть доступ к пикселям картинки
10 |
11 |
12 | class Point(object):
13 | def __init__(self, x, y):
14 | self.x = x
15 | self.y = y
16 |
17 | def show(self, color=None):
18 | canvas[self.x, scr_y-self.y] = color or (255, 255, 255)
19 |
20 | def copy(self):
21 | return Point(self.x, self.y)
22 |
23 |
24 | def zero_div(a, b):
25 | return float(a)/b if b else 0
26 |
27 |
28 | def triangle(coords, color):
29 | a, b, c = sorted(coords, key=lambda p: p.y)
30 | p1 = a.copy()
31 | p2 = a.copy()
32 | delta_p1 = zero_div((b.x - a.x), (b.y - a.y))
33 | delta_p2 = zero_div((c.x - a.x), (c.y - a.y))
34 | for y in (b.y, c.y):
35 | while p1.y < y:
36 | if p1.x > p2.x:
37 | p3 = p2.copy()
38 | x = p1.x
39 | else:
40 | p3 = p1.copy()
41 | x = p2.x
42 | while p3.x < x:
43 | p3.show(color)
44 | p3.x += 1
45 | p1.y += 1
46 | p2.y += 1
47 | p1.x += delta_p1
48 | p2.x += delta_p2
49 | delta_p1 = zero_div((c.x - b.x), (c.y - b.y))
50 |
51 | half_scr_x = int(scr_x / 2)
52 | half_scr_y = int(scr_y / 2)
53 | f = open('face.obj', 'r')
54 | lines = f.read()
55 | points = []
56 | for line in lines.split('\n'):
57 | try:
58 | v, x, y, z = re.split('\s+', line)
59 | except:
60 | continue
61 | if v == 'v':
62 | x = int((float(x) + 1) * half_scr_x)
63 | y = int((float(y) + 1) * half_scr_y)
64 | points.append(Point(x, y))
65 | if v == 'f':
66 | color = tuple([random.randint(0, 255)] * 3)
67 | triangle([points[int(i.split('/')[0])-1] for i in (x, y, z)], color)
68 |
69 | img.show()
70 |
71 |
--------------------------------------------------------------------------------
/lesson4.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from PIL import Image
3 | import re
4 |
5 | scr_x = 800 # Ширина картинки
6 | scr_y = scr_x # Высота картинки
7 |
8 |
9 | class Screen(object):
10 | def __init__(self, width, height):
11 | self.width = width
12 | self.height = height
13 | self.img = Image.new('RGB', (width, height), 'black')
14 | self.canvas = self.img.load()
15 | self.z_buffer = [[0] * width for i in range(height)]
16 |
17 | def point(self, *coords):
18 | return Point(self, *coords)
19 |
20 | @staticmethod
21 | def triangle(coords):
22 | a, b, c = sorted(coords, key=lambda p: p.y)
23 | p1 = a.copy()
24 | p2 = a.copy()
25 | height_ac = c.y - a.y
26 | height_ab = (b.y - a.y) or 1
27 | height_bc = (c.y - b.y) or 1
28 | delta_x1 = float(b.x - a.x) / height_ab
29 | delta_x2 = float(c.x - a.x) / height_ac
30 | delta_z1 = float(b.z - a.z) / height_ab
31 | delta_z2 = float(c.z - a.z) / height_ac
32 | for y in (b.y, c.y):
33 | while p1.y < y:
34 | if p1.x > p2.x:
35 | p3 = p2.copy()
36 | p4 = p1
37 | else:
38 | p3 = p1.copy()
39 | p4 = p2
40 | delta_z3 = float(p4.z - p3.z) / ((p4.x - p3.x) or 1)
41 | while p3.x < p4.x:
42 | p3.show(tuple([int(p3.z * 128)] * 3))
43 | p3.x += 1
44 | p3.z += delta_z3
45 | p1.y += 1
46 | p2.y += 1
47 | p1.x += delta_x1
48 | p1.z += delta_z1
49 | p2.x += delta_x2
50 | p2.z += delta_z2
51 | delta_x1 = float(c.x - b.x) / height_bc
52 | delta_z1 = float(c.z - b.z) / height_bc
53 | p1 = b.copy()
54 |
55 |
56 | class Point(object):
57 | def __init__(self, screen, x, y, z):
58 | self.x = x
59 | self.y = y
60 | self.z = z
61 | self.screen = screen
62 |
63 | def show(self, color=None):
64 | screen = self.screen
65 | x = int(self.x)
66 | y = int(self.y)
67 | if self.z <= screen.z_buffer[x][y]:
68 | return
69 | screen.z_buffer[x][y] = self.z
70 | screen.canvas[x, screen.height-y] = color or (255, 255, 255)
71 |
72 | def copy(self):
73 | return Point(self.screen, self.x, self.y, self.z)
74 |
75 |
76 | def show_face():
77 | half_scr_x = int(scr_x/2)
78 | half_scr_y = int(scr_y/2)
79 | f = open('face.obj', 'r')
80 | lines = f.read()
81 | points = []
82 | screen = Screen(scr_x, scr_y)
83 | for line in lines.split('\n'):
84 | try:
85 | v, x, y, z = re.split('\s+', line)
86 | except ValueError:
87 | continue
88 | if v == 'v':
89 | x = int((float(x) + 1) * half_scr_x)
90 | y = int((float(y) + 1) * half_scr_y)
91 | z = float(z) + 1
92 | points.append(screen.point(x, y, z))
93 | if v == 'f':
94 | screen.triangle([points[int(i.split('/')[0])-1] for i in (x, y, z)])
95 | screen.img.show()
96 |
97 | show_face()
98 |
--------------------------------------------------------------------------------
/lesson5.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import copy
3 | from PIL import Image
4 | import re
5 |
6 | scr_x = 800 # Ширина картинки
7 | scr_y = scr_x # Высота картинки
8 |
9 |
10 | class Screen(object):
11 | def __init__(self, width, height):
12 | self.width = width
13 | self.height = height
14 | self.img = Image.new('RGB', (width, height), 'black')
15 | self.canvas = self.img.load()
16 | self.z_buffer = [[0] * width for i in range(height)]
17 |
18 | def point(self, *coords):
19 | return TexturePoint(self, *coords)
20 |
21 | @staticmethod
22 | def triangle(coords, texture):
23 | a, b, c = sorted(coords, key=lambda p: p.y)
24 | p1, p2 = a.copy(), a.copy()
25 | height = c.y - a.y
26 | delta_x2 = float(c.x - a.x) / height
27 | deltas = lambda i, j, divider: [float(i.z-j.z)/divider, float(i.u-j.u)/divider, float(i.v-j.v)/divider]
28 | delta_z2, delta_u2, delta_v2 = deltas(c, a, height)
29 | for p in (b, c):
30 | height = (p.y - p1.y) or 1
31 | delta_x1 = float(p.x - p1.x) / height
32 | delta_z1, delta_u1, delta_v1 = deltas(p, p1, height)
33 | while p1.y < p.y:
34 | p3, p4 = (p2.copy(), p1) if p1.x > p2.x else (p1.copy(), p2)
35 | delta_z3, delta_u3, delta_v3 = deltas(p4, p3, (p4.x - p3.x) or 1)
36 | while p3.x < p4.x:
37 | p3.show(texture[p3.u, p3.v])
38 | p3.add(x=1, z=delta_z3, u=delta_u3, v=delta_v3)
39 | p1.add(x=delta_x1, y=1, z=delta_z1, u=delta_u1, v=delta_v1)
40 | p2.add(x=delta_x2, y=1, z=delta_z2, u=delta_u2, v=delta_v2)
41 | p1 = b.copy()
42 |
43 |
44 | class Point(object):
45 | def __init__(self, screen, x, y, z):
46 | self.x = x
47 | self.y = y
48 | self.z = z
49 | self.screen = screen
50 |
51 | def show(self, color=None):
52 | screen = self.screen
53 | x = int(self.x)
54 | y = int(self.y)
55 | if self.z <= screen.z_buffer[y][x]:
56 | return
57 | screen.z_buffer[y][x] = self.z
58 | screen.canvas[x, screen.height-y] = color or (255, 255, 255)
59 |
60 | def copy(self):
61 | return copy.copy(self)
62 |
63 |
64 | class TexturePoint(Point):
65 | def __init__(self, screen, x, y, z, u, v):
66 | super(TexturePoint, self).__init__(screen, x, y, z)
67 | self.u = u
68 | self.v = v
69 |
70 | def add(self, x=0, y=0, z=0, u=0, v=0):
71 | self.x += x
72 | self.y += y
73 | self.z += z
74 | self.u += u
75 | self.v += v
76 |
77 |
78 | def show_face():
79 | half_scr_x = int(scr_x/2)
80 | half_scr_y = int(scr_y/2)
81 | texture_img = Image.open('african_head_diffuse.tga')
82 | texture = texture_img.load()
83 | f = open('face.obj', 'r')
84 | lines = f.read()
85 | points = []
86 | textures = []
87 | screen = Screen(scr_x, scr_y)
88 | for line in lines.split('\n'):
89 | try:
90 | v, x, y, z = re.split('\s+', line)
91 | except ValueError:
92 | continue
93 | if v == 'v':
94 | x = int((float(x) + 1) * half_scr_x)
95 | y = int((float(y) + 1) * half_scr_y)
96 | z = float(z) + 1
97 | points.append((x, y, z))
98 | if v == 'vt':
99 | u = float(x) * texture_img.width
100 | v = (1 - float(y)) * texture_img.height
101 | textures.append((u, v))
102 | if v == 'f':
103 | indexes = [[int(j)-1 for j in i.split('/')] for i in (x, y, z)]
104 | tr_points = []
105 | for i in range(3):
106 | params = points[indexes[i][0]] + textures[indexes[i][1]]
107 | tr_points.append(screen.point(*params))
108 | screen.triangle(tr_points, texture)
109 | screen.img.show()
110 |
111 | show_face()
112 |
--------------------------------------------------------------------------------
/sokoban.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import telebot
3 | from telebot import types
4 | from sokoban_config import token
5 |
6 | bot = telebot.TeleBot(token)
7 |
8 |
9 | def show_map(gmap):
10 | gmap_width = str(gmap.find(u'█\n') + 1)
11 | btn = types.InlineKeyboardButton
12 | markup = types.InlineKeyboardMarkup(row_width=2)
13 | markup.add(
14 | btn('', callback_data='0'),
15 | btn(u'⬆', callback_data='-' + gmap_width),
16 | btn(u'⬅', callback_data='-1'),
17 | btn(u'➡', callback_data='1'),
18 | btn('', callback_data='0'),
19 | btn(u'⬇', callback_data=gmap_width),
20 | )
21 | return {
22 | 'text': '' + gmap + '
',
23 | 'parse_mode': 'html',
24 | 'reply_markup': markup
25 | }
26 |
27 |
28 | @bot.message_handler(content_types=['text'])
29 | def any_msg(message):
30 | gmap = u"""
31 | ██████████
32 | ██████ . █
33 | █ ◯☿◯ ◯ █
34 | █ ..██
35 | ██████████
36 | """.replace('\n ', '\n')
37 | bot.send_message(message.chat.id, **show_map(gmap))
38 |
39 |
40 | def replace_on_map(game_map, pos, char):
41 | return game_map[:pos] + char + game_map[pos + 1:]
42 |
43 |
44 | @bot.callback_query_handler(func=lambda call: True)
45 | def callback_inline(call):
46 |
47 | if call.message:
48 | gmap = call.message.text
49 | movement = int(call.data)
50 |
51 | pos = gmap.find(u'☿')
52 | if pos < 0:
53 | pos = gmap.find(u'♆')
54 |
55 | new_pos = pos + movement
56 | new_place = gmap[new_pos]
57 | next_place = gmap[new_pos + movement]
58 |
59 | if new_place in (' ', '.') or (new_place in (u'◯', u'◉') and next_place in (' ', '.')):
60 | if new_place in (u'◯', u'◉'):
61 | gmap = replace_on_map(gmap, new_pos + movement, u'◉' if next_place == '.' else u'◯')
62 | gmap = replace_on_map(gmap, pos, ' ' if gmap[pos] == u'☿' else '.')
63 | gmap = replace_on_map(gmap, new_pos, u'☿' if new_place in (' ', u'◯') else u'♆')
64 |
65 | if gmap != call.message.text:
66 | bot.edit_message_text(
67 | chat_id=call.message.chat.id,
68 | message_id=call.message.message_id,
69 | **show_map(gmap)
70 | )
71 |
72 |
73 | bot.polling(none_stop=True)
74 |
--------------------------------------------------------------------------------
/sokoban_config.py:
--------------------------------------------------------------------------------
1 | token = '123456789:XXXXXXXXXXXXXXXXXX'
2 |
--------------------------------------------------------------------------------