sashite-feen 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8182f6c48f6a615f38d75d3060f216c06c6606b118544cb4f4f0e40b9615e89
4
- data.tar.gz: 1150aacab981e71aa32aaae585ec1998cd678bb5997432135b0089394eef2482
3
+ metadata.gz: 6b244edf5ff22990c8ad8e4e866e866191b64836f984916f1342084b17d70cb7
4
+ data.tar.gz: a61e40e9f447f988f91382209985421608895d160f5d43b5892fd21c53f93e67
5
5
  SHA512:
6
- metadata.gz: b8ed4a473fce336ce73cb89c684e9ea7820842b78e12766bc32440f25da7f61998c13077ce3743972ef234a85771c63f58778835dd11bfba1fd97ef63dfb7154
7
- data.tar.gz: 679296955c3b032e0ebe7b9f6ca4776b42b617f67a876e5de6bee015d186e40287d9cc964a3bb2d3faec0dbaf0dd98d810e3bf522cde197d340f168ba9be3a84
6
+ metadata.gz: 5cf29b74cb4e1dc5ff0ede275fcf56af3476ef01eaf045c118aa086ae688df6122a685d97ca4dbbfb4bbe0956f1a19e0ee73d157c0148ca6baffd67d278f06ef
7
+ data.tar.gz: fb2b2e4ad688be264f031b61434d8f8cf513733b3894547f2053d46762c62144a5ba727a39bffc48f4de17cd42b362bfc19fd45bda249b654f6a90462355e6b1
data/README.md CHANGED
@@ -5,11 +5,11 @@
5
5
  ![Ruby](https://github.com/sashite/feen.rb/actions/workflows/main.yml/badge.svg?branch=main)
6
6
  [![License](https://img.shields.io/github/license/sashite/feen.rb?label=License&logo=github)](https://github.com/sashite/feen.rb/raw/main/LICENSE.md)
7
7
 
8
- > **FEEN** (Forsyth–Edwards Enhanced Notation) implementation for the Ruby language.
8
+ > **FEEN** (Field Expression Encoding Notation) implementation for the Ruby language.
9
9
 
10
10
  ## What is FEEN?
11
11
 
12
- FEEN (Forsyth–Edwards Enhanced Notation) is a universal, rule-agnostic notation for representing board game positions. It extends traditional FEN to support:
12
+ FEEN (Field Expression Encoding Notation) is a universal, rule-agnostic notation for representing board game positions. It extends traditional FEN to support:
13
13
 
14
14
  - **Multiple game systems** (Chess, Shōgi, Xiangqi, and more)
15
15
  - **Cross-style games** where players use different piece sets
@@ -39,7 +39,7 @@ gem install sashite-feen
39
39
  require "sashite/feen"
40
40
 
41
41
  # Parse a FEEN string into an immutable position object
42
- position = Sashite::Feen.parse("+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c")
42
+ position = Sashite::Feen.parse("+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c")
43
43
 
44
44
  # Access position components
45
45
  position.placement # Board configuration
@@ -63,7 +63,7 @@ A FEEN string consists of three space-separated fields:
63
63
 
64
64
  **Example:**
65
65
  ```txt
66
- +rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c
66
+ +rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c
67
67
  ```
68
68
 
69
69
  1. **Piece placement**: Board configuration using EPIN notation with `/` separators (can be empty for board-less positions)
@@ -145,16 +145,16 @@ The `to_a` method returns an array representation that adapts to the board's dim
145
145
 
146
146
  ```ruby
147
147
  # 1D board - Returns flat array
148
- feen = "K2P3k / C/c"
148
+ feen = "K^2P3k^ / C/c"
149
149
  position = Sashite::Feen.parse(feen)
150
150
  position.placement.to_a
151
151
  # => [K, nil, nil, P, nil, nil, nil, k]
152
152
 
153
153
  # 2D board - Returns array of arrays
154
- feen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR / C/c"
154
+ feen = "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
155
155
  position = Sashite::Feen.parse(feen)
156
156
  position.placement.to_a
157
- # => [[r,n,b,q,k,b,n,r], [p,p,p,p,p,p,p,p], [nil×8], ...]
157
+ # => [[+r,n,b,q,+k^,b,n,+r], [+p,+p,+p,+p,+p,+p,+p,+p], [nil×8], ...]
158
158
 
159
159
  # 3D board - Returns array of ranks (to be structured by application)
160
160
  feen = "5/5//5/5 / R/r"
@@ -229,17 +229,17 @@ styles.active.to_s.upcase != styles.inactive.to_s.upcase
229
229
  ```ruby
230
230
  # Starting position
231
231
  chess_start = Sashite::Feen.parse(
232
- "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c"
232
+ "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
233
233
  )
234
234
 
235
235
  # After 1.e4
236
236
  after_e4 = Sashite::Feen.parse(
237
- "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/4P3/8/+P+P+P+P1+P+P+P/+RNBQ+KBN+R / c/C"
237
+ "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/4P3/8/+P+P+P+P1+P+P+P/+RNBQ+K^BN+R / c/C"
238
238
  )
239
239
 
240
240
  # Ruy Lopez opening
241
241
  ruy_lopez = Sashite::Feen.parse(
242
- "r1bqkbnr/+p+p+p+p1+p+p+p/2n5/1B2p3/4P3/5N2/+P+P+P+P1+P+P+P/RNBQK2R / c/C"
242
+ "+r1bq+k^bn+r/+p+p+p+p1+p+p+p/2n5/1B2p3/4P3/5N2/+P+P+P+P1+P+P+P/+RNBQ+K^2+R / c/C"
243
243
  )
244
244
  ```
245
245
 
@@ -248,12 +248,12 @@ ruy_lopez = Sashite::Feen.parse(
248
248
  ```ruby
249
249
  # Starting position
250
250
  shogi_start = Sashite::Feen.parse(
251
- "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL / S/s"
251
+ "lnsgk^gsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGK^GSNL / S/s"
252
252
  )
253
253
 
254
254
  # Position with pieces in hand
255
255
  shogi_midgame = Sashite::Feen.parse(
256
- "lnsgkgsnl/1r5b1/pppp1pppp/9/4p4/9/PPPP1PPPP/1B5R1/LNSGKGSNL P/p s/S"
256
+ "lnsgk^gsnl/1r5b1/pppp1pppp/9/4p4/9/PPPP1PPPP/1B5R1/LNSGK^GSNL P/p s/S"
257
257
  )
258
258
 
259
259
  # Access captured pieces
@@ -270,12 +270,12 @@ position.hands.first_player.count { |p| p.to_s == "P" } # => 1
270
270
  ```ruby
271
271
  # Chess vs Makruk
272
272
  chess_vs_makruk = Sashite::Feen.parse(
273
- "rnsmksnr/8/pppppppp/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/m"
273
+ "rnsmk^snr/8/pppppppp/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/m"
274
274
  )
275
275
 
276
276
  # Chess vs Shōgi
277
277
  chess_vs_shogi = Sashite::Feen.parse(
278
- "lnsgkgsnl/1r5b1/pppppppp/9/9/9/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/s"
278
+ "lnsgk^gsnl/1r5b1/pppppppp/9/9/9/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/s"
279
279
  )
280
280
 
281
281
  # Check styles
@@ -289,7 +289,7 @@ position.styles.inactive.to_s # => "m" (Makruk, second player)
289
289
  ```ruby
290
290
  # 3D Chess (Raumschach)
291
291
  raumschach = Sashite::Feen.parse(
292
- "rnknr/+p+p+p+p+p/5/5/5//buqbu/+p+p+p+p+p/5/5/5//5/5/5/5/5//5/5/5/+P+P+P+P+P/BUQBU//5/5/5/+P+P+P+P+P/RNKNR / R/r"
292
+ "+rn+k^n+r/+p+p+p+p+p/5/5/5//buqbu/+p+p+p+p+p/5/5/5//5/5/5/5/5//5/5/5/+P+P+P+P+P/BUQBU//5/5/5/+P+P+P+P+P/+RN+K^N+R / R/r"
293
293
  )
294
294
 
295
295
  # Check dimensionality
@@ -317,7 +317,7 @@ large_board = Sashite::Feen.parse("100/100/100 / G/g")
317
317
  large_board.placement.total_squares # => 300
318
318
 
319
319
  # Single square
320
- single = Sashite::Feen.parse("K / C/c")
320
+ single = Sashite::Feen.parse("K^ / C/c")
321
321
  single.placement.rank_count # => 1
322
322
  ```
323
323
 
@@ -327,7 +327,7 @@ FEEN supports any valid combination of ranks and separators:
327
327
 
328
328
  ```ruby
329
329
  # Extreme irregularity with variable separators
330
- feen = "99999/3///K/k//r / G/g"
330
+ feen = "99999/3///K^/k^//r / G/g"
331
331
  position = Sashite::Feen.parse(feen)
332
332
 
333
333
  # Access the structure
@@ -352,11 +352,11 @@ FEEN supports empty ranks (ranks with no pieces):
352
352
 
353
353
  ```ruby
354
354
  # Trailing separator creates empty rank
355
- feen = "K/// / C/c"
355
+ feen = "K^/// / C/c"
356
356
  position = Sashite::Feen.parse(feen)
357
357
 
358
358
  position.placement.ranks.size # => 2
359
- position.placement.ranks[0] # => [K]
359
+ position.placement.ranks[0] # => [K^]
360
360
  position.placement.ranks[1] # => [] (empty rank)
361
361
  position.placement.separators # => ["///"]
362
362
 
@@ -389,7 +389,7 @@ position2 = Sashite::Feen.parse("8/8/8/8/8/8/8/8 / C/c")
389
389
  position1 == position2 # => true
390
390
 
391
391
  # Round-trip parsing
392
- original = "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c"
392
+ original = "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
393
393
  position = Sashite::Feen.parse(original)
394
394
  Sashite::Feen.dump(position) == original # => true
395
395
 
@@ -402,13 +402,13 @@ position.hands.first_player.size # Number of captured pieces
402
402
 
403
403
  ```ruby
404
404
  # Enhanced pieces (promoted, with special rights)
405
- enhanced = Sashite::Feen.parse("+K+Q+R+B/8/8/8/8/8/8/8 / C/c")
405
+ enhanced = Sashite::Feen.parse("+K^+Q+R+B/8/8/8/8/8/8/8 / C/c")
406
406
 
407
407
  # Diminished pieces (weakened, vulnerable)
408
- diminished = Sashite::Feen.parse("-K-Q-R-B/8/8/8/8/8/8/8 / C/c")
408
+ diminished = Sashite::Feen.parse("-K^-Q-R-B/8/8/8/8/8/8/8 / C/c")
409
409
 
410
410
  # Foreign pieces (using opponent's style)
411
- foreign = Sashite::Feen.parse("K'Q'R'B'/k'q'r'b'/8/8/8/8/8/8 / C/s")
411
+ foreign = Sashite::Feen.parse("K^'Q'R'B'/k^'q'r'b'/8/8/8/8/8/8 / C/s")
412
412
  ```
413
413
 
414
414
  ## Error Handling
@@ -29,7 +29,7 @@ module Sashite
29
29
  #
30
30
  # @example Chess starting position
31
31
  # dump(placement)
32
- # # => "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R"
32
+ # # => "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R"
33
33
  #
34
34
  # @example Empty 8x8 board
35
35
  # dump(placement)
@@ -37,7 +37,7 @@ module Sashite
37
37
  #
38
38
  # @example 1D board
39
39
  # dump(placement)
40
- # # => "K2P3k"
40
+ # # => "K^2P3k^"
41
41
  #
42
42
  # @example Irregular 3D board
43
43
  # dump(placement)
@@ -6,7 +6,7 @@ require_relative "dumper/style_turn"
6
6
 
7
7
  module Sashite
8
8
  module Feen
9
- # Dumper for FEEN (Forsyth–Edwards Enhanced Notation) positions.
9
+ # Dumper for FEEN (Field Expression Encoding Notation) positions.
10
10
  #
11
11
  # Converts a Position object into its canonical FEEN string representation
12
12
  # by delegating serialization to specialized dumpers for each component.
@@ -29,7 +29,7 @@ module Sashite
29
29
  #
30
30
  # @example Dump a position to FEEN
31
31
  # feen_string = Dumper.dump(position)
32
- # # => "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c"
32
+ # # => "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
33
33
  def self.dump(position)
34
34
  fields = [
35
35
  Dumper::PiecePlacement.dump(position.placement),
@@ -49,8 +49,8 @@ module Sashite
49
49
  # @return [String] Complete FEEN string
50
50
  #
51
51
  # @example Join three fields
52
- # join_fields(["rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR", "/", "C/c"])
53
- # # => "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR / C/c"
52
+ # join_fields(["+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R", "/", "C/c"])
53
+ # # => "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
54
54
  private_class_method def self.join_fields(fields)
55
55
  fields.join(FIELD_SEPARATOR)
56
56
  end
@@ -24,9 +24,6 @@ module Sashite
24
24
  # Rank separator character.
25
25
  RANK_SEPARATOR = "/"
26
26
 
27
- # Pattern to match EPIN pieces (optional state, letter, optional derivation).
28
- EPIN_PATTERN = /\A[-+]?[A-Za-z]'?\z/
29
-
30
27
  # Parse a FEEN piece placement string into a Placement object.
31
28
  #
32
29
  # Supports any valid FEEN structure:
@@ -265,10 +262,11 @@ module Sashite
265
262
 
266
263
  # Extract EPIN notation from character array.
267
264
  #
268
- # EPIN format: [state][letter][derivation]
265
+ # EPIN format: [state][letter][terminal][derivation]
269
266
  # - state: optional "+" or "-" prefix
270
267
  # - letter: required A-Z or a-z
271
- # - derivation: optional "'" suffix
268
+ # - terminal: optional "^" suffix
269
+ # - derivation: optional "'" suffix (comes after "^" if both are present)
272
270
  #
273
271
  # @param chars [Array<String>] Array of characters
274
272
  # @param start_index [Integer] Starting index
@@ -284,6 +282,12 @@ module Sashite
284
282
  # @example Foreign piece
285
283
  # extract_epin(['K', "'", 'Q'], 0) # => ["K'", 2]
286
284
  #
285
+ # @example Terminal piece
286
+ # extract_epin(['K', '^', 'Q'], 0) # => ["K^", 2]
287
+ #
288
+ # @example Foreign terminal piece
289
+ # extract_epin(['K', '^', "'", 'Q'], 0) # => ["K^'", 3]
290
+ #
287
291
  # @example Complex piece
288
292
  # extract_epin(['-', 'p', "'", 'K'], 0) # => ["-p'", 3]
289
293
  private_class_method def self.extract_epin(chars, start_index)
@@ -305,6 +309,12 @@ module Sashite
305
309
  piece_chars << chars[i]
306
310
  i += 1
307
311
 
312
+ # Optional terminal suffix (^)
313
+ if i < chars.size && chars[i] == "^"
314
+ piece_chars << chars[i]
315
+ i += 1
316
+ end
317
+
308
318
  # Optional derivation suffix (')
309
319
  if i < chars.size && chars[i] == "'"
310
320
  piece_chars << chars[i]
@@ -312,7 +322,7 @@ module Sashite
312
322
  end
313
323
 
314
324
  piece_str = piece_chars.join
315
- consumed = i - start_index
325
+ consumed = i - start_index
316
326
 
317
327
  [piece_str, consumed]
318
328
  end
@@ -342,7 +352,7 @@ module Sashite
342
352
  # parse_piece("X#") # => raises Error::Piece
343
353
  private_class_method def self.parse_piece(epin_str)
344
354
  # Pre-validate format
345
- unless EPIN_PATTERN.match?(epin_str)
355
+ unless ::Sashite::Epin.valid?(epin_str)
346
356
  raise ::Sashite::Feen::Error::Piece,
347
357
  "Invalid EPIN notation: #{epin_str}"
348
358
  end
@@ -9,7 +9,7 @@ require_relative "position"
9
9
 
10
10
  module Sashite
11
11
  module Feen
12
- # Parser for FEEN (Forsyth–Edwards Enhanced Notation) strings.
12
+ # Parser for FEEN (Field Expression Encoding Notation) strings.
13
13
  #
14
14
  # Parses a complete FEEN string by splitting it into three space-separated
15
15
  # fields and delegating parsing to specialized parsers for each component.
@@ -32,7 +32,7 @@ module Sashite
32
32
  # placement = Placement.new(ranks, separators)
33
33
  #
34
34
  # @example Highly irregular structure
35
- # # "99999/3///K/k//r"
35
+ # # "99999/3///K^/k^//r"
36
36
  # ranks = [[nil]*99999, [nil]*3, [king], [king_b], [rook]]
37
37
  # separators = ["/", "///", "/", "//"]
38
38
  # placement = Placement.new(ranks, separators)
@@ -169,7 +169,7 @@ module Sashite
169
169
  #
170
170
  # @example
171
171
  # placement.to_s
172
- # # => "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R"
172
+ # # => "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R"
173
173
  def to_s
174
174
  Dumper::PiecePlacement.dump(self)
175
175
  end
@@ -29,7 +29,7 @@ module Sashite
29
29
  # position = Position.new(placement, hands, styles)
30
30
  #
31
31
  # @example Parse from FEEN string
32
- # position = Sashite::Feen.parse("+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c")
32
+ # position = Sashite::Feen.parse("+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c")
33
33
  def initialize(placement, hands, styles)
34
34
  @placement = placement
35
35
  @hands = hands
@@ -48,7 +48,7 @@ module Sashite
48
48
  #
49
49
  # @example
50
50
  # position.to_s
51
- # # => "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c"
51
+ # # => "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
52
52
  def to_s
53
53
  Dumper.dump(self)
54
54
  end
data/lib/sashite/feen.rb CHANGED
@@ -4,7 +4,7 @@ require_relative "feen/dumper"
4
4
  require_relative "feen/parser"
5
5
 
6
6
  module Sashite
7
- # FEEN (Forsyth–Edwards Enhanced Notation) module provides parsing and dumping
7
+ # FEEN (Field Expression Encoding Notation) module provides parsing and dumping
8
8
  # functionality for board game positions.
9
9
  #
10
10
  # FEEN is a universal, rule-agnostic notation for representing board game positions.
@@ -29,10 +29,10 @@ module Sashite
29
29
  #
30
30
  # @example Dump a position to FEEN
31
31
  # feen_string = Sashite::Feen.dump(position)
32
- # # => "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c"
32
+ # # => "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
33
33
  #
34
34
  # @example Round-trip parsing and dumping
35
- # original = "+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c"
35
+ # original = "+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c"
36
36
  # position = Sashite::Feen.parse(original)
37
37
  # Sashite::Feen.dump(position) == original # => true
38
38
  def self.dump(position)
@@ -53,13 +53,13 @@ module Sashite
53
53
  # @raise [Error::Validation] For other semantic violations
54
54
  #
55
55
  # @example Parse a chess starting position
56
- # position = Sashite::Feen.parse("+rnbq+kbn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+KBN+R / C/c")
56
+ # position = Sashite::Feen.parse("+rnbq+k^bn+r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/+RNBQ+K^BN+R / C/c")
57
57
  # position.placement # => Placement object (board configuration)
58
58
  # position.hands # => Hands object (pieces in hand)
59
59
  # position.styles # => Styles object (style-turn information)
60
60
  #
61
61
  # @example Parse a shogi position with captured pieces
62
- # position = Sashite::Feen.parse("lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL P/p S/s")
62
+ # position = Sashite::Feen.parse("lnsgk^gsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGK^GSNL P/p S/s")
63
63
  def self.parse(string)
64
64
  Parser.parse(string)
65
65
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sashite-feen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
@@ -15,30 +15,30 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '1.1'
18
+ version: 2.0.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '1.1'
25
+ version: 2.0.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: sashite-sin
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '2.1'
32
+ version: 2.1.0
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2.1'
39
+ version: 2.1.0
40
40
  description: |
41
- FEEN (Forsyth—Edwards Enhanced Notation) provides a universal, rule-agnostic format for
41
+ FEEN (Field Expression Encoding Notation) provides a universal, rule-agnostic format for
42
42
  representing board game positions. This gem implements the FEEN Specification v1.0.0 with
43
43
  a modern Ruby interface featuring immutable position objects and functional programming
44
44
  principles. FEEN extends traditional FEN notation to support multiple game systems (chess,
@@ -93,8 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  requirements: []
96
- rubygems_version: 3.7.1
96
+ rubygems_version: 3.7.2
97
97
  specification_version: 4
98
- summary: FEEN (Forsyth—Edwards Enhanced Notation) implementation for Ruby with universal
98
+ summary: FEEN (Field Expression Encoding Notation) implementation for Ruby with universal
99
99
  position representation
100
100
  test_files: []