这个Principle of Computing 是Rice U在coursera上的Python课系列的第二门课。这个课的每个mini-project都是有一些小小的挑战的。
第一个mini project是实现游戏2048。
1 合并的时候每个数字只能参加一次合并。
比如,图1使用了”—>“右方向键得到图2. 注意结果不是8,是4,4。
A given tile can only merge once on any given turn
You can slide the tiles in any direction (left, right, up, or down) to move them. When you do so, if two tiles of the same number end up next to each other, they combine to form a new tile with twice the value.
图1 图2
2 准备工作
2.1. 矩阵
http://www.codeskulptor.org/#poc_indexed_grid.py
3 test模块
3.1 学校提供的简单的UnitTest模块poc_simpletest http://www.codeskulptor.org/#poc_simpletest.py
3.2 demo,通过poc_simpletest 测试模块去测试StopWatch
http://www.codeskulptor.org/#poc_format_testsuite.py
http://www.codeskulptor.org/#poc_format_student.py
4 import
4.1 使用import https://class.coursera.org/principlescomputing-001/wiki/view?page=imports
5 我的代码
"""
Clone of 2048 game.
"""
import poc_2048_gui
import random
# Directions, DO NOT MODIFY
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
# Offsets for computing tile indices in each direction.
# DO NOT MODIFY this dictionary.
OFFSETS = {UP: (1, 0),
DOWN: (-1, 0),
LEFT: (0, 1),
RIGHT: (0, -1)}
def merge(line):
"""
Helper function that merges a single row or column in 2048
"""
list_res = [0] * len(line)
bool_res = [1] * len(line)
var_j = 0
for var_i in range(len(line)):
if line[var_i] != 0:
if list_res[var_j-1] == line[var_i] and bool_res[var_j-1] == 1:
list_res[var_j-1] +=line[var_i]
bool_res[var_j-1] = 0;
else:
list_res[var_j] = line[var_i]
var_j += 1
return list_res
class TwentyFortyEight:
"""
Class to run the game logic.
"""
def __init__(self, grid_height, grid_width):
self._grid_height = grid_height
self._grid_width = grid_width
self._grid = [[ 0 for dummy_i in range(self._grid_width)] for dummy_j in range(self._grid_height)] #2D矩阵初始化
self._intial_tiles = {
UP: [ (0, i) for i in range(grid_width) ],
DOWN: [ (grid_height-1, i) for i in range(grid_width) ],
LEFT: [ (i, 0) for i in range(grid_height) ],
RIGHT: [ (i, grid_width-1) for i in range(grid_height) ],
}
self._move_helper_func = {
UP:self.helper_merge_up,
DOWN: self.helper_merge_down,
LEFT: self.helper_merge_left,
RIGHT: self.helper_merge_right,
}
self._flag_changed = False;
self.reset()
def reset(self):
"""
Reset the game so the grid is empty.
"""
for var_i in range(self._grid_height):
for var_j in range(self._grid_width):
self._grid[var_i][var_j]=0;
def __str__(self):
"""
Return a string representation of the grid for debugging.
"""
res_str = "[\n"
for var_i in range(self._grid_height):
res_str += "["
for var_j in range(self._grid_width):
res_str += str(self._grid[var_i][var_j]) + ", "
res_str += "]\n"
res_str += "]"
return res_str
def get_grid_height(self):
"""
Get the height of the board.
"""
return self._grid_height;
def get_grid_width(self):
"""
Get the width of the board.
"""
return self._grid_width;
def helper_merge_up(self,temp_list_new,ele):
"""
Move the merged list to the original grid, UP direction
"""
for var_i in range(self.get_grid_height()):
if self._flag_changed == False and self._grid[var_i][ele[1]] != temp_list_new[var_i]:
self._flag_changed = True;
self.set_tile(var_i,ele[1],temp_list_new[var_i])
def helper_merge_down(self,temp_list_new,ele):
"""
Move the merged list to the original grid, DOWN direction
"""
for var_i in range(self.get_grid_height()):
if self._flag_changed == False and self._grid[self.get_grid_height()-var_i-1][ele[1]] != temp_list_new[var_i]:
self._flag_changed = True;
self.set_tile(self.get_grid_height()-var_i-1, ele[1], temp_list_new[var_i])
def helper_merge_left(self,temp_list_new,ele):
"""
Move the merged list to the original grid, LEFT direction
"""
for var_i in range(self.get_grid_width()):
if self._flag_changed == False and self._grid[ele[0]][var_i] != temp_list_new[var_i]:
self._flag_changed = True;
self.set_tile(ele[0],var_i,temp_list_new[var_i])
def helper_merge_right(self,temp_list_new,ele):
"""
Move the merged list to the original grid, RIGHT direction
"""
for var_i in range(self.get_grid_width()):
if self._flag_changed == False and self._grid[ele[0]][self.get_grid_width()-var_i-1] != temp_list_new[var_i]:
self._flag_changed = True;
self.set_tile(ele[0], self.get_grid_width()-var_i-1, temp_list_new[var_i])
def move(self, direction):
"""
Move all tiles in the given direction and add
a new tile if any tiles moved.
"""
self._flag_changed = False;
for ele in self._intial_tiles[direction]:
temp_index_list = []
temp_list = []
temp_index_list.append(ele);
while temp_index_list[-1][0]>=0 and temp_index_list[-1][0]<self.get_grid_height() and temp_index_list[-1][1]>=0 and temp_index_list[-1][1]<self.get_grid_width():
temp_list.append(self.get_tile(temp_index_list[-1][0],temp_index_list[-1][1]))
temp_index_list.append((temp_index_list[-1][0]+OFFSETS[direction][0],temp_index_list[-1][1]+OFFSETS[direction][1]));
temp_list_new = merge(temp_list)
self._move_helper_func[direction](temp_list_new,ele)
if self._flag_changed :
self.new_tile()
def new_tile(self):
"""
Create a new tile in a randomly selected empty
square. The tile should be 2 90% of the time and
4 10% of the time.
"""
non_zero_count = 0;
for var_i in range(self._grid_height):
for var_j in range(self._grid_width):
if self._grid[var_i][var_j] == 0:
non_zero_count +=1;
random_choice = random.randrange(0,non_zero_count);
var_k = 0
generated_new_tile = False
for var_i in range(self._grid_height):
for var_j in range(self._grid_width):
if generated_new_tile==False and self._grid[var_i][var_j] == 0:
if var_k != random_choice:
var_k += 1
else:
random_2_4 = random.randrange(0,100)
if random_2_4 <10:
self.set_tile(var_i,var_j,4)
else:
self.set_tile(var_i,var_j,2)
generated_new_tile = True;
def set_tile(self, row, col, value):
"""
Set the tile at position row, col to have the given value.
"""
self._grid[row][col] = value;
def get_tile(self, row, col):
"""
Return the value of the tile at position row, col.
"""
return self._grid[row][col];
poc_2048_gui.run_gui(TwentyFortyEight(4, 9))