python源码程序_python 2048游戏源码

import random

import curses

# 一开始生成两个方块

STARTUP_TILES = 2

# 随机生成的方块中出现4的概率

FOUR_POSSIBILITY = 0.1

# 游戏板

BOARD = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

# 游戏分数

SCORE = 0

# 是否有2048

HAS_2048 = False

# 是否已经不能动了

IS_STUCK = False

# 是否已经问过是否需要继续游戏了

ASKED_FOR_CONTINUE = False

# 方向

LEFT, RIGHT, UP, DOWN = 0, 1, 2, 3

# 用来代表是否可以结束游戏的常量

CAN_END = True

VECTOR = [[-1, 0], [1, 0], [0, -1], [0, 1]]

SUCCESS = True

FAILED = False

# curses相关

SCREEN = None

def clip(num, lowerbound, upperbound):

if num < lowerbound:

return lowerbound

elif num > upperbound:

return upperbound

else:

return num

def print_score():

global SCREEN

SCREEN.addstr(9, 0, ''.join(['本场游戏结束,得分:', str(SCORE), '。']))

def print_prompt(prompt):

global SCREEN

SCREEN.addstr(10, 0, prompt)

def get_user_input(prompt, requested_input):

global SCREEN

error_prompt_str = ''.join(

['请输入', ','.join([str(x) for x in requested_input]), '的其中之一。'])

print_prompt(prompt)

user_input = SCREEN.getkey()

while user_input not in requested_input:

print_prompt(error_prompt_str)

user_input = SCREEN.getkey()

return user_input

def get_random_tile_number():

return 4 if random.random() <= FOUR_POSSIBILITY else 2

def get_empty_pos():

result = []

for y, row in enumerate(BOARD):

for x, _ in enumerate(row):

if BOARD[y][x] == 0:

result.Append((x, y))

return result

def get_random_empty_pos():

# 因为get_empty_pos返回的是(x, y),对应横坐标(也就是列数)和横坐标(行数)

try:

col, row = random.choice(get_empty_pos())

return row, col

except IndexError:

return None

def gen_tile():

pos = get_random_empty_pos()

if pos is None:

return FAILED

row, col = pos

number = get_random_tile_number()

BOARD[row][col] = number

return SUCCESS

# 开始新游戏

def new_game():

global BOARD, SCORE, HAS_2048, IS_STUCK, ASKED_FOR_CONTINUE

# 将板和分数清空

BOARD = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

SCORE = 0

HAS_2048 = False

IS_STUCK = False

ASKED_FOR_CONTINUE = False

# 随机生成起始方块

for _ in range(STARTUP_TILES):

gen_tile()

while True:

print_board()

check_board()

if HAS_2048 and not ASKED_FOR_CONTINUE:

user_choice = get_user_input(

'你合并出了2048!还要继续吗?(输入Y继续,输入Q结束这盘游戏)[Y/Q]:',

['Y', 'Q', 'y', 'q']

)

if user_choice in 'yY':

print_prompt('好的,继续游戏……')

ASKED_FOR_CONTINUE = True

elif user_choice in 'qQ':

print_prompt('好的,结束游戏……')

break

elif IS_STUCK:

break

# 取用户输入

direction = get_user_input(

'请按方向键移动方块。(按Q放弃本盘游戏)',

['KEY_UP', 'KEY_DOWN', 'KEY_LEFT', 'KEY_RIGHT', 'Q', 'q']

)

if direction in 'qQ':

break

elif direction == 'KEY_LEFT':

direction = LEFT

elif direction == 'KEY_RIGHT':

direction = RIGHT

elif direction == 'KEY_UP':

direction = UP

elif direction == 'KEY_DOWN':

direction = DOWN

moved_result = move_tile(direction)

if moved_result:

gen_tile()

print_score()

# 这里是这样:整块板分为(1)顶部的边框和(2)数字和数字下面的边框。

# 横向同理,分为(1)左边的边框和(2)数字和数字右边的边框。

def print_board():

# 顶部边框

SCREEN.addstr(0, 0, '+----+----+----+----+')

for y, row in enumerate(BOARD):

