import curses
import random
from itertools import chain
class
GameField(object):
def __init__(self, width=4, height=4, win_value=2048):
self.width = width
self.height = height
self.win_value = win_value
self.score1 = 0
self.score2 = 0
self.highscore = 0
self.moves = {}
self.moves[
'Left1'
] = self.is_left_move
self.moves[
'Right1'
] = self.is_right_move
self.moves[
'Up1'
] = self.is_up_move
self.moves[
'Down1'
] = self.is_down_move
self.moves[
'Left2'
] = self.is_left_move
self.moves[
'Right2'
] = self.is_right_move
self.moves[
'Up2'
] = self.is_up_move
self.moves[
'Down2'
] = self.is_down_move
self.movesDict1 = {}
self.movesDict2 = {}
self.movesDict1[
'Left1'
] = self.left_move
self.movesDict1[
'Right1'
] = self.right_move
self.movesDict1[
'Up1'
] = self.up_move
self.movesDict1[
'Down1'
] = self.down_move
self.movesDict2[
'Left2'
] = self.left_move
self.movesDict2[
'Right2'
] = self.right_move
self.movesDict2[
'Up2'
] = self.up_move
self.movesDict2[
'Down2'
] = self.down_move
def random_create1(self):
while
True:
i, j = random.randint(0, self.height - 1), random.randint(0, self.width - 1)
if
self.field1[i][j] == 0:
self.field1[i][j] = random.choice([2, 2, 2, 4])
break
def random_create2(self):
while
True:
i, j = random.randint(0, self.height - 1), random.randint(0, self.width - 1)
if
self.field2[i][j] == 0:
self.field2[i][j] = random.choice([2, 2, 2, 4])
break
def reset(self):
self.field1 = [[0
for
j in range(self.width)]
for
i in range(self.height)]
self.score1 = 0
self.field2 = [[0
for
j in range(self.width)]
for
i in range(self.height)]
self.score2 = 0
self.random_create1()
self.random_create1()
self.random_create2()
self.random_create2()
def draw(self, stdscr):
stdscr.clear()
self.score1 = sum(chain(*self.field1))
self.score2 = sum(chain(*self.field2))
if
max(self.score1, self.score2) > self.highscore:
self.highscore = max(self.score1, self.score2)
stdscr.addstr(
'最高分:'
+ str(self.highscore) +
' '
)
stdscr.addstr(
'玩家1分数:'
+ str(self.score1) +
' '
)
stdscr.addstr(
'玩家2分数:'
+ str(self.score2) +
'\n'
)
for
row in self.field1:
stdscr.addstr(
'+'
+
'-----+'
* self.width +
'\n'
)
stdscr.addstr(
""
.join(
'|{:^5}'
.format(num)
if
num != 0
else
"| "
for
num in row) +
'|'
+
'\n'
)
stdscr.addstr(
'+'
+
'-----+'
* self.width +
'\n'
)
if
self.is_win1():
stdscr.addstr(
'胜利\n'
)
if
self.is_gameover1():
stdscr.addstr(
'游戏结束\n'
)
for
row in self.field2:
stdscr.addstr(
'+'
+
'-----+'
* self.width +
'\n'
)
stdscr.addstr(
""
.join(
'|{:^5}'
.format(num)
if
num != 0
else
"| "
for
num in row) +
'|'
+
'\n'
)
stdscr.addstr(
'+'
+
'-----+'
* self.width +
'\n'
)
if
self.is_win2():
stdscr.addstr(
'胜利\n'
)
if
self.is_gameover2():
stdscr.addstr(
'游戏结束\n'
)
stdscr.addstr(
"玩家1:上下左右键 玩家2:wasd键(R)重置(Q)退出"
)
def is_win1(self):
return
max(chain(*self.field1)) >= self.win_value
def is_win2(self):
return
max(chain(*self.field2)) >= self.win_value
def is_gameover1(self):
return
not any([self.is_move_possible1(direction)
for
direction in self.moves])
def is_gameover2(self):
return
not any([self.is_move_possible2(direction)
for
direction in self.moves])
@staticmethod
def invert(field):
return
[row[::-1]
for
row in field]
@staticmethod
def transpose(field):
return
[list(row)
for
row in zip(*field)]
@staticmethod
def is_row_change(row):
for
i in range(len(row) - 1):
if
row[i] == 0
and
row[i + 1] != 0:
return
True
elif row[i] != 0
and
row[i] == row[i + 1]:
return
True
else
:
return
False
def is_left_move(self, field):
return
any([self.is_row_change(i)
for
i in field])
def is_right_move(self, field):
return
any([self.is_row_change(i)
for
i in self.invert(field)])
def is_up_move(self, field):
return
any([self.is_row_change(i)
for
i in self.transpose(field)])
def is_down_move(self, field):
return
any([self.is_row_change(i)
for
i in self.invert(self.transpose(field))])
def is_move_possible1(self, direction):
if
direction in self.moves:
return
self.moves[direction](self.field1)
else
:
return
False
def is_move_possible2(self, direction):
if
direction in self.moves:
return
self.moves[direction](self.field2)
else
:
return
False
@staticmethod
def row_move(row):
row = sorted(row, key=lambda x: 1
if
x == 0
else
0)
for
i in range(len(row) - 1):
if
row[i] == row[i + 1]:
row[i] *= 2
row[i + 1] = 0
return
sorted(row, key=lambda x: 1
if
x == 0
else
0)
def left_move(self, field):
return
[self.row_move(i)
for
i in field]
def right_move(self, field):
return
self.invert([self.row_move(i)
for
i in self.invert(field)])
def up_move(self, field):
return
self.transpose([self.row_move(i)
for
i in self.transpose(field)])
def down_move(self, field):
return
self.transpose(self.invert([self.row_move(i)
for
i in self.invert(self.transpose(field))]))
def move1(self, direction):
if
direction in self.movesDict1
and
self.is_move_possible1(direction):
self.field1 = self.movesDict1[direction](self.field1)
self.random_create1()
return
True
else
:
return
False
def move2(self, direction):
if
direction in self.movesDict2
and
self.is_move_possible2(direction):
self.field2 = self.movesDict2[direction](self.field2)
self.random_create2()
return
True
else
:
return
False
def get_user_action(stdscr):
action = stdscr.getch()
if
action == curses.KEY_UP:
return
'Up1'
elif action == curses.KEY_DOWN:
return
'Down1'
elif action == curses.KEY_LEFT:
return
'Left1'
elif action == curses.KEY_RIGHT:
return
'Right1'
elif action == ord(
'r'
):
return
'Restart'
elif action == ord(
'q'
):
return
'Exit'
elif action == ord(
'w'
):
return
'Up2'
elif action == ord(
's'
):
return
'Down2'
elif action == ord(
'a'
):
return
'Left2'
elif action == ord(
'd'
):
return
'Right2'
def main(stdscr):
def init():
game_field.reset()
game_field.draw(stdscr)
return
'Game'
def game():
game_field.draw(stdscr)
action = get_user_action(stdscr)
if
action ==
'Restart'
:
return
'Init'
if
action ==
'Exit'
:
return
'Exit'
if
action in (
'Up1'
,
'Down1'
,
'Left1'
,
'Right1'
):
if
game_field.move1(action):
if
game_field.is_win1():
return
'Win'
if
game_field.is_gameover1():
return
'GameOver'
if
action in (
'Up2'
,
'Down2'
,
'Left2'
,
'Right2'
):
if
game_field.move2(action):
if
game_field.is_win2():
return
'Win'
if
game_field.is_gameover2():
return
'GameOver'
return
'Game'
def not_game():
game_field.draw(stdscr)
while
True:
action = get_user_action(stdscr)
if
action ==
'Restart'
:
return
'Init'
if
action ==
'Exit'
:
return
'Exit'
game_field = GameField()
state =
'Init'
state_actions = {
'Init'
: init,
'Game'
: game,
'Win'
: not_game,
'GameOver'
: not_game
}
while
state !=
'Exit'
:
state = state_actions[state]()
curses.wrapper(main)