Conway의 게임 게임을 구현하는 기능적 프로그래밍 방법은 무엇입니까?


12

나는 최근 자바 스크립트에서 실제로 Conway의 게임 게임을 실제로 구현 했습니다 (실제로 커피 스크립트이지만 동일한 것). 자바 스크립트를 기능적 언어로 사용할 수 있기 때문에 스펙트럼의 끝까지 머물려고했습니다. 나는 내 결과에 만족하지 않았다. 나는 상당히 좋은 OO 프로그래머이고 내 솔루션은 똑같은 늙었다. 그래서 긴 질문은 짧습니다 : (의사 코드) 기능적 스타일은 무엇입니까?

내 시도에 대한 의사 코드는 다음과 같습니다.

class Node
  update: (board) ->
    get number_of_alive_neighbors from board
    get this_is_alive from board
    if this_is_alive and number_of_alive_neighbors < 2 then die
    if this_is_alive and number_of_alive_neighbors > 3 then die
    if not this_is_alive and number_of_alive_neighbors == 3 then alive

class NodeLocations
  at: (x, y) -> return node value at x,y
  of: (node) -> return x,y of node

class Board
  getNeighbors: (node) -> 
   use node_locations to check 8 neighbors 
   around node and return count

nodes = for 1..100 new Node
state = new NodeState(nodes)
locations = new NodeLocations(nodes)
board = new Board(locations, state)

executeRound:
  state = clone state
  accumulated_changes = for n in nodes n.update(board)
  apply accumulated_changes to state
  board = new Board(locations, state)


@Oded 그것은 우울하게 내 머리 위에 있습니다. 나는 기본 개념을 인식하지만 간신히
조지 Mauer

머릿속으로 넘어 가서 ... 방금 전문 언어의 달인이 할 수있는 일에 대한 예를 게시했습니다. 그것은 우리 모두에게 영감이라고 부릅니다 :)
Oded

@GeorgeMauer "실제로 커피 스크립트지만 같은"이 슬픈 하루입니다
Raynos

답변:


11

글쎄, 몇 가지 아이디어. 저는 FP의 전문가는 아니지만 ...

Board게임 상태를 나타내는 유형 이 있어야합니다 . 구현의 기초는 evolve유형 의 함수 여야합니다 evolve :: Board -> Board. Board게임 규칙을에 적용하는 것을 의미합니다 Board.

어떻게 구현해야 evolve합니까? A BoardCells 의 nxm 행렬이어야합니다 . 주어진 a 와 그 이웃 s 가 다음 반복에서 상태를 계산하는 cellEvolve유형 의 함수 를 구현할 수 있습니다.cellEvolve :: Cell -> [Cell] -> CellCellCellCell

또한 에서 이웃 getCellNeighbors을 추출하는 함수를 구현해야 Cell합니다 Board. 이 방법의 서명을 완전히 확신하지는 못합니다. 당신은 구현 방법에 따라 Cell그리고 Board당신은 예를 들어 가질 수있다 getCellNeighbors :: Board -> CoordElem -> CoordElem -> [Cell](이사회와 두 개의 좌표를 주어진 CoordElemA의 인덱스 위치에 사용되는 형태가 될 것입니다 것은 Board) 당신에게 이웃 (보드에있는 모든 세포가이없는 가변 길이 목록을 제공 같은 수의 이웃-모서리에는 이웃 3 개, 국경 5, 다른 모든 사람 8)이 있습니다.

evolve따라서 결합에 의해 구현 될 수 cellEvolvegetCellNeighbors보드의 모든 셀에 대해 다시 정확한 구현은 구현 방법에 따라 달라집니다 Board하고 Cell있지만, 현재 보드에있는 모든 세포, 이웃을 얻고을 계산하는 데 사용할 "같은 것을해야한다 새로운 보드의 해당 셀 ' "보드상의 셀 함수 맵"을 사용하여 전체 보드에 해당 기능을 일반적으로 적용 할 수 있어야합니다.

