feen 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -337
- data/lib/feen.rb +30 -677
- data/lib/feen/dumper.rb +25 -36
- data/lib/feen/dumper/board.rb +50 -12
- data/lib/feen/dumper/pieces_in_hand.rb +11 -4
- data/lib/feen/dumper/turn.rb +7 -4
- data/lib/feen/parser.rb +24 -35
- data/lib/feen/parser/board.rb +22 -1
- data/lib/feen/parser/pieces_in_hand.rb +6 -6
- data/lib/feen/parser/shape.rb +1 -1
- data/lib/feen/parser/turn.rb +1 -1
- metadata +16 -3
- data/lib/feen/dumper/inconsistent_size_error.rb +0 -8
data/lib/feen/dumper.rb
CHANGED
@@ -1,56 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
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
|
12
|
+
# @param active_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
|
15
|
+
# @param pieces_in_hand_grouped_by_sides [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
|
18
|
+
# @example Dump a classic Tsume Shogi problem
|
19
19
|
# call(
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
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
|
20
|
+
# "active_side_id": 0,
|
21
|
+
# "board": {
|
22
|
+
# "3": "s",
|
23
|
+
# "4": "k" ,
|
24
|
+
# "5": "s",
|
25
|
+
# "22": "+P",
|
26
|
+
# "43": "+B"
|
27
|
+
# },
|
28
|
+
# "indexes": [9, 9],
|
29
|
+
# "pieces_in_hand_grouped_by_sides": [
|
30
|
+
# %w[S],
|
31
|
+
# %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]
|
43
32
|
# ]
|
44
33
|
# )
|
45
|
-
# # => "3,
|
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(
|
37
|
+
def self.call(active_side_id:, board:, indexes:, pieces_in_hand_grouped_by_sides:)
|
49
38
|
[
|
50
|
-
Board.new(*indexes).to_s
|
51
|
-
Turn.dump(
|
52
|
-
PiecesInHand.dump(*
|
53
|
-
].join(
|
39
|
+
Board.new(*indexes, **board).to_s,
|
40
|
+
Turn.dump(active_side_id, pieces_in_hand_grouped_by_sides.length),
|
41
|
+
PiecesInHand.dump(*pieces_in_hand_grouped_by_sides)
|
42
|
+
].join(" ")
|
54
43
|
end
|
55
44
|
end
|
56
45
|
end
|
data/lib/feen/dumper/board.rb
CHANGED
@@ -1,27 +1,65 @@
|
|
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(10, 9,
|
12
|
+
# "0": "車",
|
13
|
+
# "1": "馬",
|
14
|
+
# "2": "象",
|
15
|
+
# "3": "士",
|
16
|
+
# "4": "將",
|
17
|
+
# "5": "士",
|
18
|
+
# "6": "象",
|
19
|
+
# "7": "馬",
|
20
|
+
# "8": "車",
|
21
|
+
# "19": "砲",
|
22
|
+
# "25": "砲",
|
23
|
+
# "27": "卒",
|
24
|
+
# "29": "卒",
|
25
|
+
# "31": "卒",
|
26
|
+
# "33": "卒",
|
27
|
+
# "35": "卒",
|
28
|
+
# "54": "兵",
|
29
|
+
# "56": "兵",
|
30
|
+
# "58": "兵",
|
31
|
+
# "60": "兵",
|
32
|
+
# "62": "兵",
|
33
|
+
# "64": "炮",
|
34
|
+
# "70": "炮",
|
35
|
+
# "81": "俥",
|
36
|
+
# "82": "傌",
|
37
|
+
# "83": "相",
|
38
|
+
# "84": "仕",
|
39
|
+
# "85": "帥",
|
40
|
+
# "86": "仕",
|
41
|
+
# "87": "相",
|
42
|
+
# "88": "傌",
|
43
|
+
# "89": "俥").to_s # => "車,馬,象,士,將,士,象,馬,車/9/1,砲,5,砲,1/卒,1,卒,1,卒,1,卒,1,卒/9/9/兵,1,兵,1,兵,1,兵,1,兵/1,炮,5,炮,1/9/俥,傌,相,仕,帥,仕,相,傌,俥"
|
8
44
|
class Board
|
9
45
|
# @param indexes [Array] The shape of the board.
|
10
|
-
|
46
|
+
# @param board [Hash] The indexes of each piece on the board.
|
47
|
+
def initialize(*indexes, **board)
|
11
48
|
@indexes = indexes
|
49
|
+
@squares = Array.new(length) { |i| board.fetch(i.to_s.to_sym, nil) }
|
12
50
|
end
|
13
51
|
|
14
|
-
# @param squares [Array] The list of squares on the board.
|
15
|
-
#
|
16
52
|
# @return [String] The string representing the board.
|
17
|
-
def to_s
|
18
|
-
|
19
|
-
|
20
|
-
unflatten(squares, *@indexes)
|
53
|
+
def to_s
|
54
|
+
unflatten(@squares, *@indexes)
|
21
55
|
end
|
22
56
|
|
23
57
|
private
|
24
58
|
|
59
|
+
def length
|
60
|
+
@indexes.inject(:*)
|
61
|
+
end
|
62
|
+
|
25
63
|
def unflatten(squares, *remaining_indexes)
|
26
64
|
return row(*squares) if remaining_indexes.length == 1
|
27
65
|
|
@@ -29,14 +67,14 @@ module FEEN
|
|
29
67
|
.each_slice(squares.length / remaining_indexes.fetch(0))
|
30
68
|
.to_a
|
31
69
|
.map { |sub_squares| unflatten(sub_squares, *remaining_indexes[1..]) }
|
32
|
-
.join(
|
70
|
+
.join("/" * remaining_indexes.length.pred)
|
33
71
|
end
|
34
72
|
|
35
73
|
def row(*squares)
|
36
74
|
squares
|
37
75
|
.map { |square| square.nil? ? 1 : square }
|
38
|
-
.join(
|
39
|
-
.gsub(/1,[1,]*1/) { |str| str.split(
|
76
|
+
.join(",")
|
77
|
+
.gsub(/1,[1,]*1/) { |str| str.split(",").length }
|
40
78
|
end
|
41
79
|
end
|
42
80
|
end
|
@@ -3,16 +3,23 @@
|
|
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
|
16
|
+
# @param pieces_in_hand_grouped_by_sides [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(*
|
15
|
-
|
21
|
+
def self.dump(*pieces_in_hand_grouped_by_sides)
|
22
|
+
pieces_in_hand_grouped_by_sides.map { |pieces| new(*pieces).to_s }.join("/")
|
16
23
|
end
|
17
24
|
|
18
25
|
# @param pieces [Array] A list of pieces in hand.
|
@@ -22,7 +29,7 @@ module FEEN
|
|
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
|
data/lib/feen/dumper/turn.rb
CHANGED
@@ -2,14 +2,17 @@
|
|
2
2
|
|
3
3
|
module FEEN
|
4
4
|
module Dumper
|
5
|
-
# The turn
|
5
|
+
# The turn module.
|
6
6
|
module Turn
|
7
|
-
# @param
|
7
|
+
# @param active_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(
|
12
|
-
String(Integer(
|
14
|
+
def self.dump(active_side_id, sides_count)
|
15
|
+
String(Integer(active_side_id) % Integer(sides_count))
|
13
16
|
end
|
14
17
|
end
|
15
18
|
end
|
data/lib/feen/parser.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
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,42 @@ module FEEN
|
|
12
12
|
#
|
13
13
|
# @param feen [String] The FEEN string representing a position.
|
14
14
|
#
|
15
|
-
# @example Parse
|
16
|
-
# call("3,
|
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
|
-
# #
|
19
|
-
# #
|
20
|
-
# #
|
21
|
-
# #
|
22
|
-
# #
|
23
|
-
# #
|
24
|
-
# #
|
25
|
-
# #
|
26
|
-
# #
|
27
|
-
# #
|
28
|
-
# #
|
29
|
-
# #
|
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
|
18
|
+
# # "active_side_id": 0,
|
19
|
+
# # "board": {
|
20
|
+
# # "3": "s",
|
21
|
+
# # "4": "k" ,
|
22
|
+
# # "5": "s",
|
23
|
+
# # "22": "+P",
|
24
|
+
# # "43": "+B"
|
25
|
+
# # },
|
26
|
+
# # "indexes": [9, 9],
|
27
|
+
# # "pieces_in_hand_grouped_by_sides": [
|
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]
|
41
30
|
# # ]
|
42
31
|
# # }
|
43
32
|
#
|
44
33
|
# @return [Hash] The position params representing the position.
|
45
34
|
def self.call(feen)
|
46
|
-
params(*feen.split(
|
35
|
+
params(*feen.split(" "))
|
47
36
|
end
|
48
37
|
|
49
38
|
# Parse the FEEN string's three fields and return the position params.
|
50
39
|
#
|
51
40
|
# @param board [String] The flatten board.
|
52
|
-
# @param
|
41
|
+
# @param active_side_id [String] The active side identifier.
|
53
42
|
# @param in_hand [String] The captured actors.
|
54
43
|
#
|
55
44
|
# @return [Hash] The position params representing the position.
|
56
|
-
private_class_method def self.params(board,
|
45
|
+
private_class_method def self.params(board, active_side_id, in_hand)
|
57
46
|
{
|
58
|
-
|
47
|
+
active_side_id: Turn.parse(active_side_id),
|
48
|
+
board: Board.new(board).to_h,
|
59
49
|
indexes: Shape.new(board).to_a,
|
60
|
-
|
61
|
-
squares: Board.new(board).to_a
|
50
|
+
pieces_in_hand_grouped_by_sides: PiecesInHand.parse(in_hand)
|
62
51
|
}
|
63
52
|
end
|
64
53
|
end
|
data/lib/feen/parser/board.rb
CHANGED
@@ -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.to_s.to_sym => 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
|
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
|
9
|
+
# @param pieces_in_hand_grouped_by_sides_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(
|
21
|
-
|
22
|
-
.split(
|
23
|
-
.map { |pieces_in_hand_str| pieces_in_hand_str.split(
|
20
|
+
def self.parse(pieces_in_hand_grouped_by_sides_str)
|
21
|
+
pieces_in_hand_grouped_by_sides_str
|
22
|
+
.split("/", -1)
|
23
|
+
.map { |pieces_in_hand_str| pieces_in_hand_str.split(",") }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/feen/parser/shape.rb
CHANGED
@@ -21,7 +21,7 @@ module FEEN
|
|
21
21
|
|
22
22
|
def indexes(string, separator)
|
23
23
|
if separator.empty?
|
24
|
-
last_index = string.split(
|
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
|
data/lib/feen/parser/turn.rb
CHANGED
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:
|
4
|
+
version: 2.0.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-
|
11
|
+
date: 2020-08-24 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
|