The title is a little long
In fact, the title is: using OpenCV Python to implement 2048 games
But who read that? Ha ha ha ha
But of course, it involves some problems mentioned in the title.
The code of this article is Python language, which needs the following modules
import cv2 import numpy as np import random
Next, to implement the 2048 game, you need some global variables
# It is used to randomly generate new elements. To facilitate the adjustment of probability, it is created in the form of list new_nums = [1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3] new_vals = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4] # 4x4 game data data = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) # Data used to record mouse movement: start (press) and end (lift) m_start = [0, 0] m_end = [0, 0]
Then the function codes
1. Generate pictures in opencv Python
1.1 game background
In python, opencv does not have the "Mat" data type, but directly uses the array in Numpy. In the original, all the operations of Mat became the operations of np array.
For example, create a white image (as the basic background of 2048 game):
# Create background map def create_back(): color = (255, 255, 255) img = np.array([[color for i in range(450)]for j in range(450)], dtype=np.uint8) return img
It's a 450x450 white image. It's not shown
1.2 figure of digital block
# Create color blocks def create_block(num): # Get number of digits index = len(str(num)) # The maximum number of 16 cells will not exceed the 16th power of 2, that is, 65536, that is, 5 digits, # Determine the color, text size, thickness and position of the block according to the length of the number greens = [180, 162, 144, 126, 108] font_sizes = [2.75, 1.75, 1.25, 1, 0.875] thickness_s = [6, 5, 4, 3, 2] color = (54, greens[index - 1], 60) font_size = font_sizes[index-1] thickness = thickness_s[index - 1] pos = (int(24 - (3.3 * index)), int(85 - (6.5 * index))) # Create a digital block img = np.array([[color for i in range(100)] for j in range(100)], dtype=np.uint8) if num > 0: # Draw numbers greater than 0 cv2.putText(img, str(num), pos, cv2.FONT_HERSHEY_SIMPLEX, font_size, (255, 255, 255), thickness) return img
Put 2, 4, 8, 16 65536 a total of 16 numbers of blocks are show n. That's it. As the number increases, the color of the block deepens.
2. Opencv Python responds to mouse events (game sliding operation)
These are the mouse events supported in opencv python.
|EVENT_LBUTTONUP||4||Release of left key|
|EVENT_RBUTTONUP||5||Right click release|
|EVENT_LBUTTONDBLCLK||7||Left click double click|
|EVENT_RBUTTONDBLCLK||8||Right click double click|
|EVENT_MBUTTONDBLCLK||9||Middle double click|
Here is mainly used to press and lift the left mouse button
First, register the mouse event function:
During the initialization and startup of the game, define the window name, bind the mouse event function, and then generate the first number block and display the screen
# Initialize game interface def game_run(): cv2.namedWindow("2048", cv2.WINDOW_AUTOSIZE) # Bind mouse response function cv2.setMouseCallback("2048", mouse_event) new_elements() img = game_image() cv2.imshow("2048", img) cv2.waitKey(0)
The second step is to implement the mouse response function:
Press the left key to record the coordinates, lift the left key to record the coordinates, then calculate the front and back coordinates to determine which direction to slide, execute the corresponding function (that is, move the digital block, adjacent and the same sum), and then regenerate into a new digital block, with a new interface.
There is a very difficult problem to deal with here. In opencv, once the mouse event function is bound, as long as the mouse is in the window, it will trigger, no matter you are moving, double clicking, clicking Function writing is not good easy to lead to "as soon as the mouse enters the window, it will be crazy to perform some operations.".
# Mouse event def mouse_event(event, x, y, flags, param): global m_start, m_end if event == cv2.EVENT_LBUTTONDOWN: m_start = [x, y] if event == cv2.EVENT_LBUTTONUP: m_end = [x, y] dx = m_end - m_start dy = m_end - m_start if abs(dx) > abs(dy): if dx > 0: to_right() else: to_left() else: if dy > 0: to_bottom() else: to_top() img = game_image() cv2.imshow("2048", img) cv2.waitKey(100) # Update the screen after sliding, pause and insert new numbers to make it feel animated new_elements() img = game_image() cv2.imshow("2048", img) m_start = [0, 0] m_end = [0, 0]
3 Python array random elements (each slide randomly generates a new number block)
Here we mainly use the random module
Random. Choice() --- > randomly take an element from the list
Random. Sample() ------ > randomly take a specified number of elements from the list
# Generate new elements def new_elements(): pos_list_t = np.where(data == 0) pos_list = [(pos_list_t[i], pos_list_t[i]) for i in range(len(pos_list_t))] # Number of random new elements nums = random.choice(new_nums) if nums >= len(pos_list): nums = 1 # Random position of a new element new_poss = random.sample(pos_list, nums) for pos in new_poss: # The value of a random new element data[pos][pos] = random.choice(new_vals)
4 (up, down, left and right sliding treatment)
The first three are the technical core of the design, the next is the algorithm core, sliding in one direction, that is, in 4x4 matrix, non-zero numbers move to the specified direction, and then sum the adjacent and the same numbers into a number.
For example, slide the first line to the left once,
[1, 0, 1, 2]-->[1, 1, 2, 0]-->[2, 0, 2, 0]-->[2, 2, 0, 0]
The code is as follows (if you have a simpler and faster way, please leave a message to teach me)
# Sliding to the left def to_left(): for i in range(4): index = 0 t = [0, 0, 0, 0] for x in range(3): if data[i][x] > 0: t[index] = data[i][x] data[i][x] = 0 n = x + 1 while data[i][n] == 0 and n < 3: n = n + 1 if t[index] == data[i][n]: t[index], data[i][n] = t[index] + data[i][n], 0 x += 1 index += 1 t[index] = data[i] data[i] = t # Towards the right def to_right(): for i in range(4): index = 3 t = [0, 0, 0, 0] for x in range(3, 0, -1): if data[i][x] > 0: t[index] = data[i][x] data[i][x] = 0 n = x - 1 while data[i][n] == 0 and n >= 0: n = n - 1 if t[index] == data[i][n]: t[index], data[i][n] = t[index] + data[i][n], 0 x -= 1 index -= 1 t[index] = data[i] data[i] = t # Upward def to_top(): for i in range(4): index = 0 t = [0, 0, 0, 0] for x in range(3): if data[x][i] > 0: t[index] = data[x][i] data[x][i] = 0 n = x + 1 while data[n][i] == 0 and n < 3: n = n + 1 if t[index] == data[n][i]: t[index], data[n][i] = t[index] + data[n][i], 0 x += 1 index += 1 t[index] = data[i] data[:, i] = t # down def to_bottom(): for i in range(4): index = 3 t = [0, 0, 0, 0] for x in range(3, 0, -1): if data[x][i] > 0: t[index] = data[x][i] data[x][i] = 0 n = x - 1 while data[n][i] == 0 and n >= 0: n = n - 1 if t[index] == data[n][i]: t[index], data[n][i] = t[index] + data[n][i], 0 x -= 1 index -= 1 t[index] = data[i] data[:, i] = t
5 (other functions and calls)
You also need a function to generate the game interface according to the current number of games data[4x4]
# Generate current screen def game_image(): img = create_back() for i in range(4): for j in range(4): x_start = 10 + 110 * i y_start = 10 + 110 * j x_end = x_start + 100 y_end = y_start + 100 block = create_block(data[i][j]) img[x_start:x_end, y_start:y_end] = block return img
Finally, make a call to start the game
if __name__ == "__main__": game_run()
The picture is as follows
Tail: of course, there are many bugs. Here are just some techniques. It's good to play. If you want to write a game, you can't do it with Opencv.