Ejemplo n.º 1
0
    def game_loop(self):

        board = self.board
        grav_rate = 200

        moves = []

        clock = pygame.time.Clock()

        tick_counter = 0

        get_moves = self.handle_key_event if not self.use_ai else self.ai.next_moves

        if self.use_ai:
            moves = get_moves()

        while True:

            time = pygame.time.get_ticks()

            tick_counter += 1

            # get the next move(s)
            if not self.use_ai:
                moves += get_moves()

            # execute move from move_queue
            if len(moves) > 0:
                next_move = dequeue(moves)
                board.execute_move(next_move)

                if next_move == encode_move('hold'):

                    self.get_next_piece()

                elif next_move == encode_move('drop'):
                    if not self.reset_board():
                        break
                    else:
                        moves += get_moves()

            if tick_counter == TICK_DELAY:
                tick_counter = 0

                if not board.move_current_down():
                    # reset
                    if not self.reset_board():
                        break
                    else:
                        moves += get_moves()

            self.render()

            pygame.display.flip()
            clock.tick(60)
            prev = time
Ejemplo n.º 2
0
    def make_children(self, children, piece, held, next_can_hold, put_hold):

        maximum = float('-inf')
        ind = -1

        for i in range(len(children)):
            # unpack that child
            x, y, rot, moveset = children[i]

            # create new board and execute moves
            new_board = self.board.get_copy()

            new_piece = Block(piece)
            new_piece.execute_moves(moveset, self.board)
            new_piece.set(new_board)

            # calculate points
            new_lines = self.lines_sent
            combo_id = -1
            new_combos_so_far = self.combos_so_far + 1

            lines_cleared = new_board.clear_lines()

            if lines_cleared == 0:
                new_combos_so_far = 0
            else:
                is_tspin = tspin_detect(moveset)
                is_perf_clear = perf_clear_detect(new_board)
                combo_id = 1 if is_tspin else 0 if is_perf_clear else -1

                if is_tspin and is_perf_clear:
                    combo_id = 2

                new_lines += next_points(
                    self.combos_so_far - 1,
                    lines_cleared if lines_cleared != 4 else 0,
                    lines_cleared == 4, is_tspin, is_perf_clear,
                    combo_id == self.last_combo_id)

            # create the new node
            new_node = Tree_node(new_board, held, new_lines, new_combos_so_far,
                                 combo_id, next_can_hold)

            self.add_child(
                ([encode_move('hold')] if put_hold else []) + moveset,
                new_node)

            ranking = new_node.get_rank()
            if ranking > maximum:
                maximum = ranking
                ind = i

        return (maximum, ind)
Ejemplo n.º 3
0
	def make_nodes(self, children, piece_type, held_piece, q, is_held):

		for child in children:

			x, y, rot, moveset = child

			new_board = self.board.get_copy()

			new_piece = Block(piece_type)
			new_piece.execute_moves(moveset, self.board)
			new_piece.set(new_board)

			new_lines = self.lines_sent
			combo_id = -1
			new_combos_so_far = self.combos_so_far + 1

			lines_cleared = new_board.clear_lines()
			if lines_cleared == 0:
				new_combos_so_far = 0
			else:
				is_tspin = tspin_detect(moveset)
				is_perf_clear = perf_clear_detect(new_board)
				combo_id = 1 if is_tspin else 0 if is_perf_clear else -1

				if is_tspin and is_perf_clear:
					combo_id = 2

				new_lines += next_points(self.combos_so_far - 1,
										 lines_cleared if lines_cleared != 4 else 0,
										 lines_cleared == 4,
										 is_tspin,
										 is_perf_clear,
										 combo_id == self.last_combo_id)


			nq = [] if len(q) < 2 else deepcopy(q[1:])

			new_node = Tree_node(new_board,
								-1 if len(q) == 0 else q[0],
								held_piece,
								nq,
								new_lines,
								new_combos_so_far,
								combo_id,
								self.ranker,
								is_held)

			self.add_child(([encode_move('hold')] if is_held else []) + moveset, new_node)
Ejemplo n.º 4
0
    def generate_children_with_piece(self, piece):

        maximum = float('-inf')
        ind = -1

        # if not the leaf, recurse
        if not self.is_leaf:

            for i in range(len(self.children)):
                child = self.children[i]
                max_v, _ = child.generate_children_with_piece(piece)

                if max_v > maximum:
                    maximum = max_v
                    ind = i

            return (maximum, ind)

        # otherwise we've hit the leaf
        self.revoke_leaf()

        # in all cases, we assume there is no current piece, but there may be a held piece
        # so first generate all possible states with the current piece without holding

        children1 = self.board.successor_states(piece)
        maximum, ind = self.make_children(
            children1, piece, self.held, True,
            False)  # the next can hold because we did not hold on these

        # now we hold the piece, but only if we can hold in the first place
        if self.can_hold:

            # either there was a held piece already or not
            # if there was a held piece, swap and execute moves and set can_hold to true for the children
            # otherwise generate one node with the current cleared, i.e. the new piece is held

            # there is a piece
            if self.held > -1:

                children2 = self.board.successor_states(self.held)
                max2, ind2 = self.make_children(children2, self.held, piece,
                                                True, True)

                if max2 > maximum:
                    maximum = max2
                    ind = ind2

            # hold this piece
            else:
                held_node = Tree_node(
                    self.board,
                    piece,
                    self.lines_sent,
                    self.combos_so_far,
                    self.last_combo_id,
                    False  # can't hold the next one
                )

                self.add_child([encode_move('hold')], held_node)

                ranking = held_node.get_rank()
                if ranking > maximum:
                    maximum = ranking
                    ind = len(self.children) - 1

        return (maximum, ind)
