Saya baru-baru ini menerapkan untuk bersenang-senang Permainan Kehidupan Conway di Javascript (sebenarnya kopi tapi hal yang sama). Karena javascript dapat digunakan sebagai bahasa fungsional, saya mencoba untuk tetap menggunakan spektrum itu. Saya tidak senang dengan hasil saya. Saya seorang programmer OO yang cukup bagus dan solusi saya sama-sama-sama-sama tua. Singkatnya, pertanyaan panjang: apa gaya fungsional (pseudocode) untuk melakukannya?
Inilah Pseudocode untuk usaha saya:
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)
functional-programming
George Mauer
sumber
sumber
Jawaban:
Nah, beberapa ide. Saya bukan ahli FP, tapi ...
Sudah cukup jelas kita harus memiliki tipe
Board
yang mewakili kondisi permainan. Dasar dari implementasi harus merupakanevolve
fungsi dari tipeevolve :: Board -> Board
; artinya menghasilkanBoard
dari menerapkan aturan permainan ke aBoard
.Bagaimana seharusnya kita menerapkannya
evolve
? ABoard
mungkin harus berupa matriks nxm dariCell
s. Kita bisa mengimplementasikan fungsicellEvolve
tipecellEvolve :: Cell -> [Cell] -> Cell
yang diberi aCell
dan tetangganyaCell
menghitungCell
status pada iterasi berikutnya.Kita juga harus mengimplementasikan
getCellNeighbors
fungsi yang mengambilCell
tetangga dariBoard
. Saya tidak sepenuhnya yakin tentang tanda tangan dari metode ini; tergantung pada bagaimana Anda menerapkanCell
danBoard
Anda dapat memiliki misalnyagetCellNeighbors :: Board -> CoordElem -> CoordElem -> [Cell]
, yang diberikan Dewan dan dua koordinat (CoordElem
akan menjadi tipe yang digunakan untuk mengindeks posisi dalamBoard
), memberi Anda daftar panjang variabel tetangga (tidak semua sel di papan memiliki jumlah tetangga yang sama - sudut memiliki 3 tetangga, perbatasan 5 dan yang lainnya, 8).evolve
dengan demikian dapat diimplementasikan dengan menggabungkancellEvolve
dangetCellNeighbors
untuk semua sel di papan, sekali lagi implementasi yang tepat akan tergantung pada bagaimana Anda menerapkanBoard
danCell
, tetapi itu harus menjadi sesuatu seperti "untuk semua sel di papan saat ini, dapatkan tetangga mereka dan menggunakannya untuk menghitung sel yang sesuai papan baru '. Ini harus mungkin dilakukan dengan aplikasi generik dari fungsi-fungsi di seluruh papan menggunakan "peta di atas fungsi sel papan".Pikiran lain:
Anda harus benar-benar mengimplementasikan
cellEvolve
sehingga dibutuhkan sebagai parameter tipeGameRules
yang mengkodekan aturan permainan- katakanlah daftar tupel(State,[(State,NumberOfNeighbors)],State)
yang mengatakan untuk keadaan tertentu dan jumlah tetangga di setiap negara bagian, yang seharusnya menjadi keadaan di iterasi berikutnya .cellEvolve
Tanda tangan kemudian bisacellEvolve :: GameRules -> Cell -> [Cell] -> Cell
Ini secara logis akan membawa Anda untuk
evolve :: Board -> Board
berbelok keevolve :: GameRules -> Board -> Board
, sehingga Anda dapat menggunakanevolve
tidak berubah dengan berbedaGameRules
, tetapi Anda bisa melangkah lebih jauh dan membuatcellEvolve
pluggable sebagai gantinyaGameRules
.Bermain dengan
getCellNeighbors
Anda juga bisa membuatevolve
generik berkaitan denganBoard
topologi - Anda dapat memilikigetCellNeighbors
yang membungkus tepi papan, papan 3d, dll.sumber
Jika Anda menulis versi pemrograman fungsional Life, Anda harus mempelajari Algoritma Gosper. Ia menggunakan ide-ide dari pemrograman fungsional untuk mencapai triliunan generasi per detik di papan triliunan kotak di satu sisi. Kedengarannya mustahil saya tahu, tetapi itu sepenuhnya mungkin; Saya memiliki implementasi kecil yang menyenangkan di C # yang dengan mudah menangani papan persegi 2 ^ 64 kotak di samping.
Kuncinya adalah mengambil keuntungan dari kemiripan diri yang besar dari papan-papan Life di kedua waktu dan ruang. Dengan memoize keadaan masa depan bagian besar papan Anda dapat dengan cepat memajukan bagian besar sekaligus.
Saya sudah lama ingin blog pengantar pemula untuk Algoritma Gosper selama bertahun-tahun sekarang, tapi saya tidak pernah punya waktu. Jika saya akhirnya melakukannya, saya akan memposting tautan di sini.
Perhatikan bahwa Anda ingin mencari Algoritma Gosper untuk perhitungan Life , bukan Algoritma Gosper untuk menghitung jumlah hypergeometrik.
sumber
Kebetulan bagus, kami membahas masalah yang sebenarnya ini dalam kuliah Haskell kami hari ini. Pertama kali saya melihatnya tetapi di sini ada tautan ke kode sumber yang kami berikan:
http://pastebin.com/K3DCyKj3
sumber
Anda mungkin ingin melihat implementasinya di RosettaCode untuk mendapatkan inspirasi.
Misalnya ada versi Haskell dan OCaml fungsional yang membuat papan baru setiap belokan dengan menerapkan fungsi ke yang sebelumnya, sedangkan versi grafis OCaml menggunakan dua array dan memperbarui secara bergantian untuk kecepatan.
Beberapa implementasi menguraikan fungsi pembaruan papan menjadi fungsi untuk menghitung lingkungan, menerapkan aturan hidup dan iterasi di atas papan. Itu tampak seperti komponen yang berguna sebagai dasar desain fungsional. Coba ubah hanya papan, jaga yang lainnya sebagai fungsi murni.
sumber
Ini versi singkat murni fungsional di Clojure. Semua penghargaan diberikan kepada Christophe Grand yang menerbitkan ini di posting blognya: Permainan Kehidupan Conway
Gim kemudian dapat dimainkan dengan berulang kali menerapkan fungsi "langkah" ke sekumpulan sel, misalnya:
Kecerdasannya adalah bagian (sel tetangga mapcat) - yang dilakukan adalah membuat daftar delapan tetangga untuk masing-masing sel aktif dan menyatukan semuanya. Kemudian berapa kali setiap sel muncul dalam daftar ini dapat dihitung dengan (frekuensi ....) dan akhirnya yang memiliki jumlah frekuensi yang tepat berhasil sampai ke generasi berikutnya.
sumber