just_shogi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []