用于表示和旋转俄罗斯方块游戏的最佳算法(和解释)是什么?我总是发现片段旋转和表示方案令人困惑.
大多数俄罗斯方块游戏似乎在每次轮换时都使用了一个天真的"重制阵列块":
http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=tetris
但是,有些人使用预先构建的编码数字和位移来表示每个部分:
http://www.codeplex.com/wintris
有没有一种方法可以使用数学来做到这一点(不确定哪种方法适用于基于单元的电路板)?
这是一个基于俄罗斯方块的谜题.在这个谜题中,我们将获得接下来将从顶部落下的n个片段的序列.我们的工作是在GameOver之前最大化得分.一般的俄罗斯方块没有多项式时间算法,但在这个难题中只允许I(直)四联体.虽然它不允许旋转它们.
所以这里是约束:
找到可以获得的最高分数.
例:
8 x 6板.接下来的7个tetrominoes是[——,|,|,——,|,——,|]其中'——'表示水平我四氨基和|表示垂直我四氨基.
在这种情况下,最大可能得分是3使用以下策略('.'代表空板,'#'代表四氨基片的一部分).
Initially:
........
........
........
........
........
........
1st move:
........
........
........
........
........
####....
2nd Move:
........
........
.......#
.......#
.......#
####...#
3rd Move:
........
........
......##
......##
......##
####..##
4th Move:
........
........
......##
......##
####..##
####..##
5th Move:
........
........
.....###
.....###
####.###
####.###
6th Move:
........
........
.....### …Run Code Online (Sandbox Code Playgroud) 我正在使用遗传算法创建一个俄罗斯方块播放器,并面临一些问题.我已经阅读了很多相关的作品,但他们没有给我足够的GA细节.
问题是我的代理似乎很快被卡住了...我使用评估功能采取了4个功能:高度,覆盖的孔,平整度和清除行数.我读了一些使用相同评估的论文,并且能够完成数千行.
经过600代,拥有100个代理商,最好的代理商平均只能做260行,这是蹩脚的.所有代理都在播放相同的片段.
我的GA详情:
世代:600人口:100
基因:4个浮点值的数组,介于0和1之间.
均匀交叉以一定的概率发生,并且以一定的概率在两个父母之间交换基因.
突变发生在一定的概率,这里我尝试了3种不同的方法:交换基因,用随机值替换基因,或者为基因添加一些噪音值.
我有50%的精英率,并注意到一些好的特工正在被选中并生下更糟糕的特工,污染了人口.
选择是轮盘赌...
如果有人能给我详细介绍交叉和变异的最佳方式,我很感激!
谢谢,对不起这篇长篇文章感到抱歉!
很高兴看到两个投票的问题.我现在要重新提出我的问题以避免混淆.
问题是如何用没有孔的随机但预定义的形状填充mxn网格/矩阵.预定义的形状具有变量k,其是形状由多少个块组成.每个块都是正方形,并且与网格方块的大小相同(即1x1网格).可以旋转形状以适合网格,但不会收缩或扩展.k不会改变一轮,换句话说,m,n和k在我运行答案脚本时不会改变.当我第二次运行脚本时,我可能会更改其中的一个或全部.例如,第一次,我可以运行答案脚本,其中k = 4,m = 10,n = 20.脚本完成并打印输出.第二次我将k = 3,m = 6且n = 10.我将保证m次n并且乘积调制k等于零(mxn%k = 0)以确保它们在数学上彼此适合.好的,还有一个条件:1
脚本需要从预设k池中随机填充网格.当k = 2时,预定义的形状只有一种,两个块在一起.如果你认为没有旋转,那么它有两种,水平和垂直.当k = 4时,基本上用Tetris块填充网格,即共有7种预定义形状(每种都可以旋转,并制作~20种).什么是k = 5的预定义形状,我还不知道.答案可以计算或者可以硬编码,因为找到k = 5的所有形状并不困难.
如果解决方案有限,则不需要随机.例如,m = 2,n = 2,k = 4; 或m = 1,n = 4,k = 2.别无他法,没有随机.
网格中的任何位置都不能留下任何孔.我认为,没有经过深思熟虑,许多使用mxn和mxn%k = 0的网格将有一个没有洞的解决方案.直观地说这听起来很合理,但在数学上我不知道.如果m或n是k的倍数,则保证有(所有直条)的解.
理想情况下,我希望k是一个小整数,如k <10,但在2到5的范围内是可以接受的.如果它更简单,我们可以在这里有一个固定的k,例如4,因为俄罗斯方块有着名的7个形状(ITOLJSZ).
我正在寻找Perl中最好的解决方案.Python也没问题.程序每次都需要运行m,n和k.再次,我将m,n,k拟合mxn%k = 0.
我在Perl中尝试过的努力可以解决一些k = 3的情况,并且由于边缘/角落中的单个(洞)而导致某些情况失败.需要一个好方法来检查是否有任何块变成单例.我的文本输出看起来像这样(m = 4,n = 9,k = 3).你当然可以使用这种或任何有意义的格式.
AABB
ACCB
DCEE
DFFE
DFGH
IGGH
IIJH
KKJJ
KLLL
Run Code Online (Sandbox Code Playgroud)
我将获得100分的奖励(感谢那两个投票,我现在有107个声誉)来奖励最佳解决方案.
感谢您的输入.
我写了一个工作的俄罗斯方块克隆,但它有一个非常凌乱的布局.我可以获得有关如何重构我的类以使我的编码更好的反馈.我专注于使我的代码尽可能通用,试图使它更像是仅使用块的游戏引擎.
每个块都是在游戏中单独创建的.我的游戏有2个BlockLists(链表):StaticBlocks和Tetroid.StaticBlocks显然是所有非移动块的列表,而tetroid是当前tetroid的4个块.
主要是世界被创造.
首先创建一个新的tetroid(列表Tetroid中的4个块)(NewTetroid)
通过(***碰撞)函数检测碰撞,通过使用(If*****)函数比较每个Tetroid和所有StaticBlock.
当tetroid停止(击中底部/块)时,它被复制(CopyTetroid)到StaticBlocks并且Tetroid变为空,然后通过用(SearchY)搜索StaticBlocks来测试完整的行,销毁/删除块等.
创建了一个新的tetroid.
(TranslateTetroid)和(RotateTetroid)逐个对Tetroid列表中的每个块执行操作(我认为这是不好的做法).
(DrawBlockList)只是遍历一个列表,为每个块运行Draw()函数.
通过在调用(NewTetroid)时相对于Tetroid中的第一个块设置旋转轴来控制旋转.我的每个程序段的旋转功能(旋转)使其围绕轴旋转,使用输入+ -1进行左/右旋转.RotationModes和States用于以2种或4种不同方式旋转的块,定义它们当前处于什么状态,以及它们是应该向左还是向右旋转.我不满意这些在"世界"中的定义,但我不知道在哪里放置它们,同时仍然保持我的(旋转)功能对每个块都是通用的.
我的课程如下
class World
{
public:
/* Constructor/Destructor */
World();
~World();
/* Blocks Operations */
void AppendBlock(int, int, BlockList&);
void RemoveBlock(Block*, BlockList&);;
/* Tetroid Operations */
void NewTetroid(int, int, int, BlockList&);
void TranslateTetroid(int, int, BlockList&);
void RotateTetroid(int, BlockList&);
void CopyTetroid(BlockList&, BlockList&);
/* Draw */
void DrawBlockList(BlockList&);
void DrawWalls();
/* Collisions */
bool TranslateCollide(int, int, BlockList&, BlockList&);
bool RotateCollide(int, BlockList&, BlockList&);
bool OverlapCollide(BlockList&, BlockList&); // For end …Run Code Online (Sandbox Code Playgroud) 这是我的第一篇文章.我在两个月前考虑职业交换时开始编码,正在研究俄罗斯方块克隆.我已经实现了大部分核心功能,但无法通过后循环让游戏不断刷新.
我正在使用Tkinter来制作我的Gui并且正在尝试面向事件的编程.
我的理解是,after(Time, Event)从Tkinter应安排任何的Event回调函数是由指定的延迟后发生Time.我认为代码应该在此之后继续执行后续项目.
我的帧刷新函数(game.updateBoard())执行俄罗斯方块工作的大部分必要事件,然后使用after调用自身.初始化游戏实例时我会调用一次.
mainloop()该game.updateboard()函数不是继续进行,而是after无限期地调用自身.
我怀疑它的表现并不像我认为的那样after,在指定的延迟发生之前继续执行脚本.我认为它正在等待回调终止继续.
我试图找到一个资源,但不能.
如果您有解决此问题,附加代码或一般编码的建议,我很高兴听到它们!这是一个学习过程,我很乐意尝试你提出的任何建议.
以下是代码的相关部分:
class game():
def __init__(self): #Set up board and image board
self.pieces = ["L","J","S","Z","T","O","I"]
self.board = boardFrame()
self.root = Tk()
self.root.title("Tetris")
self.root.geometry("250x525")
self.frame = Frame(self.root)
#set up black and green squares for display
self.bSquare = "bsquare.gif"
self.gSquare = "square.gif"
self.rSquare = "rsquare.gif"
self.image0 = PhotoImage(file = self.bSquare)
self.image1 = PhotoImage(file = self.gSquare)
self.image2 = …Run Code Online (Sandbox Code Playgroud) 我曾经写过一个很好玩俄罗斯方块的俄罗斯方块AI.我使用的算法(在本文中描述)是一个两步过程.
在第一步中,程序员决定跟踪对问题"感兴趣"的输入.在俄罗斯方块中,我们可能有兴趣跟踪连续存在的差距,因为最小化差距可以帮助更容易地放置未来的碎片.另一个可能是平均柱高,因为如果您即将失败,承担风险可能是个坏主意.
第二步是确定与每个输入相关联的权重.这是我使用遗传算法的部分.只要根据结果随时间调整权重,任何学习算法都会在此处执行.我们的想法是让计算机决定输入与解决方案的关系.
使用这些输入及其权重,我们可以确定采取任何行动的价值.例如,如果将直线形状一直放在右列中将消除4个不同行的间隙,那么如果其重量很高,则此动作可以获得非常高的分数.同样地,将其平放在顶部可能实际上会导致间隙,因此动作得分较低.
我一直想知道是否有办法将学习算法应用到第一步,在那里我们找到"有趣的"潜在输入.似乎可以编写一种算法,其中计算机首先学习哪些输入可能有用,然后应用学习来权衡这些输入.之前有过这样的事吗?它是否已经在任何AI应用程序中使用?
我正在努力编写一个尽可能符合俄罗斯方块指南的微缩版俄罗斯方块:
确切地说,我希望完整的游戏尽可能少地构建140字节的javascript.第一个140字节的脚本应返回一个包含112个整数值的数组,这些值代表4个旋转位置中每个位置的7个tetrominos的4行.旋转的确切位置顺序非常重要.
我把数据放在16位unicode字符中(尽管它们计算为2个字节)并且只需140多个字节就可以解压缩.
有谁知道构建这个数组的聪明方法?
var s ="ༀༀ∢䑄䑄ˠౄౄ00000000 ٔٔࣄӠѤѢࣄӠѤӄӈ",m = []; for(i = 0; i <28; i ++){c = s.charCodeAt(i); for(j = 4; j> 0; ){m.push(c >>(4* - j)&15)} return m}
I tetrimino
Spawn Rotate90 Rotate180 Rotate270
????????? ????????? ????????? ?????????
? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? ??? ? ?
????????? ????????? ????????? ?????????
????????? ? ? ??? ? ? ? ? ? ? ? ??? ? ?
????????? ????????? …Run Code Online (Sandbox Code Playgroud) 我正在编写一个程序,需要快速检查连续的空间区域是否可以被四格骨牌(任何类型、任何方向)填充。我的第一次尝试是简单地检查平方数是否能被 4 整除。但是,这样的情况仍然可能会出现:
\n\n
\n
正如您所看到的,即使这些区域每个都有 8 个方格,它们也不可能用四格骨牌平铺。
\n\n我想了一会儿,但不知道如何继续。在我看来,“枢纽”广场,或者通向两个以上“隧道”的广场,是关键。在上面的示例中很容易,因为您可以快速计算每个此类隧道 \xe2\x80\x94 3、1 和 3 在第一个示例中的空间,以及在第二个示例中的 3、1、1 和 2 \xe2\x80\x94 并确定不可能继续进行,因为每个隧道都需要连接到中心广场以安装四格骨牌,而这对于所有隧道来说都是不可能发生的。但是,您可以有更复杂的示例,如下所示:
\n\n
...简单的计数技术根本不起作用。(至少,据我所知。)更不用说更多的开放空间和很少数量的中心广场了。另外,我没有任何证据表明中心方块是这里唯一的技巧。据我所知,可能还有很多其他不可能的情况。
\n\n某种搜索算法(A*?)是解决这个问题的最佳选择吗?我非常关心数百甚至数千个方块的性能。该算法需要非常高效,因为它将用于实时平铺(或多或少),并且在浏览器中。
\n我正在写一个俄罗斯方块克隆,我在C#中进行原型设计.最终的代码应该在嵌入式系统上运行(使用8位CPU和非常小的RAM),所以我试图使用天真的算法来清除行.
现在,我的playfield是一个2D数组:
private readonly TetrominoType[][] _playfield;
Run Code Online (Sandbox Code Playgroud)
(其中TetrominoType是一个枚举,表示无或7种类型中的一种,用于着色块)
当一行被清除时,我想要就地修改这个数组,这就是我的问题所在.举个例子:
Before After
0 # # # #
1 # # # #
2 # # # #
3 # # # #
4 # # # #
5 #xxxxxx# # #
6 #x xx# # #
7 #xxxxxx# # #
8 #xxxxxx# #x xx#
9 #x xxxx# #x xxxx#
######## ########
Run Code Online (Sandbox Code Playgroud)
我已经确定需要删除第5,7和8行,因此其他行应该掉下来,让我处于右边的状态.
我天真的方法是向后迭代并将行复制到已清除的行上方,基本上:
for(int iy = 9; iy >= 0; iy--) {
if(_linesToClear.Contains(iy)) {
for(int ix = 0; ix < …Run Code Online (Sandbox Code Playgroud)