4

这是一个家庭作业,我真的在最后一点挣扎。我们正在用 Haskell 编写“Battleship”,除了一些关于函数式语言的一般性讲座之外,我们没有太多要讲的了。没有教科书等。我曾多次提到 LYAH,那里有好东西,但似乎没有针对这个特定问题的建议。

作为上下文,我将把我的整个 Battleship 代码放在上面,这样你就可以看到我稍后引用的定义。

--A
data Row = A | B | C | D | E | F | G | H | I | J deriving (Enum, Ord, Show, Bounded, Eq, Read)
data Column = One | Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten  deriving (Enum, Ord, Show, Bounded, Eq, Read)
--B
data Address = Address Row Column deriving (Show, Read, Eq)
--C
data Cell = Cell Address Bool deriving (Show, Read, Eq)
--D
data Ship = Ship [Cell] deriving (Show, Eq)
--E
data Ships = Ships [Ship] deriving (Show, Eq)
--F
toAddress r c = Address (toEnum r) (toEnum c)
--G
toRowColumn (Address aRow aColumn) = (fromEnum aRow, fromEnum aColumn)
--H
allAddressesA = [ Address row column | row <- [A .. J], column <- [One .. Ten]]
--I
allAddressesB = [toAddress row column | row <- [0 .. 9], column <- [0 .. 9]]
--J
targetShip (Ship ship) (Address row column)
  | Address == map (\list -> (head Address Bool)) s
--K
targetShips [(Ships)] toAddress //TODO
--L
isSunk Ship ship
  |ship [] = true
  |otherwise foldl 
--M
areSunk [(Ships)] //TODO

现在我也会发布具体的任务描述,所以我需要帮助的内容没有任何沟通错误:

(j) 编写一个函数 targetShip,它接受一个 Ship 和一个目标地址作为它的两个参数。如果船上有一个带有目标地址的单元格,则该单元格被标记为沉没。船的更新版本被退回。如果船是空的,则返回空船。(1 幅地图,116 个字符)

(k) 编写一个函数 targetShips,它接受一个 Ships 列表和一个目标地址作为它的两个参数。它试图击沉船舶列表中的每艘船。它返回更新船舶的列表。如果没有船只,则返回空列表。(1 幅地图,86 个字符)

(l) 编写一个函数 isSunk,它接受一个 Ship 作为其参数。如果船是空船,则返回真。否则,如果所有单元格都标记为下沉,则返回 true。(1折,78个字符)

(m) 编写一个接受 Ships 列表作为参数的函数 areSunk。如果没有船只,则返回 true。否则,如果所有船只都被标记为沉没,则返回 true。(1折,78个字符)

所以我在这里特别挣扎的是最后4个。我已经测试过的解决方案(A-I),它们工作得很好。

我们需要知道如何引用单元格值……地址和布尔值,对于初学者。

我们不能写更多的函数。

我会假设你会想要更多关于特定问题的解释,所以我会密切关注。任何关于从哪里开始解决最后四个问题的提示将不胜感激。提前谢谢你......我现在将回到我的文本编辑器并尝试解决这个问题。

4

2 回答 2

3

(j) 编写一个函数 targetShip,它接受一个 Ship 和一个目标地址作为它的两个参数。如果船上有一个带有目标地址的单元格,则该单元格被标记为沉没。船的更新版本被退回。如果船是空的,则返回空船。(1 幅地图,116 个字符)

函数targetShip,
参数Ship and a target address as its two parameters
产生Ship is returned

这些信息足以为您的函数写下类型注释。

targetShip :: Ship -> Address -> Ship
targetShip (Ship ship) (Address row column) 

If the ship is empty, the empty Ship is returned
并且船是一个列表,或者一个列表是一个空列表 [] 或者是一个带尾的头部,然后

targetShip :: Ship -> Address -> Ship
targetShip (Ship []) (Address row column) = Ship []
targetShip (Ship (x:xs)) (Address row column) = 

现在是困难的部分。
If the ship has a cell with the target address, that cell is marked sunk
一艘船是一个单元格列表,那么我需要为每个单元格(定义船舶)检查当前单元格的地址是否与函数参数提供的地址相同。
好的,让x我们的模式匹配出现的头部。

targetShip :: Ship -> Address -> Ship
targetShip (Ship []) (Address row column)     = Ship []
targetShip (Ship (x:xs)) (Address row column) = 
    if x ... 

OMG,我做不到,因为不允许使用辅助功能,我需要更多信息。我需要将 x 的结构出现在我的模式匹配中,就像这样,

targetShip (Ship ((Cell address bool):xs)) (Address row column) = 

OMG 再次,我不能做更多,好吧重做同样的事情,在我的模式匹配中更具表现力。

targetShip (Ship ((Cell (Address shipRow shipColumn) bool):xs)) (Address row column) = 

现在没关系,我可以做到。
我会让你完成它。

祝你好运

于 2013-05-03T21:53:56.670 回答
1

J:您必须退回一艘带有取决于地址的新清单的船。

targetShip (Ship oldCells) address = Ship newCells
  where newCells = ...
        f cell =

你如何找出新的细胞?该任务建议使用地图。所以你可以foldCells. 应该f怎么做?如果它得到一个与 targetShip 的参数具有相同地址的单元格,它应该返回一个具有相同地址但具有沉没状态的新单元格。否则它应该只返回作为参数给出的单元格。

K:应该很容易,一旦你开始瞄准目标。按照建议使用map

L 和 J:非常相似。任务建议使用折叠。您以前尝试过使用折叠吗?有两种基本类型,foldrfoldl,它们都通过一个函数来工作,该函数接受两个参数,一个累加器和一个当前元素,并使用给定的累加器将列表一次一个元素折叠到累加器中。让我向您展示一些 foldl 的实际应用示例。

foldl (\acc x -> acc + x) 0 [1,2,3] -> 6 -- starting accumulator of 0
foldl (+) 0 [1,2,3] -> 6 -- same thing as above
foldl (&&) True [True, True, True] -> True -- folding booleans
foldl (&&) True [True, False, True] -> False -- more boolean folding
foldl (&&) True [] -> True -- folding an empty list yields the initial accumulator
foldl (\acc x -> acc && (x > 5)) True [6,7,8] -> True -- complex folding function.

我希望你能看到最后一个函数,如何解决问题 L 和 J。否则,请查看匿名函数中的模式匹配并查看LYAH 中的折叠

于 2013-05-03T21:47:51.440 回答