我正在尝试用金字塔重建一个谜语:
金字塔的最后一层是数字从1到n的排列,其中n是字段数。然后,不在最低层中的所有其他字段都是该数字对角线下方数字的总和。
所以我想做一个函数,当给定左边的谜语时,返回右边的解。我打算通过枚举这样的层来做到这一点:
对于图层,我创建了一个自定义数据类型:
data Layer = One | Two | Three | Four | Five | Six
deriving (Eq,Ord,Enum,Show)
和其他类型:
type LayerDepth = Layer
type FieldNumber = Int
type FieldContent = Int
type FieldAssignment = (FieldNumber -> FieldContent)
type PyramidRiddle = FieldAssignment
type PyramidSolution = FieldAssignment
type PyramidSolutions = [PyramidSolution]
和功能:
solveRiddle :: LayerDepth -> PyramidRiddle -> Pyramidsolutions
对于所示示例,我将创建类型为(FieldNumber-> FieldContent)的匿名函数:
fieldAssignment1 = \n -> if (n==6) || n==8) then 3 else 0
此功能将用数字3标记第六和第八字段
然后调用:
solveRiddle Four fieldAssignment1 ->> [pyramidSolution1, pyramidSolution2]
四层代表四层,而PyramidSolutions是FieldAssignments列表,具有谜题的解决方案
我的问题:
我将需要以某种方式返回一个函数,该函数将给定字段分配以计算最后一层的排列,并根据该分配将数字分配给其余字段。
这样:
pyramidSolution1 = \n -> case n of 1 -> 18
2 -> 11
3 -> 7
4 -> 7
5 -> 4
6 -> 3
7 -> 4
8 -> 3
9 -> 1
10 -> 2
_ -> 0
和
pyramidSolution2 = \n -> case n of 1 -> 20
2 -> 12
3 -> 8
4 -> 7
5 -> 5
6 -> 3
7 -> 4
8 -> 3
9 -> 2
10 -> 1
_ -> 0
但是最好的方法是什么?
我该如何分配数字的排列,并知道如何将它们排列为数字等于下面的数字之和?
在上面的代码中实现匿名函数pyramidSolution1和pyramidSolution2的最佳方法是什么?
答案 0 :(得分:8)
我会简化一下。一层是数字列表:
type Layer = [Int]
-- e.g. [4,3,1,2]
规则是对某些元素的固定分配的列表。
data Must = Any | Only Int -- Yes, it's just Maybe with different labels
type Rule = [Must]
-- e.g. [Any,Only 3,Any,Any]
您需要一个可以从其下一层生成图层的函数:
nextLayer :: Layer -> Layer
nextLayer = undefined
-- nextLayer [4,3,1,2] == [7,4,3]
和用于根据有效规则检查图层的功能
isLayerValid :: Rule -> Layer -> Bool
isLayerValid = undefined
-- isLayerValid [Any,Any,Only 3] [1,2,3] == True
-- isLayerValid [Any,Any,Only 3] [1,3,2] == False
一个谜语只是规则列表:
type Riddle = [Rule]
riddle :: Riddle
riddle = [[Any, Only 3, Any, Any], [Any, Any, Only 3], [Any, Any], [Any]]
一个解决方案是从某个基础开始的层列表。
type Pyramid = [Layer]
pyramid :: Layer -> Pyramid
pyramid [] = []
pyramid base = base : pyramid (nextLayer base)
-- pyramid [4,3,1,2] == [[4,3,1,2],[7,4,3],[11,7],[18]]
正确解决方案是针对给定谜语进行验证的解决方案:
isValidFor :: Riddle -> Pyramid -> Bool
isValidFor [] [] = True
isValidFor (r:rs) (x:xs) = isLayerValid r x && isValidFor rs xs
-- isValidFor riddle (pyramid [4,3,1,2]) == True
-- isValidFor riddle (pyramid [1,3,4,2]) == False
现在的诀窍是生成所有潜在的解决方案
permutations :: [Int] -> [[Int]]
permutations ns = undefined
-- e.g. allSolutions = map pyramid (permutations [1..n])
并使用解决方案测试对其进行过滤:
solutions :: Riddle -> [Pyramid]
solutions r = filter (isValidFor r) (map pyramid (permutations [1..length r]))
-- solutions riddle == [pyramid [4,3,1,2], pyramid [4,3,2,1]]