编程之美:第一章 1.17俄罗斯方块游戏

/*
俄罗斯方块游戏:
1玩家操作:90度旋转积木块,左右移动积木块,让积木加速落下
2积木落到最下方或则在其他积木上无法移动时,会固定在该处,新的积木落下
3某行格子全部填满,该行小时,并成为玩家得分。一次删除的行越多,的扥越多
4积木堆积到区域上方,游戏结束


1如何用数据结构表示游戏的各种元素?如每个可活动的积木,在底层的积木
2现在已经知道底层积木的状态,然后在游戏区域上方出现新的积木,如何移位?
3有预览窗口时,可看到积木什么新装。比如下一个积木是长条时,就不要把最深的峡谷堵住。有了该新参数,如何改写程序?


分析:
每一块积木落下时,可以做:
1旋转到合适方向,2水平移动到某一列,3垂直下落到底部




1用一个二维数组area[M][N]表示M*N的游戏区域,数组中值为0表示空
2积木块也用数组表示,需要用统一尺寸的数组容纳所有可能的积木块,4*4的数组,积木块一共7种,每种4个方向,定义BlockSets[7][4],表示7中积木块的4个旋转
方向的形状,编译时将这个数组的值预计算好,程序中可以直接使用
可以得到旋转后的形状rotateBlock = BlockSets[n][m%4],n是特定的方块序号,m是旋转的次数。


判断方块的水平移动范围,记录积木块左上角相对于游戏区域的位移为(offset X,offset Y),平移范围即Offset X的取值范围
由于积木块可能无法占满4*4区域的每一列,因此横向位移x的值可能小于0.首先计算积木块所占区域的最小列minCol和最大列maxCol,则Offset X的取值范围为[0-minCol
,M-1-maxCol],L型积木块占据的最小列和最大列分别是1和2,因此水平移动范围为[-1,M-3]
用位移坐标,计算出积木块是否和游戏区域中已有的方块重叠。定义minRow和maxRow为积木块所占区域的最小行和最大行


while(OffsetY < N - maxRow)
{
  OffsetY++;
  Flag = 0;
  For i = 0 to 3//判断是否和已有方块重合
      For j = 0 to 3
	      if(Block[i][j] != 0 && Area[OffsetX + i][OffsetY + j] != 0)
		  {
		    Flag = 1;
		  }
  if(Flag == 1)
  {
    return OffsetY - 1;//如果有重合,则不能下落到该行
  }
}


可以下落的最低高度取决于最先接触到已有方块的那一列,可以计算每一列触底高度的最小值,即min0<=i<=3(di - maxRowi),di是该列堆积方块的高度


Dim configurations As Array
For i = 0 To 3//穷举所有旋转方向,得到各种旋转方式下的积木块形状
    rotateBlock = GetRotateBlock(currentBlock,i);
	[minCol,maxCol] = CalOffsetXRange(rotatedBlock);//计算横向坐标可以移动的范围
	For j = minCol To maxCol
	    y = CalcBottomOffsetY(rotatedBlock,j);//计算下落停留的纵向位移
		configurations.Add(i,j,y);//保存当前格局


判断格局更好例如消除2行,则加上3分,如果形成一个洞,扣除20分
1一次性多消行,同时消除1,2,3,4行,分别加1,3,7,13分
2不要形成洞,每增加一个洞,扣除4分,超过5个洞,额外扣除15分
3不要摆放太高,放置行高于M*3/5,则每高一行,扣除两分


积分规则的伪代码
Score = 0
CopyTo(area,tempArea)   // 复制一份游戏区域 
PasteTo(block,tempArea) // 将积木块放入复制的游戏区域中
linCount = 0;
For y = OffsetY to OffsetY + 4//消行一定发生在放入积木块的四行中
    if(RowIsFull(tempArea,y))
	{
	  lineCount++;
	}
Score += ClearLineScore[lineCount];
ClearLines(tempArea);//统计洞数前需要先消行
OffsetY += lineCont;//更新列下移位置
holeCount = 0;
For x = OffsetX To OffsetX + 4//增加的洞一定出现在放入积木块的4列(想不到,因为洞是按列计算的)
  holeCount += CalcHoles(tempArea,x) - CalcHoles(area,x);
Score -= holeCount*4;//每个洞扣除4分
if(holeCount > 5)
{
  Score -= 15;
}
if(OffsetY < M*3/5)
{
  Score = (M*3/5 - OffsetY)*2;//位置过高则扣分
}
return Score;


预知下一形状时,同样采用积分制,选取最好的格局。注意,摆放第二块积木前,第一块积木可能会消行,因此需要用额外空间处理。穷举法。
需要用剪枝来降低复杂度,穷举一个积木的各种格局,计算每种格局得分,然后只选取前N个最高得分的格局进行后续计算。
*/

你可能感兴趣的:(编程之美)