2

コーディングの課題の一環として、ダンジョン マップを実装する必要があります。

Data.Mapマップを印刷する必要がなく、障害物が破壊されたときなどにマップ タイルを更新する必要があったため、デザインの選択肢として使用して既にデザインしました。

type Dungeon = Map Pos Tile

type Pos = (Int,Int) -- cartesian coordinates
data Tile = Wall | Destroyable | ...

しかし、それも印刷しなければならない場合はどうすればよいでしょうか 。その場合elaboratePrint . sort $ fromList dungeon、whereelaboratePrintが改行を処理し、タイルセットから素敵な Unicode シンボルを作成するようなものを使用する必要があります。

私が検討した別の選択肢は、ネストされたリストです

type Dungeon = [[Tile]]

これには、そのようなデータ構造の単一の要素を更新するのが難しいという欠点があります。しかし、その場合、印刷は単純なワンライナーになりunlines . map showます。

私が検討した別の構造は でしArrayたが、私は配列に慣れていないので、ハック ドキュメントを一目見ただけでわかりました - インデックスを操作するマップ関数と要素を操作するマップ関数しか見つかりませんでした。要素は一見簡単ではありません。また、配列の印刷も、それを迅速かつ簡単に行う方法が明確ではありません。

さて、私の質問は、簡単に印刷でき、単一要素を簡単に更新できるという特性を持つ、ダンジョン マップを表現するためのより優れたデータ構造があるかどうかです。

4

2 に答える 2

4

はどうArrayですか?Haskell には実数の 2 次元配列があります。

import Data.Array.IArray -- Immutable Arrays

現在、Arrayは any によって索引付けされていますIx a => a。幸いなことに、インスタンスがあります(Ix a, Ix b) => Ix (a, b)。だから私たちは持つことができます

 type Dungeon = Array (Integer, Integer) Tile

ここで、いくつかの関数のいずれかでこれらの 1 つを作成します。最も簡単に使用できるのは次のとおりです。

array :: Ix i => (i, i) -> [(i, a)] -> Array i a

だからあなたのために、

startDungeon = array ( (0, 0), (100, 100) )
              [ ( (x, y), Empty ) | x <- [0..100], y <- [0..100]]

そして、適切な値を100andに置き換えるだけです。Empty

速度が問題になる場合は、MArrayとを使用するのが簡単な修正STです。ここで速度が実際に問題になる場合を除き、切り替えないことをお勧めします。

きれいな印刷に対処するには

import Data.List
import Data.Function

pretty :: Array (Integer, Integer) Tile -> String
pretty = unlines . map show . groupBy ((==) `on` snd.fst) . assoc

そして、あなたが行map showにフォーマットしたいように変えることができます[Tile]。これらを本当に素晴らしく効率的な方法で印刷したいと決めた場合 (おそらくコンソール ゲーム)、このような適切なきれいな印刷ライブラリを検討する必要があります。

于 2013-10-20T20:09:10.050 に答える
3

Data.Mapまず、や リストなどのツリーのようなものは、関数型言語の自然なデータ構造のままです。Map長方形のマップのみが必要な場合、構造的には少しやり過ぎですが、[[Tile]]実際にはかなり問題ない場合があります。ランダムアクセスと更新の両方がO(√n)あり、それほど悪くはありません.

特に、 2D 配列 ( )の純粋関数更新よりも優れてO(n)います。したがって、本当に優れたパフォーマンスが必要な場合は、変更可能な配列を使用する方法はありませ。ただし、これは必ずしも悪いことではありません。結局のところ、ゲームは本質的に IO と状態に関係しています。jozefg指摘したように、 の優れてData.Arrayいる点は、タプルをIxインデックスとして使用できることMArrayです。

配列を使用すると、印刷が簡単です。おそらくマップ全体の長方形の部分だけが必要なので、単純なリスト内包表記でそのようなスライスを抽出するだけです

[ [ arrayMap ! (x,y) | x<-[21..38] ] | y<-[37..47] ]

リストを印刷する方法はすでに知っています。

于 2013-10-20T20:11:51.960 に答える