just_shogi 0.1.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/CODE_OF_CONDUCT.md +74 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +24 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +80 -0
  8. data/Rakefile +10 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/just_shogi.gemspec +29 -0
  12. data/lib/just_shogi.rb +8 -0
  13. data/lib/just_shogi/errors/causes_check_error.rb +22 -0
  14. data/lib/just_shogi/errors/dropped_into_check_error.rb +22 -0
  15. data/lib/just_shogi/errors/error.rb +20 -0
  16. data/lib/just_shogi/errors/invalid_move_error.rb +22 -0
  17. data/lib/just_shogi/errors/invalid_promotion_error.rb +22 -0
  18. data/lib/just_shogi/errors/moved_into_check_error.rb +22 -0
  19. data/lib/just_shogi/errors/no_piece_error.rb +22 -0
  20. data/lib/just_shogi/errors/not_players_turn_error.rb +22 -0
  21. data/lib/just_shogi/errors/off_board_error.rb +22 -0
  22. data/lib/just_shogi/errors/piece_not_found_error.rb +22 -0
  23. data/lib/just_shogi/errors/square_occupied_error.rb +22 -0
  24. data/lib/just_shogi/game_state.rb +355 -0
  25. data/lib/just_shogi/hand.rb +48 -0
  26. data/lib/just_shogi/piece_factory.rb +87 -0
  27. data/lib/just_shogi/pieces/fuhyou.rb +23 -0
  28. data/lib/just_shogi/pieces/ginshou.rb +23 -0
  29. data/lib/just_shogi/pieces/gyokushou.rb +9 -0
  30. data/lib/just_shogi/pieces/hisha.rb +23 -0
  31. data/lib/just_shogi/pieces/kakugyou.rb +23 -0
  32. data/lib/just_shogi/pieces/keima.rb +23 -0
  33. data/lib/just_shogi/pieces/kin_base.rb +23 -0
  34. data/lib/just_shogi/pieces/kinshou.rb +9 -0
  35. data/lib/just_shogi/pieces/kyousha.rb +23 -0
  36. data/lib/just_shogi/pieces/narigin.rb +9 -0
  37. data/lib/just_shogi/pieces/narikei.rb +9 -0
  38. data/lib/just_shogi/pieces/narikyou.rb +9 -0
  39. data/lib/just_shogi/pieces/ou_base.rb +70 -0
  40. data/lib/just_shogi/pieces/oushou.rb +9 -0
  41. data/lib/just_shogi/pieces/piece.rb +18 -0
  42. data/lib/just_shogi/pieces/ryuuma.rb +23 -0
  43. data/lib/just_shogi/pieces/ryuuou.rb +23 -0
  44. data/lib/just_shogi/pieces/tokin.rb +9 -0
  45. data/lib/just_shogi/promotion_factory.rb +71 -0
  46. data/lib/just_shogi/square.rb +51 -0
  47. data/lib/just_shogi/square_set.rb +64 -0
  48. data/lib/just_shogi/version.rb +3 -0
  49. metadata +147 -0
