feen 1.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,56 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dumper/board'
4
- require_relative 'dumper/pieces_in_hand'
5
- require_relative 'dumper/turn'
3
+ require_relative "dumper/board"
4
+ require_relative "dumper/pieces_in_hand"
5
+ require_relative "dumper/turn"
6
6
 
7
7
  module FEEN
8
8
  # The dumper module.
9
9
  module Dumper
10
10
  # Dump position params into a FEEN string.
11
11
  #
12
- # @param active_side [Integer] The identifier of the player who must play.
12
+ # @param side_id [Integer] The identifier of the player who must play.
13
+ # @param board [Hash] The indexes of each piece on the board.
13
14
  # @param indexes [Array] The shape of the board.
14
- # @param pieces_in_hand_by_players [Array] The list of pieces in hand
15
+ # @param hands [Array] The list of pieces in hand
15
16
  # grouped by players.
16
- # @param squares [Array] The list of squares on the board.
17
17
  #
18
- # @example Dump Four-player chess's starting position
18
+ # @example Dump a classic Tsume Shogi problem
19
19
  # call(
20
- # active_side: 0,
21
- # indexes: [14, 14],
22
- # pieces_in_hand_by_players: [
23
- # [],
24
- # [],
25
- # [],
26
- # []
20
+ # "board": {
21
+ # 3 => "s",
22
+ # 4 => "k",
23
+ # 5 => "s",
24
+ # 22 => "+P",
25
+ # 43 => "+B"
26
+ # },
27
+ # "hands": [
28
+ # %w[S],
29
+ # %w[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]
27
30
  # ],
28
- # squares: [
29
- # nil , nil , nil , "yR", "yN", "yB", "yK", "yQ", "yB", "yN", "yR", nil , nil , nil ,
30
- # nil , nil , nil , "yP", "yP", "yP", "yP", "yP", "yP", "yP", "yP", nil , nil , nil ,
31
- # nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil ,
32
- # "bR", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gR",
33
- # "bN", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gN",
34
- # "bB", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gB",
35
- # "bK", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gQ",
36
- # "bQ", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gK",
37
- # "bB", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gB",
38
- # "bN", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gN",
39
- # "bR", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gR",
40
- # nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil ,
41
- # nil , nil , nil , "rP", "rP", "rP", "rP", "rP", "rP", "rP", "rP", nil , nil , nil ,
42
- # nil , nil , nil , "rR", "rN", "rB", "rQ", "rK", "rB", "rN", "rR", nil , nil , nil
43
- # ]
31
+ # "indexes": [9, 9],
32
+ # "side_id": 0
44
33
  # )
45
- # # => "3,yR,yN,yB,yK,yQ,yB,yN,yR,3/3,yP,yP,yP,yP,yP,yP,yP,yP,3/14/bR,bP,10,gP,gR/bN,bP,10,gP,gN/bB,bP,10,gP,gB/bK,bP,10,gP,gQ/bQ,bP,10,gP,gK/bB,bP,10,gP,gB/bN,bP,10,gP,gN/bR,bP,10,gP,gR/14/3,rP,rP,rP,rP,rP,rP,rP,rP,3/3,rR,rN,rB,rQ,rK,rB,rN,rR,3 0 ///"
34
+ # # => "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"
46
35
  #
47
36
  # @return [String] The FEEN string representing the position.
48
- def self.call(active_side:, indexes:, pieces_in_hand_by_players:, squares:)
37
+ def self.call(board:, hands:, indexes:, side_id:)
49
38
  [
50
- Board.new(*indexes).to_s(*squares),
51
- Turn.dump(active_side, pieces_in_hand_by_players.length),
52
- PiecesInHand.dump(*pieces_in_hand_by_players)
53
- ].join(' ')
39
+ Board.new(indexes, board).to_s,
40
+ Turn.dump(side_id, hands.length),
41
+ PiecesInHand.dump(hands)
42
+ ].join(" ")
54
43
  end
55
44
  end
56
45
  end
@@ -1,42 +1,84 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'inconsistent_size_error'
4
-
5
3
  module FEEN
6
4
  module Dumper
7
5
  # The board class.
