Class: PGN::Position

Inherits:
Object
  • Object
show all
Defined in:
lib/pgn/position.rb

Overview

Position encapsulates all of the information necessary to completely understand a chess position. It can be turned into a FEN string or perform a move.

Constant Summary collapse

PLAYERS =
%i[white black].freeze
CASTLING =
%w[K Q k q].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1) ⇒ Position

Returns a new instance of Position.

Examples:

PGN::Position.new(
  PGN::Board.start,
  :white,
)

Parameters:

  • board (PGN::Board)

    the board for the position

  • player (Symbol)

    the player who moves next

  • castling (Array<String>) (defaults to: CASTLING)

    the castling moves that are still available

  • en_passant (String, nil) (defaults to: nil)

    the en passant square if applicable

  • halfmove (Integer) (defaults to: 0)

    the number of halfmoves since the last pawn move or capture

  • fullmove (Integer) (defaults to: 1)

    the number of fullmoves made so far



65
66
67
68
69
70
71
72
# File 'lib/pgn/position.rb', line 65

def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
  self.board      = board
  self.player     = player
  self.castling   = castling
  self.en_passant = en_passant
  self.halfmove   = halfmove
  self.fullmove   = fullmove
end

Instance Attribute Details

#boardPGN::Board

Returns the board for the position.

Returns:



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pgn/position.rb', line 30

class Position
  PLAYERS  = %i[white black].freeze
  CASTLING = %w[K Q k q].freeze

  attr_accessor :board
  attr_accessor :player
  attr_accessor :castling
  attr_accessor :en_passant
  attr_accessor :halfmove
  attr_accessor :fullmove

  # @return [PGN::Position] the starting position of a chess game
  #
  def self.start
    PGN::Position.new(
      PGN::Board.start,
      PLAYERS.first
    )
  end

  # @param board [PGN::Board] the board for the position
  # @param player [Symbol] the player who moves next
  # @param castling [Array<String>] the castling moves that are still
  #   available
  # @param en_passant [String, nil] the en passant square if applicable
  # @param halfmove [Integer] the number of halfmoves since the last pawn
  #   move or capture
  # @param fullmove [Integer] the number of fullmoves made so far
  #
  # @example
  #   PGN::Position.new(
  #     PGN::Board.start,
  #     :white,
  #   )
  #
  def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
    self.board      = board
    self.player     = player
    self.castling   = castling
    self.en_passant = en_passant
    self.halfmove   = halfmove
    self.fullmove   = fullmove
  end

  # @param str [String] the move to make in SAN
  # @return [PGN::Position] the resulting position
  #
  # @example
  #   queens_pawn = PGN::Position.start.move("d4")
  #
  def move(str)
    move       = PGN::Move.new(str, player)
    calculator = PGN::MoveCalculator.new(board, move)

    new_castling = castling - calculator.castling_restrictions
    new_halfmove = if calculator.increment_halfmove?
                     halfmove + 1
                   else
                     0
                   end
    new_fullmove = if calculator.increment_fullmove?
                     fullmove + 1
                   else
                     fullmove
                   end
    no_move = str == '--'
    PGN::Position.new(
      no_move ? board : calculator.result_board,
      next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove
    )
  end

  # @return [Symbol] the next player to move
  #
  def next_player
    (PLAYERS - [player]).first
  end

  def inspect
    "\n" + board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board: board,
      active: player == :white ? 'w' : 'b',
      castling: castling.join(''),
      en_passant: en_passant,
      halfmove: halfmove.to_s,
      fullmove: fullmove.to_s
    )
  end
end

#castlingArray<String>

Returns the castling moves that are still available.

Examples:

position.castling #=> ["K", "k", "q"]

Returns:

  • (Array<String>)

    the castling moves that are still available



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pgn/position.rb', line 30

