ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python – Haskell算法/ Candy Crush可能移动

2019-07-25 08:59:20  阅读:222  来源: 互联网

标签:python haskell


我是一名本科编程学生,我正在尝试创建一个类似于“糖果粉碎”的程序.我试图在这里翻译这段代码,以便了解如何搜索可能的动作.下面是Haskell中的一段代码(尽管不完全确定)

possibleMoves gf = filter works $filter valid $allMoves
where allMoves           = concat [ [((i,j),(i+1,j)), ((i,j),(i,j+1))] | (i,j) <- range ((0,0),(9,9)) ]
      valid (_,(i,j))    = i < 10 && j < 10 -- first coordinate is always correct
      works move@(i1,i2) = let gf' = flipStones gf move
                           in  lookAround i1 gf' || lookAround i2 gf'

lookAround (i,j) gf' = any ((>=3).length) $
    (groupBy combineable $[ gf' ! (i',j) | i' <- range (max 0 (i-2), min 9 (i+2)) ]) ++
    (groupBy combineable $[ gf' ! (i,j') | j' <- range (max 0 (j-2), min 9 (j+2)) ])

但是,无论我如何尝试翻译它(显然我对Haskell一无所知),这对我来说毫无意义.这是因为我无法搜索那些符号的含义,我不知道该怎么做.虽然我知道在这些问题上寻求帮助有点蹩脚,但这是一个学校项目,我想我没有那么多时间来学习Haskell的基础知识.任何人都可以帮我找到真相(关于这个功能的作用/如何在我自己找到解决方案的想法等)?或者也许给我一些想法,让我自己创造一个新的好功能.

谢谢你的时间

(由OP编辑)

谢谢你太多了!这两个答案都非常详细和准确,我正在尝试根据提供的数据创建一个新功能,现在在这些帮助之后实现这一目标要容易得多!

另外,kobejohn,我将看看你提出的代码片段.非常感谢.

谢谢大家谢谢谢谢!

解决方法:

我知道你不想翻译,所以我在python中提供了一个大致相当的实现,使用python生成器和习语,试图说明基于惰性/流的结果生成的概念.

鉴于您正试图了解它是如何工作的,让我们分别看一下每个部分.我已经列出了使代码更易于理解的代码,并添加了类型签名,因此您可以了解这些部分如何组合在一起.您可以查找Learn You A Haskell For Great Good中使用的符号.

type Position = (Int, Int)
type Move = (Position, Position)

possibleMoves :: Position -> [Move]
possibleMoves gf = filter works $filter valid $allMoves
    where

        allMoves :: [Move]
        allMoves = concat [ [ ((i,j),(i+1,j))
                            , ((i,j),(i,j+1)) ]
                          | (i,j) <- range ((0,0),(9,9)) ]

        valid :: Move -> Bool
        valid (_,(i,j)) = i < 10 && j < 10

        works :: Move -> Bool
        works move@(i1,i2) = let gf' = flipStones gf move
                             in lookAround i1 gf' || lookAround i2 gf'

此函数首先使用列表推导生成所有可能移动的列表(绑定为allMoves). haskell中的语法与python的列表推导略有不同.由于haskell的惰性语义,这段代码最好被认为是一个返回所有可能移动流的生成器.

def allMoves():
    for i in range(0,9):
        for j in range(0,9):
            yield ((i,j),(i+1,j))
            yield ((i,j),(i,j+1))

然后有一个函数有效,它检查移动是否合法,并根据答案返回True / False.

def valid(move):
    return move[1][0] < 10 && move[1][2] < 10

最后,一个函数可以工作,它检查结果是否真的有用.

def works(move):
    # flipStones returns a new game_field that incorporates the move we're testing
    new_gf = flipStones(game_field, move)
    return lookAround(move[0], new_gf) || lookaround(move[1], new_gf)

最后,这些功能都链接在一起,以提供最终答案. $符号乍一看似乎令人困惑,但只是把它想象成一个管道运算符,管道值从右到左.它可以很容易地用括号替换.

possibleMoves gf = filter works $filter valid $allMoves
-- Is exactly equivalent to
possibleMoves gf = filter works ( filter valid ( allMoves ) )

where子句中的函数仅存在于possibleMoves的范围内.正如你在这里看到的,这很好地映射到python内部函数.

from itertools import ifilter

# possibleMoves takes
def possibleMoves(game_field):

    def allMoves():
        for i in range(0,9):
            for j in range(0,9):
                yeild ((i,j),(i+1,j))
                yield ((i,j),(i,j+1))

    def valid(move):
        return move[1][0] < 10 && move[1][3] < 10

    def works(move):
        # the gf in scope here is the gf passed to possibleMoves
        new_gf = flipStones(game_field, move)
        return lookAround(move[0], new_gf) && lookAround(move[1], new_gf)

    return ifilter(works, ifilter(valid, allMoves()))

接下来,我们看看lookAround.

lookAround :: Position -> Position -> Bool
lookAround (i,j) gf' = any ((>=3).length) $
    (groupBy combineable $[ gf' ! (i',j) | i' <- range (max 0 (i-2), min 9 (i+2)) ]) ++
    (groupBy combineable $[ gf' ! (i,j') | j' <- range (max 0 (j-2), min 9 (j+2)) ])

这是一个我只能假设正在搜索您的代码中相同的最小/最大值的函数.函数定义的左侧就像解构赋值一样. (anygroupby是python的标准)

from itertools import groupby

def lookAround(pos1, pos2):
    i, j = pos1[0], pos1[1]
    # look around 2 above/below, grouping into runs of colors, returns list of lists
    list1 = groupby([pos2[(i_, j)] for i_ in range(max(0,i-2), min(9,i+2))])
    # look around 2 left right, grouping into runs of colors, returns list of lists
    list2 = groupby([pos2[(i, j_)] for j_ in range(max(0,j-2), min(9,j+2))])
    # return true if there's a run of 3 or more colours in either direction
    return any(lambda l: len(l)>=3, list1 + list2)

我希望这可以帮助您了解正在发生的事情.这种实现速度的关键是使用延迟生成的列表(python中的生成器).这意味着一旦知道不需要结果就可以丢弃结果,或者导致无效的答案.这样做的结果是你只需要做实际需要的工作,缺点是在python中,你必须熟悉生成器(也称为协同程序)和面向流的编程.

祝你的任务顺利,我希望这能为你提供一些提高实施性能的想法.

标签:python,haskell
来源: https://codeday.me/bug/20190725/1531421.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有