6
+ #
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"
9
+ #
10
+ # @example Dump the Xiangqi starting position board
11
+ # Board.new(
12
+ # [10, 9],
13
+ # {
14
+ # 0 => "車",
15
+ # 1 => "馬",
16
+ # 2 => "象",
17
+ # 3 => "士",
18
+ # 4 => "將",
19
+ # 5 => "士",
20
+ # 6 => "象",
21
+ # 7 => "馬",
22
+ # 8 => "車",
23
+ # 19 => "砲",
24
+ # 25 => "砲",
25
+ # 27 => "卒",
26
+ # 29 => "卒",
27
+ # 31 => "卒",
28
+ # 33 => "卒",
29
+ # 35 => "卒",
30
+ # 54 => "兵",
31
+ # 56 => "兵",
32
+ # 58 => "兵",
33
+ # 60 => "兵",
34
+ # 62 => "兵",
35
+ # 64 => "炮",
36
+ # 70 => "炮",
37
+ # 81 => "俥",
38
+ # 82 => "傌",
39
+ # 83 => "相",
40
+ # 84 => "仕",
41
+ # 85 => "帥",
42
+ # 86 => "仕",
43
+ # 87 => "相",
44
+ # 88 => "傌",
45
+ # 89 => "俥"
46
+ # }
47
+ # ).to_s # => "車,馬,象,士,將,士,象,馬,車/9/1,砲,5,砲,1/卒,1,卒,1,卒,1,卒,1,卒/9/9/兵,1,兵,1,兵,1,兵,1,兵/1,炮,5,炮,1/9/俥,傌,相,仕,帥,仕,相,傌,俥"
8
48
  class Board
9
49
  # @param indexes [Array] The shape of the board.
10
- def initialize(*indexes)
50
+ # @param board [Hash] The indexes of each piece on the board.
51
+ def initialize(indexes, board)
11
52
  @indexes = indexes
53
+ @squares = Array.new(length) { |i| board.fetch(i, nil) }
12
54
  end
13
55
 
14
- # @param squares [Array] The list of squares on the board.
15
- #
16
56
  # @return [String] The string representing the board.
17
- def to_s(*squares)
18
- raise InconsistentSizeError unless squares.length == @indexes.inject(:*)
19
-
20
- unflatten(squares, *@indexes)
57
+ def to_s
58
+ unflatten(@squares, @indexes)
21
59
  end
22
60
 
23
61
  private
24
62
 
25
- def unflatten(squares, *remaining_indexes)
26
- return row(*squares) if remaining_indexes.length == 1
63
+ def length
64
+ @indexes.inject(:*)
65
+ end
66
+
67
+ def unflatten(squares, remaining_indexes)
68
+ return row(squares) if remaining_indexes.length == 1
27
69
 
28
70
  squares
29
71
  .each_slice(squares.length / remaining_indexes.fetch(0))
30
72
  .to_a
31
- .map { |sub_squares| unflatten(sub_squares, *remaining_indexes[1..]) }
32
- .join('/' * remaining_indexes.length.pred)
73
+ .map { |sub_squares| unflatten(sub_squares, remaining_indexes[1..]) }
74
+ .join("/" * remaining_indexes.length.pred)
33
75
  end
34
76
 
35
- def row(*squares)
77
+ def row(squares)
36
78
  squares
37
79
  .map { |square| square.nil? ? 1 : square }
38
- .join(',')
39
- .gsub(/1,[1,]*1/) { |str| str.split(',').length }
80
+ .join(",")
81
+ .gsub(/1,[1,]*1/) { |str| str.split(",").length }
40
82
  end
41
83
  end
42
84
  end
@@ -3,26 +3,33 @@
3
3
  module FEEN
4
4
  module Dumper
5
5
  # The pieces in hand class.
6
+ #
7
+ # @example Serialize a list of pieces in hand grouped by sides
8
+ # PiecesInHand.dump(
9
+ # %w[S],
10
+ # %w[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]
11
+ # )
12
+ # # => "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"
6
13
  class PiecesInHand
7
14
  # Serialize pieces in hand lists into a string.
8
15
  #
9
- # @param pieces_in_hand_by_players [Array] The list of pieces in hand
16
+ # @param hands [Array] The list of pieces in hand
10
17
  # grouped by players.
11
18
  #
12
19
  # @return [String] A string representing the pieces in hand of both
13
20
  # players.
14
- def self.dump(*pieces_in_hand_by_players)
15
- pieces_in_hand_by_players.map { |pieces| new(*pieces).to_s }.join('/')
21
+ def self.dump(hands)
22
+ hands.map { |pieces| new(pieces).to_s }.join("/")
16
23
  end
17
24
 
18
25
  # @param pieces [Array] A list of pieces in hand.
19
- def initialize(*pieces)
26
+ def initialize(pieces)
20
27
  @pieces = pieces.sort
21
28
  end
22
29
 