class Position
  PLAYERS  = %i[white black].freeze
  CASTLING = %w[K Q k q].freeze

  attr_accessor :board
  attr_accessor :player
  attr_accessor :castling
  attr_accessor :en_passant
  attr_accessor :halfmove
  attr_accessor :fullmove

  # @return [PGN::Position] the starting position of a chess game
  #
  def self.start
    PGN::Position.new(
      PGN::Board.start,
      PLAYERS.first
    )
  end

  # @param board [PGN::Board] the board for the position
  # @param player [Symbol] the player who moves next
  # @param castling [Array<String>] the castling moves that are still
  #   available
  # @param en_passant [String, nil] the en passant square if applicable
  # @param halfmove [Integer] the number of halfmoves since the last pawn
  #   move or capture
  # @param fullmove [Integer] the number of fullmoves made so far
  #
  # @example
  #   PGN::Position.new(
  #     PGN::Board.start,
  #     :white,
  #   )
  #
  def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
    self.board      = board
    self.player     = player
    self.castling   = castling
    self.en_passant = en_passant
    self.halfmove   = halfmove
    self.fullmove   = fullmove
  end

  # @param str [String] the move to make in SAN
  # @return [PGN::Position] the resulting position
  #
  # @example
  #   queens_pawn = PGN::Position.start.move("d4")
  #
  def move(str)
    move       = PGN::Move.new(str, player)
    calculator = PGN::MoveCalculator.new(board, move)

    new_castling = castling - calculator.castling_restrictions
    new_halfmove = if calculator.increment_halfmove?
                     halfmove + 1
                   else
                     0
                   end
    new_fullmove = if calculator.increment_fullmove?
                     fullmove + 1
                   else
                     fullmove
                   end
    no_move = str == '--'
    PGN::Position.new(
      no_move ? board : calculator.result_board,
      next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove
    )
  end

  # @return [Symbol] the next player to move
  #
  def next_player
    (PLAYERS - [player]).first
  end

  def inspect
    "\n" + board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board: board,
      active: player == :white ? 'w' : 'b',
      castling: castling.join(''),
      en_passant: en_passant,
      halfmove: halfmove.to_s,
      fullmove: fullmove.to_s
    )
  end
end

#en_passantString

Returns the en passant square if applicable.

Returns:

  • (String)

    the en passant square if applicable



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pgn/position.rb', line 30

class Position
  PLAYERS  = %i[white black].freeze
  CASTLING = %w[K Q k q].freeze

  attr_accessor :board
  attr_accessor :player
  attr_accessor :castling
  attr_accessor :en_passant
  attr_accessor :halfmove
  attr_accessor :fullmove

  # @return [PGN::Position] the starting position of a chess game
  #
  def self.start
    PGN::Position.new(
      PGN::Board.start,
      PLAYERS.first
    )
  end

  # @param board [PGN::Board] the board for the position
  # @param player [Symbol] the player who moves next
  # @param castling [Array<String>] the castling moves that are still
  #   available
  # @param en_passant [String, nil] the en passant square if applicable
  # @param halfmove [Integer] the number of halfmoves since the last pawn
  #   move or capture
  # @param fullmove [Integer] the number of fullmoves made so far
  #
  # @example
  #   PGN::Position.new(
  #     PGN::Board.start,
  #     :white,
  #   )
  #
  def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
    self.board      = board
    self.player     = player
    self.castling   = castling
    self.en_passant = en_passant
    self.halfmove   = halfmove
    self.fullmove   = fullmove
  end

  # @param str [String] the move to make in SAN
  # @return [PGN::Position] the resulting position
  #
  # @example
  #   queens_pawn = PGN::Position.start.move("d4")
  #
  def move(str)
    move       = PGN::Move.new(str, player)
    calculator = PGN::MoveCalculator.new(board, move)

    new_castling = castling - calculator.castling_restrictions
    new_halfmove = if calculator.increment_halfmove?
                     halfmove + 1
                   else
                     0
                   end
    new_fullmove = if calculator.increment_fullmove?
                     fullmove + 1
                   else
                     fullmove
                   end
    no_move = str == '--'
    PGN::Position.new(
      no_move ? board : calculator.result_board,
      next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove
    )
  end

  # @return [Symbol] the next player to move
  #
  def next_player
    (PLAYERS - [player]).first
  end

  def inspect
    "\n" + board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board: board,
      active: player == :white ? 'w' : 'b',
      castling: castling.join(''),
      en_passant: en_passant,
      halfmove: halfmove.to_s,
      fullmove: fullmove.to_s
    )
  end
end

#fullmoveInteger

Returns the number of fullmoves made so far.

Returns:

  • (Integer)

    the number of fullmoves made so far



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pgn/position.rb', line 30

