V言語でライフゲームしてみた

# はじめに

構文の確認程度に書いてみた。
元はNimで書いたライフゲーム用の簡易モジュールをV言語で書き直しただけ。
https://github.com/jiro4989/gameoflife

# 開発環境

- V 0.1.11
- Linux Mint 19.1

# コード

```go
import time

const (
	dead = 0
	live = 1
)

fn get_neighbour_cells(board [][]int, x, y int) []int {
	mut result := []int
	for y2 := y-1; y2 <= y+1; y2++ {
		if y2 < 0 || board.len <= y2 {
			continue
		}
		for x2 := x-1; x2 <= x+1; x2++ {
			if x2 < 0 || board[y2].len <= x2 {
				continue
			}
			if x == x2 && y == y2 {
				continue
			}
			result << board[y2][x2]
		}
	}
	return result
}

fn is_reproduction(self, living_cell_count int) bool {
	if self != dead {
		return false
	}
	return living_cell_count == 3
}

fn is_generation(self, living_cell_count int) bool {
	if self != live {
		return false
	}
	return living_cell_count == 2 || living_cell_count == 3
}

fn is_underpopulation(self, living_cell_count int) bool {
	if self != live {
		return false
	}
	return living_cell_count <= 1
}

fn is_overpopulation(self, living_cell_count int) bool {
	if self != live {
		return false
	}
	return 4 <= living_cell_count
}

fn next_step(board [][]int) [][]int {
	// v0.1.11
	// この構文はまだ使えないみたい
	// mut new_board := [][]int

	// 今は多次元配列をこう定義する
	mut new_board := []array_int
	for y := 0; y < board.len; y++ {
		row := board[y]
		mut new_row := []int

		for x := 0; x < row.len; x++ {
			cell := row[x]
			nc := get_neighbour_cells(board, x, y)
			mut living_cell_count := 0
			for c in nc {
				if c == live {
					living_cell_count++
				}
			}

			if cell == dead {
				if is_reproduction(cell, living_cell_count) {
					new_row << live
				} else {
					new_row << dead
				}
				continue
			}

			if is_generation(cell, living_cell_count) {
				new_row << live
			} else if is_underpopulation(cell, living_cell_count) {
				new_row << dead
			} else if is_overpopulation(cell, living_cell_count) {
				new_row << dead
			}
		}

		new_board << new_row
	}

	return new_board
}

fn print_board(board [][]int) {
	for row in board {
		mut s := '|'
		for c in row {
			s += ' $c |'
		}
		println(s)
	}
}

//////////////////////////////////////////////////
//   メイン処理
//////////////////////////////////////////////////

mut board := [
	[dead, dead, dead, dead, dead],
	[dead, dead, dead, dead, dead],
	[dead, live, live, live, dead],
	[dead, dead, dead, dead, dead],
	[dead, dead, dead, dead, dead],
]

for {
	board = next_step(board)
	print_board(board)
	println('------------------------------')
	time.sleep(1)
}
```

# 実行方法

公式リポジトリからmakeしてPATH通して動かしました。

```bash
git clone https://github.com/vlang/v.git
cd v
make
sudo cp -p v /usr/local/bin

cd ..
v run gameoflife.v
```

# 感想

構文はGoととても似ているけれど要所要所が違う。
今回書いてみたコードだけでもこれだけ違うことに気づいた。

- 変数宣言が`mut 変数名 := 値`。mutつけないと値を変更できない。
- 配列の長さの取得が`array.len`
- 文字列リテラルにシングルクォートを使う
- 文字列内で変数展開ができる `$variable_name`
- 命名規則がlower_snake_case
- 値ループが`for value in elements`
- 関数宣言が`fn`
- 配列宣言にいきなり`[1, 2, 3]`と書ける
- 空配列の宣言が`mut array := []type_name`
- 配列の末尾要素追加が`array << item`

構文だけみたらGoより多少簡単に書けるように変更が入ってるのかな、くらい。
標準ライブラリを読んだ感じTODOも多いしコンパイラ自体にバグも多い。

始まったばかりですし今後どう変わっていくかに期待します。

ちなみに、ネストしたマルチラインコメントに対応してなかったので、バグ修正のPR投げたりしました。
https://github.com/vlang/v/pull/917
（公式ドキュメントではネストしたコメントOKとか書いてあったはずなのになぜ対応してなかったのか）