23
30
  # @return [String] A string representing the pieces in hand.
24
31
  def to_s
25
- @pieces.join(',')
32
+ @pieces.join(",")
26
33
  end
27
34
  end
28
35
  end
@@ -2,14 +2,17 @@
2
2
 
3
3
  module FEEN
4
4
  module Dumper
5
- # The turn class.
5
+ # The turn module.
6
6
  module Turn
7
- # @param active_side [Integer] The identifier of the active player.
7
+ # @param side_id [Integer] The identifier of the active player.
8
8
  # @param sides_count [Integer] The number of players.
9
9
  #
10
+ # @example Dump the number that identify the player who have to play
11
+ # dump(0, 2) # => "0"
12
+ #
10
13
  # @return [String] The number that identify the player who have to play.
11
- def self.dump(active_side, sides_count)
12
- String(Integer(active_side) % Integer(sides_count))
14
+ def self.dump(side_id, sides_count)
15
+ String(Integer(side_id) % Integer(sides_count))
13
16
  end
14
17
  end
15
18
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'parser/board'
4
- require_relative 'parser/pieces_in_hand'
5
- require_relative 'parser/shape'
6
- require_relative 'parser/turn'
3
+ require_relative "parser/board"
4
+ require_relative "parser/pieces_in_hand"
5
+ require_relative "parser/shape"
6
+ require_relative "parser/turn"
7
7
 
8
8
  module FEEN
9
9
  # The parser module.
@@ -12,53 +12,33 @@ module FEEN
12
12
  #
13
13
  # @param feen [String] The FEEN string representing a position.
14
14
  #
15
- # @example Parse Four-player chess's starting position
16
- # call("3,yR,yN,yB,yK,yQ,yB,yN,yR,3/3,yP,yP,yP,yP,yP,yP,yP,yP,3/14/bR,bP,10,gP,gR/bN,bP,10,gP,gN/bB,bP,10,gP,gB/bK,bP,10,gP,gQ/bQ,bP,10,gP,gK/bB,bP,10,gP,gB/bN,bP,10,gP,gN/bR,bP,10,gP,gR/14/3,rP,rP,rP,rP,rP,rP,rP,rP,3/3,rR,rN,rB,rQ,rK,rB,rN,rR,3 0 ///")
15
+ # @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")
17
17
  # # => {
18
- # # active_side: 0,
19
- # # indexes: [14, 14],
20
- # # pieces_in_hand_by_players: [
21
- # # [],
22
- # # [],
23
- # # [],
24
- # # []
18
+ # # "board": {
19
+ # # 3 => "s",
20
+ # # 4 => "k",
21
+ # # 5 => "s",
22
+ # # 22 => "+P",
23
+ # # 43 => "+B"
24
+ # # },
25
+ # # "hands": [
26
+ # # %w[S],
27
+ # # %w[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]
25
28
  # # ],
26
- # # squares: [
27
- # # nil , nil , nil , "yR", "yN", "yB", "yK", "yQ", "yB", "yN", "yR", nil , nil , nil ,
28
- # # nil , nil , nil , "yP", "yP", "yP", "yP", "yP", "yP", "yP", "yP", nil , nil , nil ,
29
- # # nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil ,
30
- # # "bR", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gR",
31
- # # "bN", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gN",
32
- # # "bB", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gB",
33
- # # "bK", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gQ",
34
- # # "bQ", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gK",
35
- # # "bB", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gB",
36
- # # "bN", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gN",
37
- # # "bR", "bP", nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , "gP", "gR",
38
- # # nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil ,
39
- # # nil , nil , nil , "rP", "rP", "rP", "rP", "rP", "rP", "rP", "rP", nil , nil , nil ,
40
- # # nil , nil , nil , "rR", "rN", "rB", "rQ", "rK", "rB", "rN", "rR", nil , nil , nil
41
- # # ]
29
+ # # "indexes": [9, 9],
30
+ # # "side_id": 0
42
31
  # # }
43
32
  #
44
33
  # @return [Hash] The position params representing the position.
45
34
  def self.call(feen)
46
- params(*feen.split(' '))
47
- end
35
+ board, side_id, in_hand = feen.split(" ")
48
36
 