class Position
  PLAYERS  = %i[white black].freeze
  CASTLING = %w[K Q k q].freeze

  attr_accessor :board
  attr_accessor :player
  attr_accessor :castling
  attr_accessor :en_passant
  attr_accessor :halfmove
  attr_accessor :fullmove

  # @return [PGN::Position] the starting position of a chess game
  #
  def self.start
    PGN::Position.new(
      PGN::Board.start,
      PLAYERS.first
    )
  end

  # @param board [PGN::Board] the board for the position
  # @param player [Symbol] the player who moves next
  # @param castling [Array<String>] the castling moves that are still
  #   available
  # @param en_passant [String, nil] the en passant square if applicable
  # @param halfmove [Integer] the number of halfmoves since the last pawn
  #   move or capture
  # @param fullmove [Integer] the number of fullmoves made so far
  #
  # @example
  #   PGN::Position.new(
  #     PGN::Board.start,
  #     :white,
  #   )
  #
  def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
    self.board      = board
    self.player     = player
    self.castling   = castling
    self.en_passant = en_passant
    self.halfmove   = halfmove
    self.fullmove   = fullmove
  end

  # @param str [String] the move to make in SAN
  # @return [PGN::Position] the resulting position
  #
  # @example
  #   queens_pawn = PGN::Position.start.move("d4")
  #
  def move(str)
    move       = PGN::Move.new(str, player)
    calculator = PGN::MoveCalculator.new(board, move)

    new_castling = castling - calculator.castling_restrictions
    new_halfmove = if calculator.increment_halfmove?
                     halfmove + 1
                   else
                     0
                   end
    new_fullmove = if calculator.increment_fullmove?
                     fullmove + 1
                   else
                     fullmove
                   end
    no_move = str == '--'
    PGN::Position.new(
      no_move ? board : calculator.result_board,
      next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove
    )
  end

  # @return [Symbol] the next player to move
  #
  def next_player
    (PLAYERS - [player]).first
  end

  def inspect
    "\n" + board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board: board,
      active: player == :white ? 'w' : 'b',
      castling: castling.join(''),
      en_passant: en_passant,
      halfmove: halfmove.to_s,
      fullmove: fullmove.to_s
    )
  end
end

#halfmoveInteger

Returns the number of halfmoves since the last pawn move or capture.

Returns:

  • (Integer)

    the number of halfmoves since the last pawn move or capture



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pgn/position.rb', line 30

class Position
  PLAYERS  = %i[white black].freeze
  CASTLING = %w[K Q k q].freeze

  attr_accessor :board
  attr_accessor :player
  attr_accessor :castling
  attr_accessor :en_passant
  attr_accessor :halfmove
  attr_accessor :fullmove

  # @return [PGN::Position] the starting position of a chess game
  #
  def self.start
    PGN::Position.new(
      PGN::Board.start,
      PLAYERS.first
    )
  end

  # @param board [PGN::Board] the board for the position
  # @param player [Symbol] the player who moves next
  # @param castling [Array<String>] the castling moves that are still
  #   available
  # @param en_passant [String, nil] the en passant square if applicable
  # @param halfmove [Integer] the number of halfmoves since the last pawn
  #   move or capture
  # @param fullmove [Integer] the number of fullmoves made so far
  #
  # @example
  #   PGN::Position.new(
  #     PGN::Board.start,
  #     :white,
  #   )
  #
  def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
    self.board      = board
    self.player     = player
    self.castling   = castling
    self.en_passant = en_passant
    self.halfmove   = halfmove
    self.fullmove   = fullmove
  end

  # @param str [String] the move to make in SAN
  # @return [PGN::Position] the resulting position
  #
  # @example
  #   queens_pawn = PGN::Position.start.move("d4")
  #
  def move(str)
    move       = PGN::Move.new(str, player)
    calculator = PGN::MoveCalculator.new(board, move)

    new_castling = castling - calculator.castling_restrictions
    new_halfmove = if calculator.increment_halfmove?
                     halfmove + 1
                   else
                     0
                   end
    new_fullmove = if calculator.increment_fullmove?
                     fullmove + 1
                   else
                     fullmove
                   end
    no_move = str == '--'
    PGN::Position.new(
      no_move ? board : calculator.result_board,
      next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove
    )
  end

  # @return [Symbol] the next player to move
  #
  def next_player
    (PLAYERS - [player]).first
  end

  def inspect
    "\n" + board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board: board,
      active: player == :white ? 'w' : 'b',
      castling: castling.join(''),
      en_passant: en_passant,
      halfmove: halfmove.to_s,
      fullmove: fullmove.to_s
    )
  end
end

#playerSymbol

Returns the player who moves next.

Examples:

position.player #=> :white