Ejemplo n.º 5
0
from tree_search import Tetris_Search_Tree
from collections import deque

PIECE_W = 20
PIECE_H = 20
PIECE_MARGIN = 1

TOTAL_PIECE_WIDTH = PIECE_MARGIN + PIECE_W
TOTAL_PIECE_HEIGHT = PIECE_MARGIN + PIECE_H

TICK_DELAY = 50

GRAY = (80, 80, 80)

ACTIONS = {
    'LEFT': encode_move('left'),
    'RIGHT': encode_move('right'),
    'DOWN': encode_move('down'),
    'UP': encode_move('crot'),
    'SPACE': encode_move('drop'),
    'c': encode_move('hold'),
    'z': encode_move('ccrot'),
    'x': encode_move('crot'),
}


class Tetris:
    def __init__(self, width=None, height=None):
        if height == None and width == None:
            board = Board_Controller()
        else:
Ejemplo n.º 6
0
def generate_successor_states(board, piece_type):
	# number of unique rotations per piece
	r = valid_rotations(piece_type)

	# store all possible positions in a queue
	pos = Queue()
	# 3D memo for later ;)
	memo = [[[0 for z in range(r)] for y in range(board.get_height())] for x in range(board.get_width())]

	# for each unique rotation
	for rotation in range(r):
		# construct a temporary piece
		temp_piece = Block(piece_type)
		temp_piece.set_rotation(board, rotation)


		# get the next offset after rotating
		sx = temp_piece.get_offset()[0]

		# for each horizontal position
		for x in range(board.get_width() - temp_piece.get_width() + 1):

			# shift the piece horizontally
			temp_piece.set_offset(x, 0)
			if temp_piece.collides(board):
				continue

			# drop
			temp_piece.drop(board)

			# get final position
			tx, ty = temp_piece.get_offset()

			# memoize
			memo[tx][ty][rotation] = 1

			#print(str(tx) + ", " + str(ty) + ", " + str(rotation))

			# encode moves
			moves = [encode_move('crot') for i in range(rotation)] + [encode_move('left') if x - sx < 0 else encode_move('right') for i in range(abs(x-sx))] + [encode_move('drop')]

			# enqueue
			pos.put((tx, ty, rotation, moves))

	# the final set to return
	children = []

	# while the queue still contains positions
	while not pos.empty():

		child = pos.get()

		# add to final bag
		children.append(child)

		x, y, rot, moves = child

		# make a block and put it into the correct place
		test_piece = Block(piece_type)
		test_piece.execute_moves(moves, board)

		o_off_x, o_off_y = test_piece.get_offset()

		# generate partial movements from this position, i.e. left, right, and all rotations
		# stored in tuples like so (dx, dy, nr)
		next_positions = [(1, 0, rot), (-1, 0, rot)] + [(0,0,i) for i in range(r)]

		# for each partial movement
		for npos in next_positions:
			# quick access variables
			dx, dy, nr = npos

			# rotate the piece for the new rotation, if possibe, else its invalid so skip
			if not test_piece.set_rotation(board, nr):
				continue

			offset = test_piece.get_offset()

			# translate the piece right or left or skip if invalid
			if (dx > 0 and not test_piece.r_translate(board)) or (dx < 0 and not test_piece.l_translate(board)):
				continue

			# apply gravity
			down = test_piece.drop(board)

			# get updated locations
			nx, ny = test_piece.get_offset()

			# check that the move was not already encoded
			if memo[nx][ny][nr] == 1:
				test_piece.dirty_reset_position(o_off_x, o_off_y, rot)
				continue

			# now encode additional movements
			# copy moves and convert drops to down movements because this is more meticulous

			nmoves = deepcopy(moves)

			# convert drops to down moves
			l = len(moves) - 1
			if moves[l] == encode_move('drop'):
				nmoves = nmoves[:l] + [encode_move('down') for i in range(y)]

			# generate additional horizontal movements
			if dx != 0:
				nmoves.append(encode_move('left') if dx == -1 else encode_move('right'))

			# generate rotation movements
			dr = nr - rot
			#print("rotations:",dr)
			if rot == 3 and nr == 0:
				nmoves += [encode_move('crot')]
			elif dr != 0:
				nmoves += [encode_move('crot') if dr > 0 else encode_move('ccrot') for i in range(abs(dr))]

			# generate additional down movements
			nmoves += [encode_move('down') for i in range(down)]

			# enqueue
			pos.put((nx, ny, nr, nmoves))

			# mark this new space as visited, too
			memo[nx][ny][nr] = 1

			# undo moves
			test_piece.dirty_reset_position(o_off_x, o_off_y, rot)

	return children