# 左边边框

SCREEN.addstr(y * 2 + 1, 0, '|')

# the number

for x, num in enumerate(row):

# 我们用0表示当前位置没有方块

numstr = str(num) if num != 0 else ''

SCREEN.addstr(y * 2 + 1, x * 5 + 1, numstr +

(' ' * (4 - len(numstr))) + '|')

# 数字下面的边框

SCREEN.addstr(y * 2 + 2, 0, '+----+----+----+----+')

def move_tile(direction):

global SCORE

def get_line(offset: int, direction: int):

'''

取direction上offset一行/列的所有方块。例如,当需要将第2行左移时,用

get_line(1, LEFT)获得这一行。

'''

global BOARD

if direction == LEFT:

return BOARD[offset]

elif direction == RIGHT:

return list(reversed(BOARD[offset]))

elif direction == UP:

return [BOARD[y][offset] for y in range(4)]

elif direction == DOWN:

return [BOARD[y][offset] for y in range(3, -1, -1)]

def put_line(line: list, offset: int, direction: int):

'''

将一条方块按照direction所指的方向放进游戏板中。

'''

global BOARD

if direction == LEFT:

BOARD[offset] = line

elif direction == RIGHT:

BOARD[offset] = list(reversed(line))

elif direction == UP:

for y in range(4):

BOARD[y][offset] = line[y]

elif direction == DOWN:

for y in range(4):

BOARD[y][offset] = line[3 - y]

def move(line: list):

'''

移动一条方块。

'''

new_line = []

gained_score = 0

i = 0

while i < 4:

if line[i] == 0:

i += 1

else:

old_tile = line[i]

i += 1

while i < 4 and line[i] == 0:

i += 1

if i >= 4 or line[i] != old_tile:

new_line.append(old_tile)

else:

gained_score += line[i] + old_tile

new_line.append(line[i] + old_tile)

i += 1

while len(new_line) < 4:

new_line.append(0)

# 这里有三种情况:

# 1. 移动不了。

# 2. 移动了,但是没有得分。

# 3. 移动了,也得分了。

# 在这里,出现第一种情况时返回None,第二/三种情况返回移动好的方块和

# 本次移动获得的分。

if new_line == line:

return None

else:

return new_line, gained_score

board_moved = False

for offset in range(4):

line = get_line(offset, direction)

moved_line = move(line)

if moved_line is not None:

board_moved = True

line, gained_score = moved_line

put_line(line, offset, direction)

SCORE += gained_score

put_line(line, offset, direction)

# 在这里,对于整个游戏板,有两种情况:

# 1. 有至少一行/一列移动了。

# 2. 没有。全部都没有移动。

# 在第二种下是不应该生成新的方块的。在这里返回游戏板有没有移动:

return board_moved

def get_neighbour(x, y, width, height):

global VECTOR

result = []

for vec in VECTOR:

new_x = x + vec[0]

new_y = y + vec[1]

if 0 <= new_x < width and 0 <= new_y < height:

result.append((new_x, new_y))

return result

def check_board():

global BOARD, HAS_2048, IS_STUCK

for y, row in enumerate(BOARD):

for x, num in enumerate(row):

# 如果有2048,那么就记住有2048。

if num == 2048:

HAS_2048 = True

return

# 如果有空位,那么就可以继续移动。

elif num == 0:

IS_STUCK = False

return

else:

for new_x, new_y in get_neighbour(x, y, 4, 4):

if BOARD[new_y][new_x] == num:

IS_STUCK = False

return

IS_STUCK = True

return

def main(stdscr):

global SCREEN

SCREEN = stdscr

while True:

SCREEN.clear()

new_game()

user_choice = get_user_input(

'是否开始下一盘?(输入Y开始下一盘,输入Q退出)[Y/Q]', ['Y', 'Q', 'y', 'q'])

if user_choice in 'qQ':

print_prompt('正在退出……')

break

elif user_choice in 'yY':

print_prompt('开始下一盘……')

continue

# don't start the thing when loading in interactive mode.

if __name__ == '__main__':

curses.wrapper(main)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值