Class: GameRuleLogic
- Inherits:
-
Object
- Object
- GameRuleLogic
- Includes:
- Constants
- Defined in:
- lib/software_challenge_client/game_rule_logic.rb
Overview
Methoden, welche die Spielregeln von Piranhas abbilden.
Es gibt hier viele Helfermethoden, die von den beiden Hauptmethoden GameRuleLogic.valid_move? und GameRuleLogic.possible_moves benutzt werden.
Constant Summary
Constants included from Constants
Constants::GAME_IDENTIFIER, Constants::ROUND_LIMIT, Constants::SIZE
Class Method Summary collapse
-
.add_blocked_fields(board) ⇒ Board
Fügt einem leeren Spielfeld zwei Krakenfelder hinzu.
-
.count_fish(board, start, direction) ⇒ Integer
Ermittlung der Anzahl der Fische auf einer Line des Spielbrettes.
-
.greatest_swarm_from_fields(board, fields_to_check, current_biggest_swarm = Set.new) ⇒ Set<Field>
Hilfsfunktion für GameRuleLogic.swarm_size.
-
.inside_bounds?(coordinates) ⇒ Boolean
Prüft, ob sich die gegebenen Koordinaten innerhalb des Spielbrettes befinden.
-
.move_target(move, board) ⇒ Field
Das Zielfeld eines Spielzuges auf einem Spielbrett.
-
.neighbours(board, field) ⇒ Array<Field>
Alle direkten Nachbarfelder des gegebenen Feldes.
-
.obstacle?(field_type, moving_player_color) ⇒ Boolean
Ermittelt, ob der gegebene Feldtyp für den Spieler mit der angegebenen Farbe ein nicht überspringbares Hindernis darstellt.
-
.obstacle_between?(from_field, direction, to_field, color, board) ⇒ Boolean
Ermittelt, ob sich zwischen den angegebenen Feldern kein Hindernis befindet.
-
.possible_moves(board, field, current_player_color) ⇒ Array<Move>
Ermittelt alle möglichen Züge von einem bestimmten Feld aus.
-
.swarm_size(board, player_color) ⇒ Integer
Ermittelt die Schwarmgröße eines Spielers auf dem Spielbrett.
-
.target_coordinates(move, board) ⇒ Coordinates
Die Zielkoordinaten eines Spielzuges auf einem Spielbrett.
-
.valid_move?(move, board, current_player_color) ⇒ Boolean
Ermittelt, ob der gegebene Zug regelkonform ausgeführt werden kann.
-
.valid_move_target(target, moving_player_color, board) ⇒ Boolean
Ermittelt, ob der Spieler mit der angegebenen Farbe einen Fisch auf dem Feld mit den angegebenen Koordinaten besitzt.
Class Method Details
.add_blocked_fields(board) ⇒ Board
Fügt einem leeren Spielfeld zwei Krakenfelder hinzu. Die beiden Felder liegen nicht auf derselben Horizontalen, Vertikalen oder Diagonalen und sind mindestens zwei Felder von den Rändern des Spielbrettes entfernt.
Diese Methode ist dazu gedacht, ein initiales Spielbrett regelkonform zu generieren.
24 25 26 27 28 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 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 24 def self.add_blocked_fields(board) number_of_blocked_fields = 2 lower_bound = 2 # first row or column, in which blocked fields are allowed upper_bound = 7 # last row or column, in which blocked fields are allowed # create a list of coordinates for fields which may be blocked blockable_field_coordinates = (lower_bound..upper_bound).to_a.map do |x| (lower_bound..upper_bound).to_a.map do |y| Coordinate.new(x, y) end end.flatten # set fields with randomly selected coordinates to blocked coordinates may # not lay on same horizontal, vertical or diagonal lines with other selected # coordinates number_of_blocked_fields.times do selected_coords = blockable_field_coordinates.sample board.change_field(selectedCoords, FieldType::OBSTRUCTED) # remove field coordinates and fields on horizontal, vertical and diagonal # lines: coordinates_to_remove = ALL_DIRECTIONS.map do |direction| Line.new(selected_coords, direction).to_a end.flatten blockable_field_coordinates = blockable_field_coordinates.filter do |c| coordinates_to_remove.none? do |to_remove| c.x == to_remove.x && c.y == to_remove.y end end end board end |
.count_fish(board, start, direction) ⇒ Integer
Ermittlung der Anzahl der Fische auf einer Line des Spielbrettes.
62 63 64 65 66 67 68 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 62 def self.count_fish(board, start, direction) # filter function for fish field type fish = proc { |f| f.type == FieldType::RED || f.type == FieldType::BLUE } Line.new(start, direction).to_a.map do |p| board.field(p.x, p.y) end.select(&fish).size end |
.greatest_swarm_from_fields(board, fields_to_check, current_biggest_swarm = Set.new) ⇒ Set<Field>
Hilfsfunktion für swarm_size. Ermittelt die größte zusammenhängende Menge von Feldern aus einer gegebenen Menge von Feldern.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 198 def self.greatest_swarm_from_fields(board, fields_to_check, current_biggest_swarm = Set.new) # stop searching when the size of the current found biggest set is bigger # than the rest of the fields or if there are no more fields to check return current_biggest_swarm if current_biggest_swarm.size > fields_to_check.size || fields_to_check.empty? # start a new set of adjacent fields with the first field in fields_to_check current_swarm = Set.new field = fields_to_check.to_a.first fields_to_check.delete(field) current_swarm.add(field) # move all adjacent fields to the set loop do to_add = current_swarm .map { |f| GameRuleLogic.neighbours(board, f) } .flatten .select { |f| fields_to_check.include? f } break if to_add.empty? fields_to_check -= to_add current_swarm += to_add end # keep trying to find bigger sets if current_swarm.size > current_biggest_swarm.size GameRuleLogic.greatest_swarm_from_fields( board, fields_to_check, current_swarm ) else GameRuleLogic.greatest_swarm_from_fields( board, fields_to_check, current_biggest_swarm ) end end |
.inside_bounds?(coordinates) ⇒ Boolean
Prüft, ob sich die gegebenen Koordinaten innerhalb des Spielbrettes befinden.
87 88 89 90 91 92 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 87 def self.inside_bounds?(coordinates) coordinates.x >= 0 && coordinates.x < SIZE && coordinates.y >= 0 && coordinates.y < SIZE end |
.move_target(move, board) ⇒ Field
Returns Das Zielfeld eines Spielzuges auf einem Spielbrett.
80 81 82 83 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 80 def self.move_target(move, board) c = GameRuleLogic.target_coordinates(move, board) board.field(c.x, c.y) end |
.neighbours(board, field) ⇒ Array<Field>
Returns Alle direkten Nachbarfelder des gegebenen Feldes. Für Felder im Inneren des Spielbrettes gibt es acht Nachbarfelder. Für Randfelder vier oder drei Nachbarfelder.
185 186 187 188 189 190 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 185 def self.neighbours(board, field) Direction .map { |d| d.translate(field.coordinates) } .select { |c| GameRuleLogic.inside_bounds?(c) } .map { |c| board.field_at(c) } end |
.obstacle?(field_type, moving_player_color) ⇒ Boolean
Ermittelt, ob der gegebene Feldtyp für den Spieler mit der angegebenen Farbe ein nicht überspringbares Hindernis darstellt.
98 99 100 101 102 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 98 def self.obstacle?(field_type, moving_player_color) field_type == PlayerColor.field_type( PlayerColor.opponent_color(moving_player_color) ) end |
.obstacle_between?(from_field, direction, to_field, color, board) ⇒ Boolean
Ermittelt, ob sich zwischen den angegebenen Feldern kein Hindernis befindet.
111 112 113 114 115 116 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 111 def self.obstacle_between?(from_field, direction, to_field, color, board) Line.new(from_field, direction) .to_a .select { |c| Line.between(from_field, to_field, direction).call(c) } .any? { |f| GameRuleLogic.obstacle?(board.field(f.x, f.y).type, color) } end |
.possible_moves(board, field, current_player_color) ⇒ Array<Move>
Ermittelt alle möglichen Züge von einem bestimmten Feld aus.
163 164 165 166 167 168 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 163 def self.possible_moves(board, field, current_player_color) Direction.map { |direction| Move.new(field.x, field.y, direction) } .select do |m| GameRuleLogic.valid_move?(m, board, current_player_color) end end |
.swarm_size(board, player_color) ⇒ Integer
Ermittelt die Schwarmgröße eines Spielers auf dem Spielbrett.
174 175 176 177 178 179 180 181 182 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 174 def self.swarm_size(board, player_color) GameRuleLogic.greatest_swarm_from_fields( board, board.fields_of_type( PlayerColor.field_type(player_color) ).to_set, Set.new ).size end |
.target_coordinates(move, board) ⇒ Coordinates
Returns Die Zielkoordinaten eines Spielzuges auf einem Spielbrett.
71 72 73 74 75 76 77 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 71 def self.target_coordinates(move, board) speed = GameRuleLogic.count_fish( board, move.from_field, Line.line_direction_for_direction(move.direction) ) move.target_field(speed) end |
.valid_move?(move, board, current_player_color) ⇒ Boolean
Ermittelt, ob der gegebene Zug regelkonform ausgeführt werden kann.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 136 def self.valid_move?(move, board, current_player_color) from_field_type = board.field(move.x, move.y).type return false unless [FieldType::BLUE, FieldType::RED].include? from_field_type return false unless current_player_color == FieldType.player_color(from_field_type) return false unless GameRuleLogic.inside_bounds?( GameRuleLogic.target_coordinates(move, board) ) target = GameRuleLogic.move_target(move, board) GameRuleLogic.valid_move_target(target, current_player_color, board) && !GameRuleLogic.obstacle_between?( move.from_field, Line.line_direction_for_direction(move.direction), target, current_player_color, board ) end |
.valid_move_target(target, moving_player_color, board) ⇒ Boolean
Ermittelt, ob der Spieler mit der angegebenen Farbe einen Fisch auf dem Feld mit den angegebenen Koordinaten besitzt.
123 124 125 126 127 128 129 |
# File 'lib/software_challenge_client/game_rule_logic.rb', line 123 def self.valid_move_target(target, moving_player_color, board) target_field_type = board.field(target.x, target.y).type target_field_type == FieldType::EMPTY || target_field_type == PlayerColor.field_type( PlayerColor.opponent_color(moving_player_color) ) end |