software_challenge_client 22.1.0.1 → 23.0.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -15
  3. data/.rspec +3 -3
  4. data/.rubocop.yml +11 -11
  5. data/.ruby-version +1 -1
  6. data/.stickler.yml +7 -7
  7. data/.vscode/launch.json +40 -40
  8. data/.vscode/settings.json +9 -9
  9. data/AUTHORS +6 -6
  10. data/CODE_OF_CONDUCT.md +13 -13
  11. data/Dockerfile +3 -3
  12. data/Gemfile +5 -5
  13. data/Guardfile +45 -45
  14. data/README.md +172 -147
  15. data/RELEASES.md +144 -140
  16. data/Rakefile +7 -7
  17. data/bin/console +15 -15
  18. data/bin/setup +7 -7
  19. data/develop.sh +3 -3
  20. data/example/client.rb +35 -35
  21. data/example/main.rb +42 -42
  22. data/example/start.bat +2 -2
  23. data/generate-authors.sh +19 -19
  24. data/lib/software_challenge_client/board.rb +149 -127
  25. data/lib/software_challenge_client/client_interface.rb +19 -19
  26. data/lib/software_challenge_client/condition.rb +27 -27
  27. data/lib/software_challenge_client/coordinates.rb +71 -45
  28. data/lib/software_challenge_client/debug_hint.rb +17 -17
  29. data/lib/software_challenge_client/direction.rb +41 -0
  30. data/lib/software_challenge_client/field.rb +70 -69
  31. data/lib/software_challenge_client/game_rule_logic.rb +206 -141
  32. data/lib/software_challenge_client/game_state.rb +57 -24
  33. data/lib/software_challenge_client/invalid_move_exception.rb +15 -15
  34. data/lib/software_challenge_client/logging.rb +26 -26
  35. data/lib/software_challenge_client/move.rb +37 -41
  36. data/lib/software_challenge_client/network.rb +126 -126
  37. data/lib/software_challenge_client/piece.rb +43 -81
  38. data/lib/software_challenge_client/player.rb +31 -31
  39. data/lib/software_challenge_client/protocol.rb +103 -54
  40. data/lib/software_challenge_client/runner.rb +36 -36
  41. data/lib/software_challenge_client/team.rb +23 -25
  42. data/lib/software_challenge_client/util/constants.rb +9 -9
  43. data/lib/software_challenge_client/version.rb +5 -5
  44. data/lib/software_challenge_client.rb +23 -25
  45. data/lib/update_client_module.sh +15 -15
  46. data/push_image_production.sh +12 -12
  47. data/release.sh +9 -9
  48. data/software_challenge_client.gemspec +41 -41
  49. metadata +3 -5
  50. data/lib/software_challenge_client/color.rb +0 -26
  51. data/lib/software_challenge_client/has_hints.rb +0 -11
  52. data/lib/software_challenge_client/piece_type.rb +0 -16
