feen 1.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  - - ">="