feen 4.0.2 → 5.0.0.beta0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.md +2 -2
- data/README.md +56 -24
- data/lib/feen/dumper/{square.rb → piece_placement.rb} +8 -8
- data/lib/feen/dumper/{in_hand.rb → pieces_in_hand.rb} +9 -8
- data/lib/feen/dumper.rb +20 -19
- data/lib/feen/parser/{shape.rb → board_shape.rb} +8 -8
- data/lib/feen/parser/{square.rb → piece_placement.rb} +10 -10
- data/lib/feen/parser/{in_hand.rb → pieces_in_hand.rb} +14 -7
- data/lib/feen/parser.rb +14 -15
- data/lib/feen.rb +21 -21
- metadata +17 -161
- data/lib/feen/dumper/turn.rb +0 -18
- data/lib/feen/parser/turn.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53d90951a531e63bc118104956d29e7c71c90075ab4d42d57506ec5197a783cb
|
4
|
+
data.tar.gz: 2cbf73113cc4a429420c3c4e0f30c448380a397bf39f264e617fa85119193f7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3919811f24c5ad1f82dfd257eeefe3515efbcb6fd433a1feb20597e4c6a0fbe6a24c33bef56ea7f612e87fac3124b6334b261c1e987a02f7ecf43a6da745f950
|
7
|
+
data.tar.gz: 7b16a8ecd4d80444d1ee14477be61906f3c9503f0a05083dc191822d8a663a6a4fee379c6b0d40fd9bec509c98f0ae863282e1512a6035b7f0624279cb774da0
|
data/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
The MIT License
|
1
|
+
# The MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2020-
|
3
|
+
Copyright (c) 2020-2023 Sashité
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Feen.rb
|
2
2
|
|
3
3
|
[![Version](https://img.shields.io/github/v/tag/sashite/feen.rb?label=Version&logo=github)](https://github.com/sashite/feen.rb/releases)
|
4
4
|
[![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/sashite/feen.rb/main)
|
@@ -6,69 +6,101 @@
|
|
6
6
|
[![RuboCop](https://github.com/sashite/feen.rb/workflows/RuboCop/badge.svg?branch=main)](https://github.com/sashite/feen.rb/actions?query=workflow%3Arubocop+branch%3Amain)
|
7
7
|
[![License](https://img.shields.io/github/license/sashite/feen.rb?label=License&logo=github)](https://github.com/sashite/feen.rb/raw/main/LICENSE.md)
|
8
8
|
|
9
|
-
> __FEEN__ (
|
9
|
+
> __FEEN__ (FEN Easy Extensible Notation) support for the Ruby language.
|
10
10
|
|
11
11
|
## Overview
|
12
12
|
|
13
|
-
This is an implementation of [FEEN](https://developer.sashite.com/specs/
|
13
|
+
This is an implementation of [FEEN](https://developer.sashite.com/specs/fen-easy-extensible-notation), a generic format that can be used for serializing and deserializing positions.
|
14
14
|
|
15
|
-
|
15
|
+
A __FEEN__ string consists of a single line of ASCII text containing three data fields, separated by a space. These are:
|
16
16
|
|
17
|
-
|
17
|
+
1. Piece placement
|
18
|
+
2. Side to move
|
19
|
+
3. Pieces in hand
|
18
20
|
|
19
|
-
|
21
|
+
The main chess variants may be supported, including [Chess](https://en.wikipedia.org/wiki/Chess), [Janggi](https://en.wikipedia.org/wiki/Janggi), [Makruk](https://en.wikipedia.org/wiki/Makruk), [Shogi](https://en.wikipedia.org/wiki/Shogi), [Xiangqi](https://en.wikipedia.org/wiki/Xiangqi).
|
22
|
+
|
23
|
+
More exotic variants may be also supported, like: [Dai dai shogi](https://en.wikipedia.org/wiki/Dai_dai_shogi), [Four-player chess](https://en.wikipedia.org/wiki/Four-player_chess), or [Three-dimensional chess](https://en.wikipedia.org/wiki/Three-dimensional_chess) 🖖
|
24
|
+
|
25
|
+
![3D chess on Star Trek (from the episode "Court Martial")](https://github.com/sashite/feen.rb/raw/main/star-trek-chess.jpg)
|
20
26
|
|
21
27
|
## Installation
|
22
28
|
|
23
29
|
Add this line to your application's Gemfile:
|
24
30
|
|
25
31
|
```ruby
|
26
|
-
gem "feen"
|
32
|
+
gem "feen", ">= 5.0.0.beta0"
|
27
33
|
```
|
28
34
|
|
29
35
|
And then execute:
|
30
36
|
|
31
37
|
```sh
|
32
|
-
bundle
|
38
|
+
bundle install
|
33
39
|
```
|
34
40
|
|
35
41
|
Or install it yourself as:
|
36
42
|
|
37
43
|
```sh
|
38
|
-
gem install feen
|
44
|
+
gem install feen --pre
|
39
45
|
```
|
40
46
|
|
41
47
|
## Usage
|
42
48
|
|
49
|
+
### Serialization
|
50
|
+
|
51
|
+
A position can be serialized by filling in these fields:
|
52
|
+
|
53
|
+
- **Piece placement**: Describes the placement of pieces on the board with a hash that references each piece on the board. The keys could be numbers, or strings of characters representing coordinates.
|
54
|
+
- **Side to move**: A char that indicates who moves next. In chess, "`w`" would mean that White must move, and "`b`" that Black must move. In Shogi, "`s`" could mean that Sente must move, and "`g`" that Gote must move. In Xiangqi, "`r`" could mean that Red must move, and "`b`" that Black must move.
|
55
|
+
- **Pieces in hand**: An array of all captured pieces that remain _in hand_, like in Shogi.
|
56
|
+
- **Board shape**: An array of integers. For instance, it would be `[10, 9]` in Xiangqi. And it would be `[8, 8]` in Chess.
|
57
|
+
|
58
|
+
#### Examples
|
59
|
+
|
60
|
+
##### A classic Tsume Shogi problem
|
61
|
+
|
43
62
|
```ruby
|
44
63
|
require "feen"
|
45
64
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
5 => "s",
|
65
|
+
Feen.dump(
|
66
|
+
side_to_move: "s",
|
67
|
+
pieces_in_hand: %w[S r r b g g g g s n n n n p p p p p p p p p p p p p p p p p],
|
68
|
+
board_shape: [9, 9],
|
69
|
+
piece_placement: {
|
70
|
+
3 => "s",
|
71
|
+
4 => "k",
|
72
|
+
5 => "s",
|
55
73
|
22 => "+P",
|
56
74
|
43 => "+B"
|
57
75
|
}
|
58
76
|
)
|
59
|
-
# => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9
|
77
|
+
# => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 s S,b,g*4,n*4,p*17,r*2,s"
|
78
|
+
```
|
79
|
+
|
80
|
+
### Deserialization
|
81
|
+
|
82
|
+
Serialized positions can be converted back to fields.
|
83
|
+
|
84
|
+
#### Examples
|
85
|
+
|
86
|
+
##### A classic Tsume Shogi problem
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
require "feen"
|
60
90
|
|
61
|
-
|
62
|
-
|
63
|
-
#
|
91
|
+
Feen.parse("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 s S,b,g*4,n*4,p*17,r*2,s")
|
92
|
+
# {:board_shape=>[9, 9],
|
93
|
+
# :pieces_in_hand=>["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
|
94
|
+
# :piece_placement=>{3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"},
|
95
|
+
# :side_to_move=>"s"}
|
64
96
|
```
|
65
97
|
|
66
98
|
## License
|
67
99
|
|
68
100
|
The code is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
69
101
|
|
70
|
-
## About
|
102
|
+
## About Sashité
|
71
103
|
|
72
|
-
This [gem](https://rubygems.org/gems/feen) is maintained by [
|
104
|
+
This [gem](https://rubygems.org/gems/feen) is maintained by [Sashité](https://sashite.com/).
|
73
105
|
|
74
106
|
With some [lines of code](https://github.com/sashite/), let's share the beauty of Chinese, Japanese and Western cultures through the game of chess!
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Feen
|
4
4
|
module Dumper
|
5
|
-
# The
|
5
|
+
# The PiecePlacement class.
|
6
6
|
#
|
7
7
|
# @example Dump an empty board of Xiangqi
|
8
|
-
#
|
8
|
+
# PiecePlacement.new([10, 9]).to_s # => "9/9/9/9/9/9/9/9/9/9"
|
9
9
|
#
|
10
10
|
# @example Dump the Xiangqi starting position board
|
11
|
-
#
|
11
|
+
# PiecePlacement.new(
|
12
12
|
# [10, 9],
|
13
13
|
# {
|
14
14
|
# 0 => "車",
|
@@ -45,12 +45,12 @@ module FEEN
|
|
45
45
|
# 89 => "俥"
|
46
46
|
# }
|
47
47
|
# ).to_s # => "車,馬,象,士,將,士,象,馬,車/9/1,砲,5,砲,1/卒,1,卒,1,卒,1,卒,1,卒/9/9/兵,1,兵,1,兵,1,兵,1,兵/1,炮,5,炮,1/9/俥,傌,相,仕,帥,仕,相,傌,俥"
|
48
|
-
class
|
48
|
+
class PiecePlacement
|
49
49
|
# @param indexes [Array] The shape of the board.
|
50
|
-
# @param
|
51
|
-
def initialize(indexes,
|
50
|
+
# @param piece_placement [Hash] The index of each piece on the board.
|
51
|
+
def initialize(indexes, piece_placement = {})
|
52
52
|
@indexes = indexes
|
53
|
-
@squares = Array.new(length) { |i|
|
53
|
+
@squares = ::Array.new(length) { |i| piece_placement.fetch(i, nil) }
|
54
54
|
end
|
55
55
|
|
56
56
|
# @return [String] The string representing the board.
|
@@ -1,26 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Feen
|
4
4
|
module Dumper
|
5
|
-
#
|
6
|
-
module
|
5
|
+
# A module that serializes pieces in hand lists into a string.
|
6
|
+
module PiecesInHand
|
7
7
|
# Serialize pieces in hand lists into a string.
|
8
8
|
#
|
9
9
|
# @param piece_names [Array] A list of pieces in hand.
|
10
10
|
#
|
11
11
|
# @example Dump a list of pieces in hand
|
12
12
|
# dump(["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"])
|
13
|
-
# # => "S,b,g,
|
13
|
+
# # => "S,b,g*4,n*4,p*17,r*2,s"
|
14
14
|
#
|
15
15
|
# @example Dump an empty list of pieces in hand
|
16
16
|
# dump([])
|
17
|
-
# # =>
|
17
|
+
# # => nil
|
18
18
|
#
|
19
|
-
# @return [String] A
|
19
|
+
# @return [String, nil] A serialized list of pieces in hand.
|
20
20
|
def self.dump(piece_names)
|
21
|
-
return
|
21
|
+
return if piece_names.empty?
|
22
22
|
|
23
|
-
piece_names.
|
23
|
+
hash = piece_names.group_by(&:itself).transform_values(&:count)
|
24
|
+
hash.map { |k, v| v > 1 ? "#{k}*#{v}" : k }.sort.join(",")
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
data/lib/feen/dumper.rb
CHANGED
@@ -1,25 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative File.join("dumper", "
|
4
|
-
require_relative File.join("dumper", "
|
5
|
-
require_relative File.join("dumper", "turn")
|
3
|
+
require_relative File.join("dumper", "piece_placement")
|
4
|
+
require_relative File.join("dumper", "pieces_in_hand")
|
6
5
|
|
7
|
-
module
|
6
|
+
module Feen
|
8
7
|
# The dumper module.
|
9
8
|
module Dumper
|
10
9
|
# Dump position params into a FEEN string.
|
11
10
|
#
|
12
|
-
# @param
|
13
|
-
# @param
|
14
|
-
# @param
|
15
|
-
# @param
|
11
|
+
# @param side_to_move [String] Identify the active side.
|
12
|
+
# @param pieces_in_hand [Array, nil] The list of pieces in hand.
|
13
|
+
# @param board_shape [Array] The shape of the board.
|
14
|
+
# @param piece_placement [Hash] The index of each piece on the board.
|
16
15
|
#
|
17
16
|
# @example Dump a classic Tsume Shogi problem
|
18
17
|
# call(
|
19
|
-
# "
|
20
|
-
# "
|
21
|
-
# "
|
22
|
-
# "
|
18
|
+
# "side_to_move": "s",
|
19
|
+
# "pieces_in_hand": %w[S r r b g g g g s n n n n p p p p p p p p p p p p p p p p p],
|
20
|
+
# "board_shape": [9, 9],
|
21
|
+
# "piece_placement": {
|
23
22
|
# 3 => "s",
|
24
23
|
# 4 => "k",
|
25
24
|
# 5 => "s",
|
@@ -27,15 +26,17 @@ module FEEN
|
|
27
26
|
# 43 => "+B"
|
28
27
|
# }
|
29
28
|
# )
|
30
|
-
# # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9
|
29
|
+
# # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 s S,b,g*4,n*4,p*17,r*2,s"
|
31
30
|
#
|
32
31
|
# @return [String] The FEEN string representing the position.
|
33
|
-
def self.call(
|
34
|
-
[
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
def self.call(board_shape:, side_to_move:, piece_placement:, pieces_in_hand: nil)
|
33
|
+
array = [
|
34
|
+
PiecePlacement.new(board_shape, piece_placement).to_s,
|
35
|
+
side_to_move
|
36
|
+
]
|
37
|
+
|
38
|
+
array << PiecesInHand.dump(pieces_in_hand) if Array(pieces_in_hand).any?
|
39
|
+
array.join(" ")
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Feen
|
4
4
|
module Parser
|
5
|
-
# The
|
5
|
+
# The BoardShape class.
|
6
6
|
#
|
7
7
|
# @example Parse the shape of a shogiban
|
8
|
-
#
|
9
|
-
class
|
10
|
-
# @param
|
11
|
-
def initialize(
|
12
|
-
@
|
8
|
+
# BoardShape.new("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9").to_a # => [9, 9]
|
9
|
+
class BoardShape
|
10
|
+
# @param board_str [String] The flatten board.
|
11
|
+
def initialize(board_str)
|
12
|
+
@board_str = board_str
|
13
13
|
end
|
14
14
|
|
15
15
|
# @return [Array] The size of each dimension of the board.
|
16
16
|
def to_a
|
17
|
-
indexes(@
|
17
|
+
indexes(@board_str, @board_str.scan(%r{/+}).sort.fetch(-1))
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Feen
|
4
4
|
module Parser
|
5
|
-
# The
|
5
|
+
# The PiecePlacement class.
|
6
6
|
#
|
7
7
|
# @example Parse a Shogi problem board and return an array
|
8
|
-
#
|
8
|
+
# PiecePlacement.new("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9").to_a
|
9
9
|
# # => [
|
10
10
|
# # nil, nil, nil, "s", "k", "s", nil, nil, nil,
|
11
11
|
# # nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
@@ -19,7 +19,7 @@ module FEEN
|
|
19
19
|
# # ]
|
20
20
|
#
|
21
21
|
# @example Parse a Shogi problem board and return a hash
|
22
|
-
#
|
22
|
+
# PiecePlacement.new("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9").to_h
|
23
23
|
# # => {
|
24
24
|
# # 3 => "s",
|
25
25
|
# # 4 => "k",
|
@@ -27,15 +27,15 @@ module FEEN
|
|
27
27
|
# # 22 => "+P",
|
28
28
|
# # 43 => "+B"
|
29
29
|
# # }
|
30
|
-
class
|
31
|
-
# @param
|
32
|
-
def initialize(
|
33
|
-
@
|
30
|
+
class PiecePlacement
|
31
|
+
# @param piece_placement_str [String] The placement of pieces on the board.
|
32
|
+
def initialize(piece_placement_str)
|
33
|
+
@piece_placement_str = piece_placement_str
|
34
34
|
end
|
35
35
|
|
36
|
-
# @return [Array] The list of
|
36
|
+
# @return [Array] The list of pieces on the board.
|
37
37
|
def to_a
|
38
|
-
@
|
38
|
+
@piece_placement_str
|
39
39
|
.split(%r{[/,]+})
|
40
40
|
.flat_map { |str| row(str) }
|
41
41
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Feen
|
4
4
|
module Parser
|
5
5
|
# The pieces in hand module.
|
6
|
-
module
|
6
|
+
module PiecesInHand
|
7
7
|
# The list of pieces in hand grouped by players.
|
8
8
|
#
|
9
|
-
# @param
|
9
|
+
# @param pieces_in_hand [String, nil] The serialized list of pieces in hand.
|
10
10
|
#
|
11
11
|
# @example Parse a list of serialized pieces in hand
|
12
|
-
# parse("S,b,g,
|
12
|
+
# parse("S,b,g*4,n*4,p*17,r*2,s")
|
13
13
|
# # => ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"]
|
14
14
|
#
|
15
15
|
# @example Parse an empty list of serialized pieces in hand
|
@@ -17,10 +17,17 @@ module FEEN
|
|
17
17
|
# # => []
|
18
18
|
#
|
19
19
|
# @return [Array] The list of pieces in hand grouped by players.
|
20
|
-
def self.parse(
|
21
|
-
return
|
20
|
+
def self.parse(pieces_in_hand)
|
21
|
+
return if pieces_in_hand.nil?
|
22
22
|
|
23
|
-
|
23
|
+
pieces_in_hand.split(",").flat_map do |piece|
|
24
|
+
if piece.include?("*")
|
25
|
+
letter, count = piece.split("*")
|
26
|
+
[letter] * count.to_i
|
27
|
+
else
|
28
|
+
piece
|
29
|
+
end
|
30
|
+
end.sort
|
24
31
|
end
|
25
32
|
end
|
26
33
|
end
|
data/lib/feen/parser.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative File.join("parser", "
|
4
|
-
require_relative File.join("parser", "
|
5
|
-
require_relative File.join("parser", "
|
6
|
-
require_relative File.join("parser", "turn")
|
3
|
+
require_relative File.join("parser", "board_shape")
|
4
|
+
require_relative File.join("parser", "pieces_in_hand")
|
5
|
+
require_relative File.join("parser", "piece_placement")
|
7
6
|
|
8
|
-
module
|
7
|
+
module Feen
|
9
8
|
# The parser module.
|
10
9
|
module Parser
|
11
10
|
# Parse a FEEN string into position params.
|
@@ -13,12 +12,12 @@ module FEEN
|
|
13
12
|
# @param feen [String] The FEEN string representing a position.
|
14
13
|
#
|
15
14
|
# @example Parse a classic Tsume Shogi problem
|
16
|
-
# call("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9
|
15
|
+
# call("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 s S,b,g*4,n*4,p*17,r*2,s")
|
17
16
|
# # => {
|
18
|
-
# # "
|
19
|
-
# # "
|
20
|
-
# # "
|
21
|
-
# # "
|
17
|
+
# # "side_to_move": "s",
|
18
|
+
# # "pieces_in_hand": ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
|
19
|
+
# # "board_shape": [9, 9],
|
20
|
+
# # "piece_placement": {
|
22
21
|
# # 3 => "s",
|
23
22
|
# # 4 => "k",
|
24
23
|
# # 5 => "s",
|
@@ -28,13 +27,13 @@ module FEEN
|
|
28
27
|
#
|
29
28
|
# @return [Hash] The position params representing the position.
|
30
29
|
def self.call(feen)
|
31
|
-
|
30
|
+
piece_placement, side_to_move, pieces_in_hand = feen.split
|
32
31
|
|
33
32
|
{
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
board_shape: BoardShape.new(piece_placement).to_a,
|
34
|
+
pieces_in_hand: PiecesInHand.parse(pieces_in_hand),
|
35
|
+
piece_placement: PiecePlacement.new(piece_placement).to_h,
|
36
|
+
side_to_move:
|
38
37
|
}
|
39
38
|
end
|
40
39
|
end
|
data/lib/feen.rb
CHANGED
@@ -6,21 +6,21 @@ require_relative File.join("feen", "parser")
|
|
6
6
|
# This module provides a Ruby interface for data serialization and
|
7
7
|
# deserialization in FEEN format.
|
8
8
|
#
|
9
|
-
# @see https://developer.sashite.com/specs/
|
10
|
-
module
|
9
|
+
# @see https://developer.sashite.com/specs/fen-easy-extensible-notation
|
10
|
+
module Feen
|
11
11
|
# Dumps position params into a FEEN string.
|
12
12
|
#
|
13
|
-
# @param
|
14
|
-
# @param
|
15
|
-
# @param
|
16
|
-
# @param
|
13
|
+
# @param pieces_in_hand [Array, nil] The list of pieces in hand.
|
14
|
+
# @param board_shape [Array] The shape of the board.
|
15
|
+
# @param side_to_move [String] The identifier of the player who must play.
|
16
|
+
# @param piece_placement [Hash] The index of each piece on the board.
|
17
17
|
#
|
18
18
|
# @example Dump a classic Tsume Shogi problem
|
19
19
|
# dump(
|
20
|
-
# "
|
21
|
-
# "
|
22
|
-
# "
|
23
|
-
# "
|
20
|
+
# "side_to_move": "s",
|
21
|
+
# "pieces_in_hand": %w[S r r b g g g g s n n n n p p p p p p p p p p p p p p p p p],
|
22
|
+
# "board_shape": [9, 9],
|
23
|
+
# "piece_placement": {
|
24
24
|
# 3 => "s",
|
25
25
|
# 4 => "k",
|
26
26
|
# 5 => "s",
|
@@ -28,15 +28,15 @@ module FEEN
|
|
28
28
|
# 43 => "+B"
|
29
29
|
# }
|
30
30
|
# )
|
31
|
-
# # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9
|
31
|
+
# # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 s S,b,g*4,n*4,p*17,r*2,s"
|
32
32
|
#
|
33
33
|
# @return [String] The FEEN string representing the position.
|
34
|
-
def self.dump(
|
34
|
+
def self.dump(board_shape:, side_to_move:, piece_placement:, pieces_in_hand: nil)
|
35
35
|
Dumper.call(
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
pieces_in_hand:,
|
37
|
+
board_shape:,
|
38
|
+
side_to_move:,
|
39
|
+
piece_placement:
|
40
40
|
)
|
41
41
|
end
|
42
42
|
|
@@ -45,12 +45,12 @@ module FEEN
|
|
45
45
|
# @param feen [String] The FEEN string representing a position.
|
46
46
|
#
|
47
47
|
# @example Parse a classic Tsume Shogi problem
|
48
|
-
# parse("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9
|
48
|
+
# parse("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 s S,b,g*4,n*4,p*17,r*2,s")
|
49
49
|
# # => {
|
50
|
-
# # "
|
51
|
-
# # "
|
52
|
-
# # "
|
53
|
-
# # "
|
50
|
+
# # "pieces_in_hand": ["S", "b", "g", "g", "g", "g", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r", "r", "s"],
|
51
|
+
# # "board_shape": [9, 9],
|
52
|
+
# # "side_to_move": "s",
|
53
|
+
# # "piece_placement": {
|
54
54
|
# # 3 => "s",
|
55
55
|
# # 4 => "k",
|
56
56
|
# # 5 => "s",
|
metadata
CHANGED
@@ -1,155 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0.beta0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: brutal
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: byebug
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rubocop-md
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop-performance
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rubocop-rake
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rubocop-thread_safety
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: simplecov
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: yard
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
11
|
+
date: 2023-04-25 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
153
13
|
description: A Ruby interface for data serialization and deserialization in FEEN format.
|
154
14
|
email: contact@cyril.email
|
155
15
|
executables: []
|
@@ -160,22 +20,18 @@ files:
|
|
160
20
|
- README.md
|
161
21
|
- lib/feen.rb
|
162
22
|
- lib/feen/dumper.rb
|
163
|
-
- lib/feen/dumper/
|
164
|
-
- lib/feen/dumper/
|
165
|
-
- lib/feen/dumper/turn.rb
|
23
|
+
- lib/feen/dumper/piece_placement.rb
|
24
|
+
- lib/feen/dumper/pieces_in_hand.rb
|
166
25
|
- lib/feen/parser.rb
|
167
|
-
- lib/feen/parser/
|
168
|
-
- lib/feen/parser/
|
169
|
-
- lib/feen/parser/
|
170
|
-
|
171
|
-
homepage: https://developer.sashite.com/specs/forsyth-edwards-expanded-notation
|
26
|
+
- lib/feen/parser/board_shape.rb
|
27
|
+
- lib/feen/parser/piece_placement.rb
|
28
|
+
- lib/feen/parser/pieces_in_hand.rb
|
29
|
+
homepage: https://github.com/sashite/feen.rb
|
172
30
|
licenses:
|
173
31
|
- MIT
|
174
32
|
metadata:
|
175
|
-
|
176
|
-
|
177
|
-
source_code_uri: https://github.com/sashite/feen.rb
|
178
|
-
post_install_message:
|
33
|
+
rubygems_mfa_required: 'true'
|
34
|
+
post_install_message:
|
179
35
|
rdoc_options: []
|
180
36
|
require_paths:
|
181
37
|
- lib
|
@@ -183,15 +39,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
39
|
requirements:
|
184
40
|
- - ">="
|
185
41
|
- !ruby/object:Gem::Version
|
186
|
-
version: 3.
|
42
|
+
version: 3.2.0
|
187
43
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
44
|
requirements:
|
189
|
-
- - "
|
45
|
+
- - ">"
|
190
46
|
- !ruby/object:Gem::Version
|
191
|
-
version:
|
47
|
+
version: 1.3.1
|
192
48
|
requirements: []
|
193
|
-
rubygems_version: 3.
|
194
|
-
signing_key:
|
49
|
+
rubygems_version: 3.4.6
|
50
|
+
signing_key:
|
195
51
|
specification_version: 4
|
196
52
|
summary: FEEN support for the Ruby language.
|
197
53
|
test_files: []
|
data/lib/feen/dumper/turn.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module FEEN
|
4
|
-
module Dumper
|
5
|
-
# The turn module.
|
6
|
-
module Turn
|
7
|
-
# @param side_id [Integer] The identifier of the active player.
|
8
|
-
#
|
9
|
-
# @example Dump the number that identify the player who have to play
|
10
|
-
# dump(0) # => "0"
|
11
|
-
#
|
12
|
-
# @return [String] The number that identify the player who have to play.
|
13
|
-
def self.dump(side_id)
|
14
|
-
String(side_id)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/feen/parser/turn.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module FEEN
|
4
|
-
module Parser
|
5
|
-
# The turn module.
|
6
|
-
module Turn
|
7
|
-
# @param side_id [String] The identifier of bottom-side and
|
8
|
-
# top-side.
|
9
|
-
#
|
10
|
-
# @example Parse the number that identify the player who have to play
|
11
|
-
# parse("0") # => 0
|
12
|
-
#
|
13
|
-
# @return [Integer] The number that identify the player who have to play.
|
14
|
-
def self.parse(side_id)
|
15
|
-
Integer(side_id)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|