data/bin/setup CHANGED
@@ -1,7 +1,7 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/develop.sh CHANGED
@@ -1,3 +1,3 @@
1
- #!/bin/sh
2
- set -x # echo commands as they are executed
3
- docker run -it --rm -p 8808:8808 -v "$PWD":/usr/src/app -w /usr/src/app ruby:latest /bin/bash
1
+ #!/bin/sh
2
+ set -x # echo commands as they are executed
3
+ docker run -it --rm -p 8808:8808 -v "$PWD":/usr/src/app -w /usr/src/app ruby:latest /bin/bash
data/example/client.rb CHANGED
@@ -1,35 +1,35 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
- require 'software_challenge_client'
4
-
5
- # This is an example of a client playing the game using the software challenge
6
- # gem.
7
- class Client < ClientInterface
8
- include Logging
9
-
10
- attr_accessor :gamestate
11
-
12
- def initialize(log_level)
13
- logger.level = log_level
14
- logger.info 'Einfacher Spieler wurde erstellt.'
15
- end
16
-
17
- # gets called, when it's your turn
18
- def move_requested
19
- logger.info "Spielstand: #{gamestate.points_for_player(gamestate.current_player)} - #{gamestate.points_for_player(gamestate.other_player)}"
20
- logger.debug "Board: #{gamestate.board}"
21
- move = best_move
22
- logger.debug "Zug gefunden: #{move}" unless move.nil?
23
- move
24
- end
25
-
26
- def best_move
27
- # gamestate.board.add_field(Field.new(5, 0))
28
- logger.debug "Berechne zuege fuer Board #{gamestate.board}"
29
-
30
- # all possible moves can't be calculated in under two seconds
31
- possible_moves = GameRuleLogic.possible_moves(gamestate)
32
- logger.debug "#{possible_moves.size} moegliche Zuege gefunden"
33
- possible_moves.sample
34
- end
35
- end
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ require 'software_challenge_client'
4
+
5
+ # This is an example of a client playing the game using the software challenge
6
+ # gem.
7
+ class Client < ClientInterface
8
+ include Logging
9
+
10
+ attr_accessor :gamestate
11
+
12
+ def initialize(log_level)
13
+ logger.level = log_level
14
+ logger.info 'Einfacher Spieler wurde erstellt.'
15
+ end
16
+
17
+ # gets called, when it's your turn
18
+ def move_requested
19
+ logger.info "Spielstand: #{gamestate.points_for_player(gamestate.current_player)} - #{gamestate.points_for_player(gamestate.other_player)}"
20
+ logger.debug "Board: #{gamestate.board}"
21
+ move = best_move
22
+ logger.debug "Zug gefunden: #{move}" unless move.nil?
23
+ move
24
+ end
25
+
26
+ def best_move
27
+ # gamestate.board.add_field(Field.new(5, 0))
28
+ logger.debug "Berechne zuege fuer Board #{gamestate.board}"
29
+
30
+ # all possible moves can't be calculated in under two seconds
31
+ possible_moves = GameRuleLogic.possible_moves(gamestate)
32
+ logger.debug "#{possible_moves.size} moegliche Zuege gefunden"
33
+ possible_moves.sample
34
+ end
35
+ end
data/example/main.rb CHANGED
@@ -1,42 +1,42 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
- # frozen_string_literal: true
4
- require 'software_challenge_client'
5
- require 'optparse'
6
- require 'ostruct'
7
-
8
- require_relative 'client'
9
-
10
- options = OpenStruct.new
11
- options.host = '127.0.0.1'
12
- options.port = 13_050
13
- options.reservation = ''
14
-
15
- opt_parser = OptionParser.new do |opt|
16
- opt.banner = 'Usage: main.rb [OPTIONS]'
17
- opt.separator ''
18
- opt.separator 'Options'
19
-
20
- opt.on('-p', '--port PORT', Integer, "connect to the server at PORT (default #{options.port})") do |p|
21
- options.port = p
22
- end
23
-
24
- opt.on('-h', '--host HOST', "the host's IP address (default #{options.host})") do |h|
25
- options.host = h
26
- end
27
-
28
- opt.on('-r', '--reservation RESERVATION', "the host's RESERVATION (default #{options.reservation})") do |r|
29
- options.reservation = r
30
- end
31
-
32
- opt.on_tail('-?', '--help', 'Show this message') do
33
- puts opt
34
- exit
35
- end
36
- end
37
-
38
- opt_parser.parse!(ARGV)
39
-
40
- client = Client.new(Logger::DEBUG)
41
- runner = Runner.new(options.host, options.port, client, options.reservation)
42
- runner.start
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ require 'software_challenge_client'
5
+ require 'optparse'
6
+ require 'ostruct'
7
+
8
+ require_relative 'client'
9
+
10
+ options = OpenStruct.new
11
+ options.host = '127.0.0.1'
12
+ options.port = 13_050
13
+ options.reservation = ''
14
+
15
+ opt_parser = OptionParser.new do |opt|
16
+ opt.banner = 'Usage: main.rb [OPTIONS]'
17
+ opt.separator ''
18
+ opt.separator 'Options'
19
+
20
+ opt.on('-p', '--port PORT', Integer, "connect to the server at PORT (default #{options.port})") do |p|
21
+ options.port = p
22
+ end
23
+
24
+ opt.on('-h', '--host HOST', "the host's IP address (default #{options.host})") do |h|
25
+ options.host = h
26
+ end
27
+
28
+ opt.on('-r', '--reservation RESERVATION', "the host's RESERVATION (default #{options.reservation})") do |r|
29
+ options.reservation = r
30
+ end
31
+
32
+ opt.on_tail('-?', '--help', 'Show this message') do
33
+ puts opt
34
+ exit
35
+ end
36
+ end
37
+
38
+ opt_parser.parse!(ARGV)
39
+
40
+ client = Client.new(Logger::DEBUG)
41
+ runner = Runner.new(options.host, options.port, client, options.reservation)
42
+ runner.start
data/example/start.bat CHANGED
@@ -1,2 +1,2 @@
1
- :: Gedacht zum ausführen des ruby SimpleClients
2
- ruby main.rb %*
1
+ :: Gedacht zum ausführen des ruby SimpleClients
2
+ ruby main.rb %*
data/generate-authors.sh CHANGED
@@ -1,19 +1,19 @@
1
- #!/bin/bash
2
- # Thanks to the docker project!
3
- # https://github.com/docker/docker/blob/2c224e4fc09518d33780d818cf74026f6aa32744/hack/generate-authors.sh
4
- set -e
5
-
6
- # change to the directory where the script is located, this should be the project root
7
- pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")/"
8
-
9
- # see also ".mailmap" for how email addresses and names are deduplicated
10
-
11
- {
12
- cat <<-'EOH'
13
- # This file lists all individuals having contributed content to the repository.
14
- # For how it is generated, see `generate-authors.sh`.
15
- EOH
16
- echo
17
- git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf
18
- } > AUTHORS
19
- popd
1
+ #!/bin/bash
2
+ # Thanks to the docker project!
3
+ # https://github.com/docker/docker/blob/2c224e4fc09518d33780d818cf74026f6aa32744/hack/generate-authors.sh
4
+ set -e
5
+
6
+ # change to the directory where the script is located, this should be the project root
7
+ pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")/"
8
+
9
+ # see also ".mailmap" for how email addresses and names are deduplicated
10
+
11
+ {
12
+ cat <<-'EOH'
13
+ # This file lists all individuals having contributed content to the repository.
14
+ # For how it is generated, see `generate-authors.sh`.
15
+ EOH
16
+ echo
17
+ git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf
18
+ } > AUTHORS
19
+ popd
@@ -1,127 +1,149 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- require_relative './util/constants'
5
- require_relative 'game_state'
6
- require_relative 'field'
7
-
8
- # Ein Spielbrett fuer Ostseeschach
9
- class Board
10
- include Constants
11
-
12
- # @!attribute [r] fields
13
- # @note Besser über die {#field} Methode auf Felder zugreifen.
14
- # @return [Array<Array<Field>>] Ein Feld wird an der Position entsprechend
15
- # seiner x und y Coordinates im Array gespeichert.
16
- attr_reader :fields
17
-
18
- # Erstellt ein neues leeres Spielbrett.
19
- def initialize(fields = [])
20
- @fields = Board.empty_game_field
21
- fields.each { |f| add_field(f) }
22
- end
23
-
24
- # @return [Array] leere Felder entsprechend des Spielbrettes angeordnet
25
- def self.empty_game_field
26
- (0...BOARD_SIZE).to_a.map do |x|
27
- (0...BOARD_SIZE).to_a.map do |y|
28
- Field.new(x, y)
29
- end
30
- end
31
- end
32
-
33
- # Entfernt alle Felder des Spielfeldes
34
- def clear
35
- @fields = []
36
- end
37
-
38
- # @return [Array] Liste aller Felder
39
- def field_list
40
- @fields.flatten.reject(&:nil?)
41
- end
42
-
43
- # Vergleicht zwei Spielbretter. Gleichheit besteht, wenn zwei Spielbretter die
44
- # gleichen Felder enthalten.
45
- def ==(other)
46
- field_list == other.field_list
47
- end
48
-
49
- # Fügt ein Feld dem Spielbrett hinzu. Das übergebene Feld ersetzt das an den
50
- # Koordinaten bestehende Feld.
51
- #
52
- # @param field [Field] Das einzufügende Feld.
53
- def add_field(field)
54
- @fields[field.x][field.y] = field
55
- end
56
-
57
- # Zugriff auf die Felder des Spielfeldes
58
- #
59
- # @param x [Integer] Die X-Koordinate des Feldes.
60
- # @param y [Integer] Die Y-Koordinate des Feldes.
61
- # @return [Field] Das Feld mit den gegebenen Koordinaten. Falls das Feld nicht
62
- # exisitert, wird nil zurückgegeben.
63
- def field(x, y)
64
- fields.dig(x, y) # NOTE that #dig requires ruby 2.3+
65
- end
66
-
67
- # Zugriff auf die Felder des Spielfeldes über ein Koordinaten-Paar.
68
- #
69
- # @param coordinates [Coordinates] X- und Y-Koordinate als Paar, sonst wie
70
- # bei {Board#field}.
71
- #
72
- # @return [Field] Wie bei {Board#field}.
73
- #
74
- # @see #field
75
- def field_at(coordinates)
76
- field(coordinates.x, coordinates.y)
77
- end
78
-
79
- def fields_of_color(color)
80
- fields = []
81
-
82
- (0...BOARD_SIZE).to_a.map do |x|
83
- (0...BOARD_SIZE).to_a.map do |y|
84
- f = field(x,y)
85
- if (f.color == color)
86
- fields << f
87
- end
88
- end
89
- end
90
-
91
- fields
92
- end
93
-
94
- # @param it [Coordinates] Die zu untersuchenden Koordinaten
95
- # @return [Boolean] Ob die gegebenen Koordinaten auf dem Board liegen oder nicht
96
- def in_bounds?(it)
97
- it.x >= 0 && it.y >= 0 && it.x < BOARD_SIZE && it.y < BOARD_SIZE
98
- end
99
-
100
- # @return eine unabhaengige Kopie des Spielbretts
101
- def clone
102
- Marshal.load(Marshal.dump(self))
103
- end
104
-
105
- # @param coords [Coordinates] Die Koordinaten des Felds
106
- # @return Das Feld an den gegebenen Koordinaten
107
- def [](coords)
108
- field_at(coords)
109
- end
110
-
111
- # Gibt eine textuelle Repräsentation des Spielbrettes aus.
112
- def to_s
113
- "\n" +
114
- (0...BOARD_SIZE).to_a.map do |y|
115
- (0...BOARD_SIZE).to_a.map do |x|
116
- @fields[x][y].to_s
117
- end.join(' ')
118
- end.join("\n")
119
- end
120
-
121
- # @param position [Coordinates] Die zu überprüfenden Koordinaten
122
- # @return Ob die gegebenen Koordinaten auf dem board liegen
123
- def self.contains(position)
124
- position.x >= 0 && position.x < BOARD_SIZE &&
125
- position.y >= 0 && position.y < BOARD_SIZE
126
- end
127
- end
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require_relative './util/constants'
5
+ require_relative 'game_state'
6
+ require_relative 'field'
7
+
8
+ # Ein Spielbrett fuer Ostseeschach
9
+ class Board
10
+ include Constants
11
+
12
+ # @!attribute [r] fields
13
+ # @note Besser über die {#field} Methode auf Felder zugreifen.
14
+ # @return [Array<Array<Field>>] Ein Feld wird an der Position entsprechend
15
+ # seiner x und y Coordinates im Array gespeichert.
16
+ attr_reader :fields
17
+
18
+ # --- Init ------------------------------------------------------------
19
+
20
+ # Erstellt ein neues leeres Spielbrett.
21
+ def initialize(fields = [])
22
+ @fields = Board.empty_game_field
23
+ fields.each { |f| add_field(f) }
24
+ end
25
+
26
+ # @return [Array] leere Felder entsprechend des Spielbrettes angeordnet
27
+ def self.empty_game_field
28
+ (0...BOARD_SIZE).to_a.map do |x|
29
+ (0...BOARD_SIZE).to_a.map do |y|
30
+ Field.new(x, y)
31
+ end
32
+ end
33
+ end
34
+
35
+ # Entfernt alle Felder des Spielfeldes
36
+ def clear
37
+ @fields = []
38
+ end
39
+
40
+ # --- Field Access ------------------------------------------------------------
41
+
42
+ # Fügt ein Feld dem Spielbrett hinzu. Das übergebene Feld ersetzt das an den
43
+ # Koordinaten bestehende Feld.
44
+ #
45
+ # @param field [Field] Das einzufügende Feld.
46
+ def add_field(field)
47
+ @fields[field.x][field.y] = field
48
+ end
49
+
50
+ # Zugriff auf die Felder des Spielfeldes
51
+ #
52
+ # @param x [Integer] Die X-Koordinate des Feldes.
53
+ # @param y [Integer] Die Y-Koordinate des Feldes.
54
+ # @return [Field] Das Feld mit den gegebenen Koordinaten. Falls das Feld nicht
55
+ # exisitert, wird nil zurückgegeben.
56
+ def field(x, y)
57
+ fields.dig(x, y) # NOTE that #dig requires ruby 2.3+
58
+ end
59
+
60
+ # Zugriff auf die Felder des Spielfeldes über ein Koordinaten-Paar.
61
+ #
62
+ # @param coords [Coordinates] X- und Y-Koordinate als Paar, sonst wie
63
+ # bei {Board#field}.
64
+ #
65
+ # @return [Field] Wie bei {Board#field}.
66
+ #
67
+ # @see #field
68
+ def field_at(coords)
69
+ field(coords.x, coords.y)
70
+ end
71
+
72
+ # @return [Array] Liste aller Felder
73
+ def field_list
74
+ @fields.flatten.reject(&:nil?)
75
+ end
76
+
77
+ # @param coords [Coordinates] Die Koordinaten des Felds
78
+ # @return Das Feld an den gegebenen Koordinaten
79
+ def [](coords)
80
+ field_at(coords)
81
+ end
82
+
83
+ def fields_of_team(team)
84
+ fields = []
85
+
86
+ (0...BOARD_SIZE).to_a.map do |x|
87
+ (0...BOARD_SIZE).to_a.map do |y|
88
+ f = field(x,y)
89
+ if (!f.piece.nil? && f.piece.team == team)
90
+ fields << f
91
+ end
92
+ end
93
+ end
94
+
95
+ fields
96
+ end
97
+
98
+ # @param field [Field] Das eingabe Feld
99
+ # @return Die Felder um dem gegebenen Feld
100
+ def neighbors_of(field)
101
+ coords = []
102
+ c = Coordinates.oddr_to_doubled(field.coords)
103
+
104
+ Direction.each { |d|
105
+ disp = d.to_vec()
106
+
107
+ x = c.x + disp.x
108
+ y = c.y + disp.y
109
+
110
+ oddr_coords = Coordinates.doubled_to_oddr_int(x, y)
111
+ if !in_bounds?(oddr_coords)
112
+ next
113
+ end
114
+
115
+ coords.push(oddr_coords)
116
+ }
117
+
118
+ coords.map{ |x| self.field_at(x) }.to_a
119
+ end
120
+
121
+ # --- Other ------------------------------------------------------------
122
+
123
+ # @param coords [Coordinates] Die zu untersuchenden Koordinaten
124
+ # @return [Boolean] Ob die gegebenen Koordinaten auf dem Board liegen oder nicht
125
+ def in_bounds?(coords)
126
+ coords.x >= 0 && coords.y >= 0 && coords.x < BOARD_SIZE && coords.y < BOARD_SIZE
127
+ end
128
+
129
+ # Vergleicht zwei Spielbretter. Gleichheit besteht, wenn zwei Spielbretter die
130
+ # gleichen Felder enthalten.
131
+ def ==(other)
132
+ field_list == other.field_list
133
+ end
134
+
135
+ # @return eine unabhaengige Kopie des Spielbretts
136
+ def clone
137
+ Marshal.load(Marshal.dump(self))
138
+ end
139
+
140
+ # Gibt eine textuelle Repräsentation des Spielbrettes aus.
141
+ def to_s
142
+ "\n" +
143
+ (0...BOARD_SIZE).to_a.map do |y|
144
+ (0...BOARD_SIZE).to_a.map do |x|
145
+ @fields[x][y].to_s
146
+ end.join(' ')
147
+ end.join("\n")
148
+ end
149
+ end
@@ -1,19 +1,19 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- # Das Interface sollte von einem Client implementiert werden, damit er über das
5
- # Gem an einem Spiel teilnehmen kann.
6
- class ClientInterface
7
- # Wird automatisch aktualisiert und ist immer der Spielzustand des aktuellen Zuges.
8
- attr_accessor :gamestate
9
-
10
- # Wird aufgerufen, wenn der Client einen Zug machen soll. Dies ist der
11
- # Einstiegspunkt für die eigentliche Logik des Computerspielers. Er muss auf
12
- # Basis des Spielzustandes entscheiden, welchen Zug er machen möchte und diese
13
- # zurückgeben.
14
- #
15
- # @return [Move] Ein für den aktuellen Spielzustand gültiger Spielzug.
16
- def move_requested
17
- raise 'Not yet implemented'
18
- end
19
- end
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ # Das Interface sollte von einem Client implementiert werden, damit er über das
5
+ # Gem an einem Spiel teilnehmen kann.
6
+ class ClientInterface
7
+ # Wird automatisch aktualisiert und ist immer der Spielzustand des aktuellen Zuges.
8
+ attr_accessor :gamestate
9
+
10
+ # Wird aufgerufen, wenn der Client einen Zug machen soll. Dies ist der
11
+ # Einstiegspunkt für die eigentliche Logik des Computerspielers. Er muss auf
12
+ # Basis des Spielzustandes entscheiden, welchen Zug er machen möchte und diese
13
+ # zurückgeben.
14
+ #
15
+ # @return [Move] Ein für den aktuellen Spielzustand gültiger Spielzug.
16
+ def move_requested
17
+ raise 'Not yet implemented'
18
+ end
19
+ end
@@ -1,27 +1,27 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
- require_relative 'player'
4
-
5
- # Das Ergebnis eines Spieles. Ist im `GameState#condition` zu finden, wenn das Spiel beendet wurde.
6
- class Condition
7
- # @!attribute [r] winner
8
- # @return [Player] Spieler, der das Spiel gewonnen hat.
9
- attr_reader :winner
10
-
11
- # @!attribute [r] reason
12
- # @return [String] Grund fuer Spielende
13
- attr_reader :reason
14
-
15
- # Initializes the winning Condition with a player
16
- # @param winner [Player] winning player
17
- # @param reason [String] why the player has won
18
- def initialize(winner, reason)
19
- @winner = winner
20
- @reason = reason
21
- end
22
-
23
- # Überprüfe ob es ein Unentschieden gab
24
- def draw?
25
- @winner.nil?
26
- end
27
- end
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ require_relative 'player'
4
+
5
+ # Das Ergebnis eines Spieles. Ist im `GameState#condition` zu finden, wenn das Spiel beendet wurde.
6
+ class Condition
7
+ # @!attribute [r] winner
8
+ # @return [Player] Spieler, der das Spiel gewonnen hat.
9
+ attr_reader :winner
10
+
11
+ # @!attribute [r] reason
12
+ # @return [String] Grund fuer Spielende
13
+ attr_reader :reason
14
+
15
+ # Initializes the winning Condition with a player
16
+ # @param winner [Player] winning player
17
+ # @param reason [String] why the player has won
18
+ def initialize(winner, reason)
19
+ @winner = winner
20
+ @reason = reason
21
+ end
22
+
23
+ # Überprüfe ob es ein Unentschieden gab
24
+ def draw?
25
+ @winner.nil?
26
+ end
27
+ end