@@ -0,0 +1,18 @@
1
+ require 'board_game_grid'
2
+
3
+ module JustShogi
4
+
5
+ # = Piece
6
+ #
7
+ # A piece that can move on a chess board
8
+ class Piece < BoardGameGrid::Piece
9
+ def initialize(id: , player_number: , type: nil)
10
+ @id = id
11
+ @player_number = player_number
12
+ end
13
+
14
+ def switch_player
15
+ @player_number = opponent
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require 'just_shogi/pieces/piece'
2
+
3
+ module JustShogi
4
+
5
+ # = Ryuuma
6
+ #
7
+ # The piece that moves diagonally any number of squares and 1 space orthogonally
8
+ class Ryuuma < Piece
9
+
10
+ # All the squares that the piece can move to and/or capture.
11
+ #
12
+ # @param [Square] square
13
+ # the origin square.
14
+ #
15
+ # @param [GameState] game_state
16
+ # the current game state.
17
+ #
18
+ # @return [SquareSet]
19
+ def destinations(square, game_state)
20
+ (game_state.squares.diagonal(square) | game_state.squares.at_range(square, 1)).unoccupied_or_occupied_by_opponent(player_number).unblocked(square, game_state.squares)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'just_shogi/pieces/piece'
2
+
3
+ module JustShogi
4
+
5
+ # = Ryuuou
6
+ #
7
+ # The piece that moves any number of squares orthogonally and 1 space diagonally.
8
+ class Ryuuou < Piece
9
+
10
+ # All the squares that the piece can move to and/or capture.
11
+ #
12
+ # @param [Square] square
13
+ # the origin square.
14
+ #
15
+ # @param [GameState] game_state
16
+ # the current game state.
17
+ #
18
+ # @return [SquareSet]
19
+ def destinations(square, game_state)
20
+ (game_state.squares.orthogonal(square) | game_state.squares.at_range(square, 1)).unoccupied_or_occupied_by_opponent(player_number).unblocked(square, game_state.squares)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ require 'just_shogi/pieces/kin_base'
2
+
3
+ module JustShogi
4
+
5
+ # = Tokin
6
+ #
7
+ # The piece that can move 1 space orthogonally or forwards diagonally
8
+ class Tokin < KinBase; end
9
+ end
@@ -0,0 +1,71 @@
1
+ require 'just_shogi/pieces/fuhyou'
2
+ require 'just_shogi/pieces/kakugyou'
3
+ require 'just_shogi/pieces/hisha'
4
+ require 'just_shogi/pieces/kyousha'
5
+ require 'just_shogi/pieces/keima'
6
+ require 'just_shogi/pieces/ginshou'
7
+ require 'just_shogi/pieces/kinshou'
8
+ require 'just_shogi/pieces/oushou'
9
+ require 'just_shogi/pieces/gyokushou'
10
+
11
+ require 'just_shogi/pieces/tokin'
12
+ require 'just_shogi/pieces/narikyou'
13
+ require 'just_shogi/pieces/narikei'
14
+ require 'just_shogi/pieces/narigin'
15
+ require 'just_shogi/pieces/ryuuma'
16
+ require 'just_shogi/pieces/ryuuou'
17
+
18
+ module JustShogi
19
+
20
+ # = Promotion Factory
21
+ #
22
+ # Generates the promoted or demoted piece given a piece
23
+ class PromotionFactory
24
+
25
+ # A mapping of promotions
26
+ PROMOTIONS = {
27
+ Fuhyou => Tokin,
28
+ Kakugyou => Ryuuma,
29
+ Hisha => Ryuuou,
30
+ Kyousha => Narikyou,
31
+ Keima => Narikei,
32
+ Ginshou => Narigin
33
+ }
34
+
35
+ # New objects can be instantiated by passing in the piece
36
+ #
37
+ # @params [Piece] piece
38
+ # the piece to be promoted
39
+ def initialize(piece)
40
+ @piece = piece
41
+ end
42
+
43
+ def promotable?
44
+ !PROMOTIONS[@piece.class].nil?
45
+ end
46
+
47
+ def demotable?
48
+ !PROMOTIONS.key(@piece.class).nil?
49
+ end
50
+
51
+ # Returns the promoted piece
52
+ def promote
53
+ promoted_klass = PROMOTIONS[@piece.class]
54
+ if promoted_klass
55
+ promoted_klass.new(id: @piece.id, player_number: @piece.player_number)
56
+ else
57
+ raise ArgumentError, "Piece cannot be promoted."
58
+ end
59
+ end
60
+
61
+ # Returns the demoted piece
62
+ def demote
63
+ demoted_klass = PROMOTIONS.key(@piece.class)
64
+ if demoted_klass
65
+ demoted_klass.new(id: @piece.id, player_number: @piece.player_number)
66
+ else
67
+ raise ArgumentError, "Piece cannot be demoted."
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,51 @@
1
+ require 'just_shogi/piece_factory'
2
+ require 'board_game_grid'
3
+
4
+ module JustShogi
5
+
6
+ # = Square
7
+ #
8
+ # A Square on a shogi board.
9
+ class Square < BoardGameGrid::Square
10
+
11
+ # New object can be instantiated by passing in a hash with
12
+ #
13
+ # @param [String] id
14
+ # the unique identifier of the square.
15
+ #
16
+ # @param [Fixnum] x
17
+ # the x co-ordinate of the square.
18
+ #
19
+ # @param [Fixnum] y
20
+ # the y co-ordinate of the square.
21
+ #
22
+ # @option [Piece,Hash,NilClass] piece
23
+ # The piece on the square, can be a piece object or hash or nil.
24
+ #
25
+ # ==== Example:
26
+ # # Instantiates a new Square
27
+ # JustShogi::Square.new({
28
+ # id: '91',
29
+ # x: 0,
30
+ # y: 0,
31
+ # piece: { id: 1, player_number: 1, type: 'fuhyou' }
32
+ # })
33
+ def initialize(id: , x: , y: , piece: nil)
34
+ @id = id
35
+ @x = x
36
+ @y = y
37
+ @piece = PieceFactory.new(piece).build
38
+ end
39
+
40
+ def promotion_zone(player_number)
41
+ case player_number
42
+ when 1
43
+ (0..2).include?(y)
44
+ when 2
45
+ (6..8).include?(y)
46
+ else
47
+ raise ArgumentError, "Invalid Player Number"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,64 @@
1
+ require 'just_shogi/square'
2
+ require 'board_game_grid'
3
+
4
+ module JustShogi
5
+
6
+ # = Square Set
7
+ #
8
+ # A collection of Squares with useful filtering functions
9
+ class SquareSet < BoardGameGrid::SquareSet
10
+
11
+ # New objects can be instantiated by passing in a hash with squares.
12
+ # They can be square objects or hashes.
13
+ #
14
+ # @param [Array<Square,Hash>] squares
15
+ # An array of squares, each with an x and y co-oordinates an a piece.
16
+ #
17
+ # ==== Example:
18
+ # # Instantiates a new Square Sete
19
+ # JustShogi::SquareSet.new({
20
+ # squares: [
21
+ # { id: '91', x: 0, y: 0, piece: { id: 1, player_number: 1, type: 'fuhyou' } }
22
+ # ]
23
+ # })
24
+ def initialize(squares: )
25
+ @squares = if squares.all? { |s| s.instance_of?(Hash) }
26
+ squares.map { |s| Square.new(**s) }
27
+ elsif squares.all? { |s| s.instance_of?(Square) }
28
+ squares
29
+ else
30
+ raise ArgumentError, "all squares must have the same class"
31
+ end
32
+ end
33
+
34
+ # Find the square occupied by the player's king
35
+ #
36
+ # @param [Fixnum] player_number
37
+ # the number of the player
38
+ #
39
+ # @return [Square]
40
+ # ==== Example:
41
+ # # Find the square occupied by player 2's ou
42
+ # square_est.find_ou_for_player(2)
43
+ def find_ou_for_player(player_number)
44
+ find { |s| s.piece && s.piece.is_a?(JustShogi::OuBase) && s.occupied_by_player?(player_number) }
45
+ end
46
+
47
+ # Returns all squares threatened by the specified player
48
+ #
49
+ # @param [Fixnum] player_number
50
+ # the player's number.
51
+ #
52
+ # @param [GameState] game_state
53
+ # the current game state.
54
+ #
55
+ # @return [SquareSet]
56
+ def threatened_by(player_number, game_state)
57
+ _squares = occupied_by_player(player_number).map do |s|
58
+ s.piece.potential_capture_squares(s, game_state).squares
59
+ end.flatten.uniq
60
+
61
+ self.class.new(squares: _squares)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module JustShogi
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: just_shogi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Humphreys
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-05-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.1.4
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 13.0.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 13.0.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 5.14.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 5.14.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: board_game_grid
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.6
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.6
69
+ description: Provides a representation of a shogi game complete with rules enforcement
70
+ and serialisation.
71
+ email:
72
+ - mark@mrlhumphreys.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - CODE_OF_CONDUCT.md
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - just_shogi.gemspec
87
+ - lib/just_shogi.rb
88
+ - lib/just_shogi/errors/causes_check_error.rb
89
+ - lib/just_shogi/errors/dropped_into_check_error.rb
90
+ - lib/just_shogi/errors/error.rb
91
+ - lib/just_shogi/errors/invalid_move_error.rb
92
+ - lib/just_shogi/errors/invalid_promotion_error.rb
93
+ - lib/just_shogi/errors/moved_into_check_error.rb
94
+ - lib/just_shogi/errors/no_piece_error.rb
95
+ - lib/just_shogi/errors/not_players_turn_error.rb
96
+ - lib/just_shogi/errors/off_board_error.rb
97
+ - lib/just_shogi/errors/piece_not_found_error.rb
98
+ - lib/just_shogi/errors/square_occupied_error.rb
99
+ - lib/just_shogi/game_state.rb
100
+ - lib/just_shogi/hand.rb
101
+ - lib/just_shogi/piece_factory.rb
102
+ - lib/just_shogi/pieces/fuhyou.rb
103
+ - lib/just_shogi/pieces/ginshou.rb
104
+ - lib/just_shogi/pieces/gyokushou.rb
105
+ - lib/just_shogi/pieces/hisha.rb
106
+ - lib/just_shogi/pieces/kakugyou.rb
107
+ - lib/just_shogi/pieces/keima.rb
108
+ - lib/just_shogi/pieces/kin_base.rb
109
+ - lib/just_shogi/pieces/kinshou.rb
110
+ - lib/just_shogi/pieces/kyousha.rb
111
+ - lib/just_shogi/pieces/narigin.rb
112
+ - lib/just_shogi/pieces/narikei.rb
113
+ - lib/just_shogi/pieces/narikyou.rb
114
+ - lib/just_shogi/pieces/ou_base.rb
115
+ - lib/just_shogi/pieces/oushou.rb
116
+ - lib/just_shogi/pieces/piece.rb
117
+ - lib/just_shogi/pieces/ryuuma.rb
118
+ - lib/just_shogi/pieces/ryuuou.rb
119
+ - lib/just_shogi/pieces/tokin.rb
120
+ - lib/just_shogi/promotion_factory.rb
121
+ - lib/just_shogi/square.rb
122
+ - lib/just_shogi/square_set.rb
123
+ - lib/just_shogi/version.rb
124
+ homepage: https://github.com/mrlhumphreys/just_shogi
125
+ licenses:
126
+ - MIT
127
+ metadata: {}
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 2.7.0
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.1.2
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: A Shogi engine written in ruby
147
+ test_files: []