The project was created by Karteek Menda, who has open-sourced and published related content on Github,YouTube, and Medium.
Tic-tac-toe is a classic two-player game where players take turns marking a 3×3 grid. The player who succeeds in placing 3 of their marks in a horizontal, vertical, or diagonal row wins the game.
In this project, we will build a simple robot system for human-machine confrontation.
The myCobot 280 series, created by Elephant Robotcs, represent a line of 6 DOF collaborative robot arms designed primarily for research, education, science and technology applications. The myCobot 280 Pi, equipped with a Raspberry Pi as its control board, is designed to be user-friendly and easy for beginners to learn and use.
The AI Kit 2023 includes a set of educational equipment, such as cameras, aluminum profiles, and wooden blocks. The accompanying vision positioning code is available in the Gitbook tutorial, allowing users to access it directly. This enables users to quickly learn about computer vision recognition and robotic control while facilitating secondary development.
The minimax algorithm is a decision-making algorithm commonly used in two-player turn-based games. The primary goal of the minimax algorithm is to determine the optimal move for a player, considering all possible moves and their potential outcomes.
Here’s a simplified explanation of how the Minimax algorithm works:
1. Evaluation Function: Assign a value to each possible move based on its advantage or disadvantage for the player position, while a negative value might suggest a disadvantage.
2. Recursive Search:Explore future moves in a decision tree, alternating between maximizing and minimizing players.
3. Backtracking: Pass values back up the tree, with the maximizing player choosing the highest value and the minimizing player choosing the lowest.
4. Optimal Move: The root of the tree represents the initial game state, and the algorithm selects the move that leads to the child node with the highest value, assuming both players play optimally.
pip install opencv-python
pip install pymycobot
2. Set the Rule of Gamedef find_best_pickup_place_cords(board):
best_val = float('-inf')
best_pickup_place_cords = None
for pickup_place_cords in get_available_pickup_place_cordss(board):
row, col = pickup_place_cords
board[row][col] = 'O'
pickup_place_cords_val = minimax(board, 0, False)
board[row][col] = ' '
if pickup_place_cords_val > best_val:
best_pickup_place_cords = pickup_place_cords
best_val = pickup_place_cords_val
return best_pickup_place_cords
def minimax(board, depth, is_maximizing):
if cross_check_winner(board, 'O'):
return 1
elif cross_check_winner(board, 'X'):
return -1
elif is_board_full(board):
return 0
if is_maximizing:
max_eval = float('-inf')
for pickup_place_cords in get_available_pickup_place_cordss(board):
row, col = pickup_place_cords
board[row][col] = 'O'
eval = minimax(board, depth + 1, False)
board[row][col] = ' '
max_eval = max(max_eval, eval)
return max_eval
else:
min_eval = float('inf')
for pickup_place_cords in get_available_pickup_place_cordss(board):
row, col = pickup_place_cords
board[row][col] = 'X'
eval = minimax(board, depth + 1, True)
board[row][col] = ' '
min_eval = min(min_eval, eval)
return min_eval
def cross_check_winner(board, player):
# Check rows and columns
for i in range(rows):
if all(board[i][j] == player for j in range(columns)) or all(board[j][i] == player for j in range(rows)):
return True
# Check diagonals
if all(board[i][i] == player for i in range(rows)) or all(
board[i][rows - 1 - i] == player for i in range(rows)):
return True
return False
3. Detect ArUco for PositioningThis function identifies 2 ArUco markers in an image and calculates the center coordinates (X, Y) of each marker. The resulting X and Y coordinates are then returned for further use, such as coordinate transformations, camera calibration, or robotic positioning.
def get_calculate_params(self, img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Detect ArUco marker.
corners, ids, rejectImaPoint = cv2.aruco.detectMarkers(
gray, self.aruco_dict, parameters=self.aruco_params
)
if len(corners) > 0:
if ids is not None:
if len(corners) <= 1 or ids[0] == 1:
return None
x1 = x2 = y1 = y2 = 0
point_11, point_21, point_31, point_41 = corners[0][0]
x1, y1 = int((point_11[0] + point_21[0] + point_31[0] + point_41[0]) / 4.0), int(
(point_11[1] + point_21[1] + point_31[1] + point_41[1]) / 4.0)
point_1, point_2, point_3, point_4 = corners[1][0]
x2, y2 = int((point_1[0] + point_2[0] + point_3[0] + point_4[0]) / 4.0), int(
(point_1[1] + point_2[1] + point_3[1] + point_4[1]) / 4.0)
return x1, x2, y1, y2
return None
4. Draw the Game Boarddef block_centers(row, col):
centers_of_square = {
(0, 0): [213.5, 57.5], (0, 1): [221.3, 7.9], (0, 2): [212.7, -49.3], (1, 0): [158.4, 50], (1, 1): [167.2, 3], (1, 2): [172.4, -51.2], (2, 0): [114.1, 52.9],
(2, 1): [121.1, 4.1], (2, 2): [113.9, -56.0]
}
if (row, col) in centers_of_square:
return centers_of_square[(row, col)]
else:
return None
def draw_board(frame):
height, width, _ = frame.shape
width_cell = width // columns
height_cell = height // rows
x_range = [0, width_cell, width_cell * 2, width_cell * 3]
y_range = [0, height_cell, height_cell * 2, height_cell * 3]
# Draw horizontal lines
for i in range(1, rows):
cv2.line(frame, (0, i * height_cell), (width, i * height_cell), (0,0,0), 3)
# Draw vertical lines
for j in range(1, columns):
cv2.line(frame, (j * width_cell, 0), (j * width_cell, height), (0,0,0), )
return x_range, y_range
5. Color DetectionThis part of code distinguish the background and chess pieces through the HSV color rule to obtain the center coordinates of the chess pieces.
def detect_color(frame, lower_color, upper_color, color_name, min_rect_size):
# Convert the frame from BGR to HSV color space
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Threshold the image to get only the specified color
color_mask = cv2.inRange(hsv, lower_color, upper_color)
# Find contours in the binary image
contours, _ = cv2.findContours(color_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
color_centers = []
# Check if there are any contours before processing
if contours:
# Draw rectangles around the color patches
for contour in contours:
# Get the bounding rectangle
x, y, w, h = cv2.boundingRect(contour)
# Check if the rectangle is bigger than the minimum size
if w > min_rect_size and h > min_rect_size:
# Calculate the center of the rectangle
center_x = x + w // 2
center_y = y + h // 2
# Draw rectangle
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
# Append the center coordinates to the list
color_centers.append([center_x, center_y])
return frame, color_centers
6. Integrate with CameraThis part of code implements a real-time tic-tac-toe game using computer vision. The game involves a human player and AI. It interacts with a camera, processes frames to detect moves, and updates the game board accordingly.
def play_tic_tac_toe_with_camera(detect, cap):
board = board_initialization()
player_turn = True # True for player X, False for player O
while True:
ret, frame = cap.read()
#print("before transform frame")
frame = detect.transform_frame(frame)
#print("after transform frame")
frame = cv2.flip(frame,-1)
x_range, y_range = draw_board(frame)
if not ret:
print("Error captured frame")
break
# Draw Tic Tac Toe board on the frame
#draw_board(frame)
# Draw X or O based on player's turn
if player_turn:
cv2.putText(frame, "Karteek's turn", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,0), 3, cv2.LINE_AA)
else:
cv2.putText(frame, "MyCobot turn", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,0), 3, cv2.LINE_AA)
# Detect keyboard input to make a pickup_place_cords
key = cv2.waitKey(1) & 0xFF
if key == 27: # Press 'Esc' to exit
break
if key == ord(' ') and player_turn: # Press 'Space' to make a pickup_place_cords for Player X
image = frame # Replace with the actual image path
cv2.waitKey(4)
result_image_yellow, yellow_centers = detect_color(image, lower_yellow, upper_yellow, "Yellow", min_rect_size)
for center in yellow_centers:
x, y = center
value_x, value_y = get_grid_indices(x, y, x_range, y_range)
#blue_color_list.append((value_x, value_y))
if board[value_y][value_x] == ' ':
board[value_y][value_x] = 'X'
#draw_pickup_place_cords(image, value_y, value_x, 'O')
#print(x_range, y_range)
#print("green :", green_centers)
#print("blue ", blue_centers)
print_board(board)
print("---------------------------------")
cv2.imshow("Project_Tic_Tac_Toe", image)
#cv2.waitKey(5)
#time.sleep(3)
player_turn = not player_turn
else:
print("Position opted for")
# AI makes a pickup_place_cords for Player O
if not player_turn:
best_pickup_place_cords = find_best_pickup_place_cords(board)
if best_pickup_place_cords:
row, col = best_pickup_place_cords
board[row][col] = 'O'
player_turn = not player_turn
print_board(board)
print("******************************")
#print(row, col)
pickup_place_cords(detect, row, col)
# Display the resulting frame
cv2.imshow("Tic Tac Toe", frame)
# Check for game over conditions
if cross_check_winner(board, 'X'):
print("Player wins!")
time.sleep(3)
break
elif cross_check_winner(board, 'O'):
print("Computer wins!")
time.sleep(3)
break
elif is_board_full(board):
print("Match draw!")
time.sleep(3)
break
cap.release()
cv2.destroyAllWindows()
7. Play Tic-tac-toe GameThis project showcases how to build a project applying human-machine confrontation with robotic arm myCobot 280 Pi, highlighting its technological capabilities, interactive fun, and educational value.
You can try to allowing myCobot to perform more complex operations. We're excited to see more users and makers using the myCobot series robots to create innovative projects and participate in our cases collection activity: https://www.elephantrobotics.com/en/call-for-user-cases-en/.
Comments
Please log in or sign up to comment.