Returns:

  • (Symbol)

    the player who moves next



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pgn/position.rb', line 30

class Position
  PLAYERS  = %i[white black].freeze
  CASTLING = %w[K Q k q].freeze

  attr_accessor :board
  attr_accessor :player
  attr_accessor :castling
  attr_accessor :en_passant
  attr_accessor :halfmove
  attr_accessor :fullmove

  # @return [PGN::Position] the starting position of a chess game
  #
  def self.start
    PGN::Position.new(
      PGN::Board.start,
      PLAYERS.first
    )
  end

  # @param board [PGN::Board] the board for the position
  # @param player [Symbol] the player who moves next
  # @param castling [Array<String>] the castling moves that are still
  #   available
  # @param en_passant [String, nil] the en passant square if applicable
  # @param halfmove [Integer] the number of halfmoves since the last pawn
  #   move or capture
  # @param fullmove [Integer] the number of fullmoves made so far
  #
  # @example
  #   PGN::Position.new(
  #     PGN::Board.start,
  #     :white,
  #   )
  #
  def initialize(board, player, castling = CASTLING, en_passant = nil, halfmove = 0, fullmove = 1)
    self.board      = board
    self.player     = player
    self.castling   = castling
    self.en_passant = en_passant
    self.halfmove   = halfmove
    self.fullmove   = fullmove
  end

  # @param str [String] the move to make in SAN
  # @return [PGN::Position] the resulting position
  #
  # @example
  #   queens_pawn = PGN::Position.start.move("d4")
  #
  def move(str)
    move       = PGN::Move.new(str, player)
    calculator = PGN::MoveCalculator.new(board, move)

    new_castling = castling - calculator.castling_restrictions
    new_halfmove = if calculator.increment_halfmove?
                     halfmove + 1
                   else
                     0
                   end
    new_fullmove = if calculator.increment_fullmove?
                     fullmove + 1
                   else
                     fullmove
                   end
    no_move = str == '--'
    PGN::Position.new(
      no_move ? board : calculator.result_board,
      next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove
    )
  end

  # @return [Symbol] the next player to move
  #
  def next_player
    (PLAYERS - [player]).first
  end

  def inspect
    "\n" + board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board: board,
      active: player == :white ? 'w' : 'b',
      castling: castling.join(''),
      en_passant: en_passant,
      halfmove: halfmove.to_s,
      fullmove: fullmove.to_s
    )
  end
end

Class Method Details

.startPGN::Position

Returns the starting position of a chess game.

Returns:



43
44
45
46
47
48
# File 'lib/pgn/position.rb', line 43

def self.start
  PGN::Position.new(
    PGN::Board.start,
    PLAYERS.first
  )
end

Instance Method Details

#inspectObject



112
113
114
# File 'lib/pgn/position.rb', line 112

def inspect
  "\n" + board.inspect
end

#move(str) ⇒ PGN::Position

Returns the resulting position.

Examples:

queens_pawn = PGN::Position.start.move("d4")

Parameters:

  • str (String)

    the move to make in SAN

Returns:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/pgn/position.rb', line 80

def move(str)
  move       = PGN::Move.new(str, player)
  calculator = PGN::MoveCalculator.new(board, move)

  new_castling = castling - calculator.castling_restrictions
  new_halfmove = if calculator.increment_halfmove?
                   halfmove + 1
                 else
                   0
                 end
  new_fullmove = if calculator.increment_fullmove?
                   fullmove + 1
                 else
                   fullmove
                 end
  no_move = str == '--'
  PGN::Position.new(
    no_move ? board : calculator.result_board,
    next_player,
    new_castling,
    calculator.en_passant_square,
    new_halfmove,
    new_fullmove
  )
end

#next_playerSymbol

Returns the next player to move.

Returns:

  • (Symbol)

    the next player to move



108
109
110
# File 'lib/pgn/position.rb', line 108

def next_player
  (PLAYERS - [player]).first
end

#to_fenPGN::FEN

Returns a FEN object representing the current position.

Returns:

  • (PGN::FEN)

    a FEN object representing the current position



118
119
120
121
122
123
124
125
126
127
# File 'lib/pgn/position.rb', line 118

def to_fen
  PGN::FEN.from_attributes(
    board: board,
    active: player == :white ? 'w' : 'b',
    castling: castling.join(''),
    en_passant: en_passant,
    halfmove: halfmove.to_s,
    fullmove: fullmove.to_s
  )
end