다른 생각들:

  • 게임의 규칙을 인코딩 cellEvolve하는 형식 GameRules인 매개 변수로 (State,[(State,NumberOfNeighbors)],State)주어진 상태와 각 상태의 이웃 수를 나타내는 튜플 목록 ( 다음 반복의 상태 여야 함)을 실제로 구현 해야합니다. . cellEvolve의 서명은cellEvolve :: GameRules -> Cell -> [Cell] -> Cell

  • 이것은 논리적으로 evolve :: Board -> Board전환 하여 다른 것으로 변경하지 않고 evolve :: GameRules -> Board -> Board사용할 수 있지만 한 걸음 더 나아가 플러그 가능 하게 만들 수 있습니다.evolveGameRulescellEvolveGameRules

  • getCellNeighbors당신 과 함께 플레이 evolve하면 Board'의 토폴로지 와 관련하여 일반적으로 만들 수 있습니다- getCellNeighbors보드의 가장자리, 3d 보드 등을 감쌀 수 있습니다 .


9

함수형 프로그래밍 버전의 Life를 작성하는 경우 Gosper의 알고리즘에 대해 스스로 알아볼 수 있습니다. 그것은 함수형 프로그래밍의 아이디어를 사용 하여 한쪽에 수조 제곱의 보드에서 초당 수조 세대 를 달성 합니다. 그건 불가능하다고 들리지만, 완전히 가능합니다. C #에서는 측면에서 2 ^ 64 정사각형 보드를 쉽게 처리하는 멋진 작은 구현이 있습니다.

비결은 시간과 공간에서 라이프 보드의 방대한 자립성을 활용하는 것입니다. 보드의 큰 섹션의 미래 상태를 기억함으로써 한 번에 큰 섹션을 빠르게 발전시킬 수 있습니다.

나는 수년 동안 Gosper 's Algorithm에 대한 초보자 소개 블로그를 작성하는 것을 의미했지만 시간이 없었습니다. 내가 그렇게하면 여기에 링크를 게시 할 것입니다.

하이퍼 지오메트리 합계를 계산하기위한 Gosper의 알고리즘이 아니라 Lifes 계산을위한 Gosper의 알고리즘 을 찾으려고합니다 .


흥미롭게 보인다 – 아직도 그 링크를 기다리고있다. ..
jk.

3

우연의 일치, 오늘 우리는 Haskell 강의에서이 정확한 문제를 다루었습니다. 처음 보았지만 여기에 제공된 소스 코드에 대한 링크가 있습니다.

http://pastebin.com/K3DCyKj3


무엇을하는지 더 자세히 설명해 주시겠습니까? 그리고 질문에 대한 답변으로 추천하는 이유는 무엇입니까? "링크 전용 답변" 은 Stack Exchange에서 환영받지 못합니다
gnat

3

영감 을 얻기 위해 RosettaCode 의 구현을 살펴볼 수 있습니다 .

예를 들어, 기능적인 Haskell 및 OCaml 버전이 있습니다. 이전 버전에 기능을 적용하여 매번 새로운 보드를 생성하는 반면 그래픽 OCaml 버전은 두 개의 어레이를 사용하고 속도를 위해 교대로 업데이트합니다.

구현의 일부는 보드 분해 업데이트 에 대한 함수로 함수를 계산 , 이웃을 적용 삶의 규칙반복 보드를 통해. 그것들은 기능적 디자인을 기반으로하는 유용한 구성 요소처럼 보입니다. 보드 만 수정하고 다른 모든 것은 순수한 기능으로 유지하십시오.


1

Clojure의 순전히 기능적인 짧은 버전입니다. 모든 크레딧은 그의 블로그 포스트 : Conway 's Game of Life에 이것을 게시 한 Christophe Grand에게갑니다.

(defn neighbours [[x y]]
  (for [dx [-1 0 1] 
        dy (if (zero? dx) [-1 1] [-1 0 1])]
    [(+ dx x) (+ dy y)]))

(defn step [cells]
  (set (for [[loc n] (frequencies (mapcat neighbours cells))
             :when (or (= n 3) (and (= n 2) (cells loc)))]
         loc)))

그런 다음 "step"기능을 일련의 셀에 반복적으로 적용하여 게임을 재생할 수 있습니다. 예 :

(step #{[1 0] [1 1] [1 2]})
=> #{[2 1] [1 1] [0 1]}

영리함은 (mapcat neighbours cells) 부분입니다. 이것이하는 것은 각 활성 셀에 대해 8 개의 이웃 목록을 작성하고이를 모두 연결하는 것입니다. 그런 다음이 목록에 각 셀이 나타나는 횟수는 (주파수 ....)로 계산할 수 있으며 마지막으로 올바른 주파수 카운트를 가진 셀은 다음 세대로 넘어갑니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.