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 =
[:white, :black]
CASTLING =
%w{K Q k q}

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



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

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:



29
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
# File 'lib/pgn/position.rb', line 29

class Position
  PLAYERS  = [:white, :black]
  CASTLING = %w{K Q k q}

  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, self.player)
    calculator = PGN::MoveCalculator.new(self.board, move)

    new_castling = self.castling - calculator.castling_restrictions
    new_halfmove = calculator.increment_halfmove? ?
      self.halfmove + 1 :
      0
    new_fullmove = calculator.increment_fullmove? ?
      self.fullmove + 1 :
      self.fullmove

    PGN::Position.new(
      calculator.result_board,
      self.next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove,
    )
  end

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

  def inspect
    "\n" + self.board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board:      self.board,
      active:     self.player == :white ? 'w' : 'b',
      castling:   self.castling.join(''),
      en_passant: self.en_passant,
      halfmove:   self.halfmove.to_s,
      fullmove:   self.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



29
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
# File 'lib/pgn/position.rb', line 29

class Position
  PLAYERS  = [:white, :black]
  CASTLING = %w{K Q k q}

  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, self.player)
    calculator = PGN::MoveCalculator.new(self.board, move)

    new_castling = self.castling - calculator.castling_restrictions
    new_halfmove = calculator.increment_halfmove? ?
      self.halfmove + 1 :
      0
    new_fullmove = calculator.increment_fullmove? ?
      self.fullmove + 1 :
      self.fullmove

    PGN::Position.new(
      calculator.result_board,
      self.next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove,
    )
  end

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

  def inspect
    "\n" + self.board.inspect
  end

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

end

#en_passantString

Returns the en passant square if applicable.

Returns:

  • (String)

    the en passant square if applicable



29
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
# File 'lib/pgn/position.rb', line 29

class Position
  PLAYERS  = [:white, :black]
  CASTLING = %w{K Q k q}

  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, self.player)
    calculator = PGN::MoveCalculator.new(self.board, move)

    new_castling = self.castling - calculator.castling_restrictions
    new_halfmove = calculator.increment_halfmove? ?
      self.halfmove + 1 :
      0
    new_fullmove = calculator.increment_fullmove? ?
      self.fullmove + 1 :
      self.fullmove

    PGN::Position.new(
      calculator.result_board,
      self.next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove,
    )
  end

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

  def inspect
    "\n" + self.board.inspect
  end

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

end

#fullmoveInteger

Returns the number of fullmoves made so far.

Returns:

  • (Integer)

    the number of fullmoves made so far



29
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
# File 'lib/pgn/position.rb', line 29

class Position
  PLAYERS  = [:white, :black]
  CASTLING = %w{K Q k q}

  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, self.player)
    calculator = PGN::MoveCalculator.new(self.board, move)

    new_castling = self.castling - calculator.castling_restrictions
    new_halfmove = calculator.increment_halfmove? ?
      self.halfmove + 1 :
      0
    new_fullmove = calculator.increment_fullmove? ?
      self.fullmove + 1 :
      self.fullmove

    PGN::Position.new(
      calculator.result_board,
      self.next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove,
    )
  end

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

  def inspect
    "\n" + self.board.inspect
  end

  # @return [PGN::FEN] a {PGN::FEN} object representing the current position
  #
  def to_fen
    PGN::FEN.from_attributes(
      board:      self.board,
      active:     self.player == :white ? 'w' : 'b',
      castling:   self.castling.join(''),
      en_passant: self.en_passant,
      halfmove:   self.halfmove.to_s,
      fullmove:   self.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



29
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
# File 'lib/pgn/position.rb', line 29

class Position
  PLAYERS  = [:white, :black]
  CASTLING = %w{K Q k q}

  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, self.player)
    calculator = PGN::MoveCalculator.new(self.board, move)

    new_castling = self.castling - calculator.castling_restrictions
    new_halfmove = calculator.increment_halfmove? ?
      self.halfmove + 1 :
      0
    new_fullmove = calculator.increment_fullmove? ?
      self.fullmove + 1 :
      self.fullmove

    PGN::Position.new(
      calculator.result_board,
      self.next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove,
    )
  end

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

  def inspect
    "\n" + self.board.inspect
  end

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

end

#playerSymbol

Returns the player who moves next.

Examples:

position.player #=> :white

Returns:

  • (Symbol)

    the player who moves next



29
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
# File 'lib/pgn/position.rb', line 29

class Position
  PLAYERS  = [:white, :black]
  CASTLING = %w{K Q k q}

  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, self.player)
    calculator = PGN::MoveCalculator.new(self.board, move)

    new_castling = self.castling - calculator.castling_restrictions
    new_halfmove = calculator.increment_halfmove? ?
      self.halfmove + 1 :
      0
    new_fullmove = calculator.increment_fullmove? ?
      self.fullmove + 1 :
      self.fullmove

    PGN::Position.new(
      calculator.result_board,
      self.next_player,
      new_castling,
      calculator.en_passant_square,
      new_halfmove,
      new_fullmove,
    )
  end

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

  def inspect
    "\n" + self.board.inspect
  end

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

end

Class Method Details

.startPGN::Position

Returns the starting position of a chess game.

Returns:



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

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

Instance Method Details

#inspectObject



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

def inspect
  "\n" + self.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:



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

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

  new_castling = self.castling - calculator.castling_restrictions
  new_halfmove = calculator.increment_halfmove? ?
    self.halfmove + 1 :
    0
  new_fullmove = calculator.increment_fullmove? ?
    self.fullmove + 1 :
    self.fullmove

  PGN::Position.new(
    calculator.result_board,
    self.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



103
104
105
# File 'lib/pgn/position.rb', line 103

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

#to_fenPGN::FEN

Returns a FEN object representing the current position.

Returns:

  • (PGN::FEN)

    a FEN object representing the current position



113
114
115
116
117
118
119
120
121
122
# File 'lib/pgn/position.rb', line 113

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