feen 4.0.3 → 5.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98cae677c862ba15d503bd607228abfd3aa06f7b4524c30f1a8890f446978784
4
- data.tar.gz: ce5628e2b182d15d7e51567b67550338308a87508bf4422cae6e710b04aa6e33
3
+ metadata.gz: 2fa56bccbb1911f15569f2f5643646986cbf83661efba3165c69978e7c85fd56
4
+ data.tar.gz: 13d706d1bfe1c09f6d015d0a8f28af621754677711074ec60ec96e395f1a1061
5
5
  SHA512:
6
- metadata.gz: b294ea3521b0e34fbce443942d7c9aec06388f290025977d6995312f0a01492aedd498ea6a9e41b5eb19f9762ae79a6970a512f192fda2ab09ec890cd77c606d
7
- data.tar.gz: 6dd225e8abcf4189f4124225a35d26c1f1faf39e804204f2467bf11350539394f9ea52eeabb3835d1d3ab232c74b1136e341f21669b469a126395473034bdac7
6
+ metadata.gz: 5479cbd02c902aa8c45cc12ecfab31c7b7283eb1f8ec60b110c889505a7ebbcf76fa7b0d2e6ad44c60da954312fa85ae03cd4981d929207b0612754f1d62a033
7
+ data.tar.gz: b6268ce619808bf2c2f889261b55007edbfc030bc37b8edea7f73f505de55e8c0fc1cd4a268e8e2bdc71fe21c9fa33f904c8b26a23b92b471e406e109494bd97
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # FEEN.rb
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,24 +6,18 @@
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__ (FEN Easy Extensible Notation) support for the Ruby language.
9
+ > __FEEN__ (Forsyth–Edwards Expanded 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/fen-easy-extensible-notation), a generic format that can be used for serializing and deserializing chess positions.
14
-
15
- 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).
16
-
17
- 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) 🖖
18
-
19
- ![3D chess on Star Trek (from the episode "Court Martial")](https://github.com/sashite/feen.rb/raw/main/star-trek-chess.jpg)
13
+ This is an implementation of [FEEN](https://github.com/sashite/specs/blob/main/forsyth-edwards-expanded-notation.md), a flexible and minimalist format for describing chess variant positions.
20
14
 
21
15
  ## Installation
22
16
 
23
17
  Add this line to your application's Gemfile:
24
18
 
25
19
  ```ruby
26
- gem "feen"
20
+ gem "feen", ">= 5.0.0.beta1"
27
21
  ```
28
22
 
29
23
  And then execute:
@@ -35,20 +29,30 @@ bundle install
35
29
  Or install it yourself as:
36
30
 
37
31
  ```sh
38
- gem install feen
32
+ gem install feen --pre
39
33
  ```
40
34
 
41
35
  ## Usage
42
36
 
37
+ ### Serialization
38
+
39
+ A position can be serialized by filling in these fields:
40
+
41
+ - **Board shape**: An array of integers. For instance, it would be `[10, 9]` for a Xiangqi board. Or it would be `[8, 8]` for a Chess board.
42
+ - **Piece placement**: Describes the placement of pieces on the board with a hash that references each piece on the board.
43
+ - **Side to move**: A char that indicates who moves next. In chess, "`w`" would mean that White can play a move.
44
+
45
+ #### Example
46
+
47
+ From a classic Tsume Shogi problem:
48
+
43
49
  ```ruby
44
50
  require "feen"
45
51
 
46
- # Dump a classic Tsume Shogi problem
47
- FEEN.dump(
48
- 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],
49
- shape: [9, 9],
50
- side_id: 0,
51
- square: {
52
+ Feen.dump(
53
+ board_shape: [9, 9],
54
+ side_to_move: "s",
55
+ piece_placement: {
52
56
  3 => "s",
53
57
  4 => "k",
54
58
  5 => "s",
@@ -56,11 +60,22 @@ FEEN.dump(
56
60
  43 => "+B"
57
61
  }
58
62
  )
59
- # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 0 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"
63
+ # => "3sks3/9/4+P4/9/7+B1/9/9/9/9 s"
64
+ ```
65
+
66
+ ### Deserialization
67
+
68
+ Serialized positions can be converted back to fields.
69
+
70
+ #### Example
71
+
72
+ ```ruby
73
+ require "feen"
60
74
 
61
- # Parse a classic Tsume Shogi problem
62
- FEEN.parse("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 0 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")
63
- # => {:square=>{3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"}, :shape=>[9, 9], :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"], :side_id=>0}
75
+ Feen.parse("3sks3/9/4+P4/9/7+B1/9/9/9/9 s")
76
+ # {:board_shape=>[9, 9],
77
+ # :piece_placement=>{3=>"s", 4=>"k", 5=>"s", 22=>"+P", 43=>"+B"},
78
+ # :side_to_move=>"s"}
64
79
  ```
65
80
 
66
81
  ## License
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module FEEN
3
+ module Feen
4
4
  module Dumper
5
- # The square class.
5
+ # The PiecePlacement class.
6
6
  #
7
7
  # @example Dump an empty board of Xiangqi
8
- # Board.new([10, 9]).to_s # => "9/9/9/9/9/9/9/9/9/9"
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
- # Board.new(
11
+ # PiecePlacement.new(
12
12
  # [10, 9],
13
13
  # {
14
14
  # 0 => "車",
@@ -44,13 +44,13 @@ module FEEN
44
44
  # 88 => "傌",
45
45
  # 89 => "俥"
46
46
  # }
47
- # ).to_s # => "車,馬,象,士,將,士,象,馬,車/9/1,砲,5,砲,1/卒,1,卒,1,卒,1,卒,1,卒/9/9/兵,1,兵,1,兵,1,兵,1,兵/1,炮,5,炮,1/9/俥,傌,相,仕,帥,仕,相,傌,俥"
48
- class Square
47
+ # ).to_s # => "車馬象士將士象馬車/9/151/卒1111卒/9/9/兵1111兵/151/9/俥傌相仕帥仕相傌俥"
48
+ class PiecePlacement
49
49
  # @param indexes [Array] The shape of the board.
50
- # @param board [Hash] The index of each piece on the board.
51
- def initialize(indexes, board)
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| board.fetch(i, nil) }
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.
@@ -79,6 +79,7 @@ module FEEN
79
79
  .map { |square| square.nil? ? 1 : square }
80
80
  .join(",")
81
81
  .gsub(/1,[1,]*1/) { |str| str.split(",").length }
82
+ .delete(",")
82
83
  end
83
84
  end
84
85
  end
data/lib/feen/dumper.rb CHANGED
@@ -1,25 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative File.join("dumper", "in_hand")
4
- require_relative File.join("dumper", "square")
5
- require_relative File.join("dumper", "turn")
3
+ require_relative File.join("dumper", "piece_placement")
6
4
 
7
- module FEEN
5
+ module Feen
8
6
  # The dumper module.
9
7
  module Dumper
10
8
  # Dump position params into a FEEN string.
11
9
  #
12
- # @param in_hand [Array] The list of pieces in hand.
13
- # @param shape [Array] The shape of the board.
14
- # @param side_id [Integer] The identifier of the player who must play.
15
- # @param square [Hash] The index of each piece on the board.
10
+ # @param board_shape [Array] The shape of the board.
11
+ # @param side_to_move [String] Identify the active side.
12
+ # @param piece_placement [Hash] The index of each piece on the board.
16
13
  #
17
14
  # @example Dump a classic Tsume Shogi problem
18
15
  # call(
19
- # "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
- # "shape": [9, 9],
21
- # "side_id": 0,
22
- # "square": {
16
+ # "board_shape": [9, 9],
17
+ # "side_to_move": "s",
18
+ # "piece_placement": {
23
19
  # 3 => "s",
24
20
  # 4 => "k",
25
21
  # 5 => "s",
@@ -27,14 +23,13 @@ module FEEN
27
23
  # 43 => "+B"
28
24
  # }
29
25
  # )
30
- # # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 0 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"
26
+ # # => "3sks3/9/4+P4/9/7+B1/9/9/9/9 s"
31
27
  #
32
28
  # @return [String] The FEEN string representing the position.
33
- def self.call(in_hand:, shape:, side_id:, square:)
29
+ def self.call(board_shape:, side_to_move:, piece_placement:)
34
30
  [
35
- Square.new(shape, square).to_s,
36
- Turn.dump(side_id),
37
- InHand.dump(in_hand)
31
+ PiecePlacement.new(board_shape, piece_placement).to_s,
32
+ side_to_move
38
33
  ].join(" ")
39
34
  end
40
35
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Feen
4
+ module Parser
5
+ # The BoardShape class.
6
+ #
7
+ # @example Parse the shape of a shogiban
8
+ # BoardShape.new("3sks3/9/4+P4/9/7+B1/9/9/9/9").to_a # => [9, 9]
9
+ class BoardShape
10
+ # @param board_str [String] The flatten board.
11
+ def initialize(board_str, regex: /\+?[a-z]/i)
12
+ @board_str = board_str
13
+ @regex = regex
14
+ end
15
+
16
+ # @return [Array] The size of each dimension of the board.
17
+ def to_a
18
+ indexes(@board_str, @board_str.scan(%r{/+}).sort.fetch(-1))
19
+ end
20
+
21
+ private
22
+
23
+ def indexes(string, separator)
24
+ if separator.empty?
25
+ last_index = string.scan(/(\d+|#{@regex})/).inject(0) do |counter, match|
26
+ sub_string = match[0]
27
+ number = sub_string.match?(/\d+/) ? Integer(sub_string) : 1
28
+ counter + number
29
+ end
30
+
31
+ return [last_index]
32
+ end
33
+
34
+ sub_strings = string.split(separator)
35
+ [sub_strings.length] + indexes(sub_strings.fetch(0), separator[1..])
36
+ end
37
+ end
38
+ end
39
+ end
data/lib/feen/parser.rb CHANGED
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative File.join("parser", "in_hand")
4
- require_relative File.join("parser", "shape")
5
- require_relative File.join("parser", "square")
6
- require_relative File.join("parser", "turn")
3
+ require_relative File.join("parser", "board_shape")
7
4
 
8
- module FEEN
5
+ module Feen
9
6
  # The parser module.
10
7
  module Parser
11
8
  # Parse a FEEN string into position params.
@@ -13,12 +10,11 @@ module FEEN
13
10
  # @param feen [String] The FEEN string representing a position.
14
11
  #
15
12
  # @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 0 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
+ # call("3sks3/9/4+P4/9/7+B1/9/9/9/9 s")
17
14
  # # => {
18
- # # "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
- # # "shape": [9, 9],
20
- # # "side_id": 0,
21
- # # "square": {
15
+ # # "board_shape": [9, 9],
16
+ # # "side_to_move": "s",
17
+ # # "piece_placement": {
22
18
  # # 3 => "s",
23
19
  # # 4 => "k",
24
20
  # # 5 => "s",
@@ -27,15 +23,29 @@ module FEEN
27
23
  # # }
28
24
  #
29
25
  # @return [Hash] The position params representing the position.
30
- def self.call(feen)
31
- square_str, side_id_str, in_hand_str = feen.split
26
+ def self.call(feen, regex: /\+?[a-z]/i)
27
+ piece_placement_str, side_to_move_str = feen.split
32
28
 
33
29
  {
34
- in_hand: InHand.parse(in_hand_str),
35
- shape: Shape.new(square_str).to_a,
36
- side_id: Turn.parse(side_id_str),
37
- square: Square.new(square_str).to_h
30
+ board_shape: BoardShape.new(piece_placement_str, regex:).to_a,
31
+ piece_placement: piece_placement(piece_placement_str, regex:),
32
+ side_to_move: side_to_move_str
38
33
  }
39
34
  end
35
+
36
+ def self.piece_placement(string, regex:)
37
+ hash = {}
38
+ index = 0
39
+ string.scan(/(\d+|#{regex})/) do |match|
40
+ if /\d+/.match?(match[0])
41
+ index += match[0].to_i
42
+ else
43
+ hash[index] = match[0]
44
+ index += 1
45
+ end
46
+ end
47
+ hash
48
+ end
49
+ private_class_method :piece_placement
40
50
  end
41
51
  end
data/lib/feen.rb CHANGED
@@ -6,21 +6,19 @@ 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/fen-easy-extensible-notation
10
- module FEEN
9
+ # @see https://github.com/sashite/specs/blob/main/forsyth-edwards-expanded-notation.md
10
+ module Feen
11
11
  # Dumps position params into a FEEN string.
12
12
  #
13
- # @param in_hand [Array] The list of pieces in hand.
14
- # @param shape [Array] The shape of the board.
15
- # @param side_id [Integer] The identifier of the player who must play.
16
- # @param square [Hash] The index of each piece on the board.
13
+ # @param board_shape [Array] The shape of the board.
14
+ # @param side_to_move [String] The identifier of the player who must play.
15
+ # @param piece_placement [Hash] The index of each piece on the board.
17
16
  #
18
17
  # @example Dump a classic Tsume Shogi problem
19
18
  # dump(
20
- # "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],
21
- # "shape": [9, 9],
22
- # "side_id": 0,
23
- # "square": {
19
+ # "board_shape": [9, 9],
20
+ # "side_to_move": "s",
21
+ # "piece_placement": {
24
22
  # 3 => "s",
25
23
  # 4 => "k",
26
24
  # 5 => "s",
@@ -28,15 +26,14 @@ module FEEN
28
26
  # 43 => "+B"
29
27
  # }
30
28
  # )
31
- # # => "3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9 0 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"
29
+ # # => "3sks3/9/4+P4/9/7+B1/9/9/9/9 s"
32
30
  #
33
31
  # @return [String] The FEEN string representing the position.
34
- def self.dump(in_hand:, shape:, side_id:, square:)
32
+ def self.dump(board_shape:, side_to_move:, piece_placement:)
35
33
  Dumper.call(
36
- in_hand:,
37
- shape:,
38
- side_id:,
39
- square:
34
+ board_shape:,
35
+ side_to_move:,
36
+ piece_placement:
40
37
  )
41
38
  end
42
39
 
@@ -45,12 +42,11 @@ module FEEN
45
42
  # @param feen [String] The FEEN string representing a position.
46
43
  #
47
44
  # @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 0 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")
45
+ # parse("3sks3/9/4+P4/9/7+B1/9/9/9/9 s")
49
46
  # # => {
50
- # # "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
- # # "shape": [9, 9],
52
- # # "side_id": 0,
53
- # # "square": {
47
+ # # "board_shape": [9, 9],
48
+ # # "side_to_move": "s",
49
+ # # "piece_placement": {
54
50
  # # 3 => "s",
55
51
  # # 4 => "k",
56
52
  # # 5 => "s",
@@ -59,7 +55,7 @@ module FEEN
59
55
  # # }
60
56
  #
61
57
  # @return [Hash] The position params representing the position.
62
- def self.parse(feen)
63
- Parser.call(feen)
58
+ def self.parse(feen, regex: /\+?[a-z]/i)
59
+ Parser.call(feen, regex:)
64
60
  end
65
61
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feen
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.3
4
+ version: 5.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-24 00:00:00.000000000 Z
11
+ date: 2023-04-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby interface for data serialization and deserialization in FEEN format.
14
14
  email: contact@cyril.email
@@ -20,14 +20,9 @@ files:
20
20
  - README.md
21
21
  - lib/feen.rb
22
22
  - lib/feen/dumper.rb
23
- - lib/feen/dumper/in_hand.rb
24
- - lib/feen/dumper/square.rb
25
- - lib/feen/dumper/turn.rb
23
+ - lib/feen/dumper/piece_placement.rb
26
24
  - lib/feen/parser.rb
27
- - lib/feen/parser/in_hand.rb
28
- - lib/feen/parser/shape.rb
29
- - lib/feen/parser/square.rb
30
- - lib/feen/parser/turn.rb
25
+ - lib/feen/parser/board_shape.rb
31
26
  homepage: https://github.com/sashite/feen.rb
32
27
  licenses:
33
28
  - MIT
@@ -44,9 +39,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
44
39
  version: 3.2.0
45
40
  required_rubygems_version: !ruby/object:Gem::Requirement
46
41
  requirements:
47
- - - ">="
42
+ - - ">"
48
43
  - !ruby/object:Gem::Version
49
- version: '0'
44
+ version: 1.3.1
50
45
  requirements: []
51
46
  rubygems_version: 3.4.6
52
47
  signing_key:
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FEEN
4
- module Dumper
5
- # The pieces in hand module.
6
- module InHand
7
- # Serialize pieces in hand lists into a string.
8
- #
9
- # @param piece_names [Array] A list of pieces in hand.
10
- #
11
- # @example Dump a list of pieces in hand
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,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
- #
15
- # @example Dump an empty list of pieces in hand
16
- # dump([])
17
- # # => "-"
18
- #
19
- # @return [String] A string representing the pieces in hand.
20
- def self.dump(piece_names)
21
- return "-" if piece_names.empty?
22
-
23
- piece_names.sort.join(",")
24
- end
25
- end
26
- end
27
- end
@@ -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
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FEEN
4
- module Parser
5
- # The pieces in hand module.
6
- module InHand
7
- # The list of pieces in hand grouped by players.
8
- #
9
- # @param piece_names_str [String] The serialized list of pieces in hand.
10
- #
11
- # @example Parse a list of serialized pieces in hand
12
- # parse("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", "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
- #
15
- # @example Parse an empty list of serialized pieces in hand
16
- # parse("-")
17
- # # => []
18
- #
19
- # @return [Array] The list of pieces in hand grouped by players.
20
- def self.parse(piece_names_str)
21
- return [] if piece_names_str == "-"
22
-
23
- piece_names_str.split(",")
24
- end
25
- end
26
- end
27
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FEEN
4
- module Parser
5
- # The shape class.
6
- #
7
- # @example Parse the shape of a shogiban
8
- # Shape.new("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9").to_a # => [9, 9]
9
- class Shape
10
- # @param board [String] The flatten board.
11
- def initialize(board)
12
- @board = board
13
- end
14
-
15
- # @return [Array] The size of each dimension of the board.
16
- def to_a
17
- indexes(@board, @board.scan(%r{/+}).sort.fetch(-1))
18
- end
19
-
20
- private
21
-
22
- def indexes(string, separator)
23
- if separator.empty?
24
- last_index = string.split(",").inject(0) do |counter, sub_string|
25
- number = sub_string.match?(/[0-9]+/) ? Integer(sub_string) : 1
26
- counter + number
27
- end
28
-
29
- return [last_index]
30
- end
31
-
32
- sub_strings = string.split(separator)
33
- [sub_strings.length] + indexes(sub_strings.fetch(0), separator[1..])
34
- end
35
- end
36
- end
37
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FEEN
4
- module Parser
5
- # The square class.
6
- #
7
- # @example Parse a Shogi problem board and return an array
8
- # Board.new("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9").to_a
9
- # # => [
10
- # # nil, nil, nil, "s", "k", "s", nil, nil, nil,
11
- # # nil, nil, nil, nil, nil, nil, nil, nil, nil,
12
- # # nil, nil, nil, nil, "+P", nil, nil, nil, nil,
13
- # # nil, nil, nil, nil, nil, nil, nil, nil, nil,
14
- # # nil, nil, nil, nil, nil, nil, nil, "+B", nil,
15
- # # nil, nil, nil, nil, nil, nil, nil, nil, nil,
16
- # # nil, nil, nil, nil, nil, nil, nil, nil, nil,
17
- # # nil, nil, nil, nil, nil, nil, nil, nil, nil,
18
- # # nil, nil, nil, nil, nil, nil, nil, nil, nil
19
- # # ]
20
- #
21
- # @example Parse a Shogi problem board and return a hash
22
- # Board.new("3,s,k,s,3/9/4,+P,4/9/7,+B,1/9/9/9/9").to_h
23
- # # => {
24
- # # 3 => "s",
25
- # # 4 => "k",
26
- # # 5 => "s",
27
- # # 22 => "+P",
28
- # # 43 => "+B"
29
- # # }
30
- class Square
31
- # @param board [String] The flatten board.
32
- def initialize(board)
33
- @board = board
34
- end
35
-
36
- # @return [Array] The list of squares on the board.
37
- def to_a
38
- @board
39
- .split(%r{[/,]+})
40
- .flat_map { |str| row(str) }
41
- end
42
-
43
- # @return [Hash] The index of each piece on the board.
44
- def to_h
45
- to_a
46
- .each_with_index
47
- .inject({}) do |h, (v, i)|
48
- next h if v.nil?
49
-
50
- h.merge(i => v)
51
- end
52
- end
53
-
54
- private
55
-
56
- def row(string)
57
- string.match?(/[0-9]+/) ? ::Array.new(Integer(string)) : string
58
- end
59
- end
60
- end
61
- end
@@ -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