49
- # Parse the FEEN string's three fields and return the position params.
50
- #
51
- # @param board [String] The flatten board.
52
- # @param active_side [String] The active side identifier.
53
- # @param in_hand [String] The captured actors.
54
- #
55
- # @return [Hash] The position params representing the position.
56
- private_class_method def self.params(board, active_side, in_hand)
57
37
  {
58
- active_side: Turn.parse(active_side),
38
+ board: Board.new(board).to_h,
59
39
  indexes: Shape.new(board).to_a,
60
- pieces_in_hand_by_players: PiecesInHand.parse(in_hand),
61
- squares: Board.new(board).to_a
40
+ hands: PiecesInHand.parse(in_hand),
41
+ side_id: Turn.parse(side_id)
62
42
  }
63
43
  end
64
44
  end
@@ -4,7 +4,7 @@ module FEEN
4
4
  module Parser
5
5
  # The board class.
6
6
  #
7
- # @example Parse a Shogi problem board
7
+ # @example Parse a Shogi problem board and return an array
8
8
  # Board.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,
@@ -17,6 +17,16 @@ module FEEN
17
17
  # # nil, nil, nil, nil, nil, nil, nil, nil, nil,
18
18
  # # nil, nil, nil, nil, nil, nil, nil, nil, nil
19
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
+ # # }
20
30
  class Board
21
31
  # @param board [String] The flatten board.
22
32
  def initialize(board)
@@ -30,6 +40,17 @@ module FEEN
30
40
  .flat_map { |str| row(str) }
31
41
  end
32
42
 
43
+ # @return [Hash] The indexes 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
+
33
54
  private
34
55
 
35
56
  def row(string)
@@ -2,11 +2,11 @@
2
2
 
3
3
  module FEEN
4
4
  module Parser
5
- # The pieces in hand class.
5
+ # The pieces in hand module.
6
6
  module PiecesInHand
7
7
  # The list of pieces in hand grouped by players.
8
8
  #
9
- # @param pieces_in_hand_by_players_str [String] The serialized list of
9
+ # @param hands_str [String] The serialized list of
10
10
  # pieces in hand grouped by players.
11
11
  #
12
12
  # @example Parse a list of serialized pieces in hand
@@ -17,10 +17,10 @@ module FEEN
17
17
  # # ]
18
18
  #
19
19
  # @return [Array] The list of pieces in hand grouped by players.
20
- def self.parse(pieces_in_hand_by_players_str)
21
- pieces_in_hand_by_players_str
22
- .split('/', -1)
23
- .map { |pieces_in_hand_str| pieces_in_hand_str.split(',') }
20
+ def self.parse(hands_str)
21
+ hands_str
22
+ .split("/", -1)
23
+ .map { |pieces_in_hand_str| pieces_in_hand_str.split(",") }
24
24
  end
25
25
  end
26
26
  end
@@ -21,7 +21,7 @@ module FEEN
21
21
 
22
22
  def indexes(string, separator)
23
23
  if separator.empty?
24
- last_index = string.split(',').inject(0) do |counter, sub_string|
24
+ last_index = string.split(",").inject(0) do |counter, sub_string|
25
25
  number = sub_string.match?(/[0-9]+/) ? Integer(sub_string) : 1
26
26
  counter + number
27
27
  end
@@ -2,17 +2,17 @@
2
2
 
3
3
  module FEEN
4
4
  module Parser
5
- # The turn class.
5
+ # The turn module.
6
6
  module Turn
7
- # @param active_side_id [String] The identifier of bottom-side and
7
+ # @param side_id [String] The identifier of bottom-side and
8
8
  # top-side.
9
9
  #
10
10
  # @example Parse the number that identify the player who have to play
11
11
  # parse("0") # => 0
12
12
  #
13
13
  # @return [Integer] The number that identify the player who have to play.
14
- def self.parse(active_side_id)
15
- Integer(active_side_id)
14
+ def self.parse(side_id)
15
+ Integer(side_id)
16
16
  end
17
17
  end
18
18
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-16 00:00:00.000000000 Z
11
+ date: 2020-09-20 00:00:00.000000000 Z
12
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'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -119,7 +133,6 @@ files:
119
133
  - lib/feen.rb
120
134
  - lib/feen/dumper.rb
121
135
  - lib/feen/dumper/board.rb
122
- - lib/feen/dumper/inconsistent_size_error.rb
123
136
  - lib/feen/dumper/pieces_in_hand.rb
124
137
  - lib/feen/dumper/turn.rb
125
138
  - lib/feen/parser.rb
@@ -142,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
155
  requirements:
143
156
  - - ">="
144
157
  - !ruby/object:Gem::Version
145
- version: '0'
158
+ version: 2.7.0
146
159
  required_rubygems_version: !ruby/object:Gem::Requirement
147
160
  requirements:
148
161
  - - ">="