glimmer-dsl-swt 4.20.13.14 → 4.20.13.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,143 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'grid'
23
+ require_relative 'ship'
24
+
25
+ class Battleship
26
+ module Model
27
+ class Game
28
+ BATTLESHIPS = {
29
+ aircraft_carrier: 5,
30
+ battleship: 4,
31
+ submarine: 3,
32
+ cruiser: 3,
33
+ destroyer: 2
34
+ }
35
+ PLAYERS = [:enemy, :you]
36
+
37
+ attr_reader :grids, :ship_collections
38
+ attr_accessor :started, :current_player, :over
39
+ alias started? started
40
+ alias over? over
41
+
42
+ def initialize
43
+ @grids = PLAYERS.reduce({}) { |hash, player| hash.merge(player => Grid.new(self, player)) }
44
+ @ship_collections = PLAYERS.reduce({}) { |hash, player| hash.merge(player => ShipCollection.new(self, player)) }
45
+ @started = false
46
+ @current_player = :enemy
47
+ @enemy_moves = []
48
+ end
49
+
50
+ def battle!
51
+ self.started = true
52
+ place_enemy_ships!
53
+ enemy_attack!
54
+ end
55
+
56
+ def reset!
57
+ self.started = false
58
+ self.over = false
59
+ self.current_player = :enemy
60
+ @grids.values.each(&:reset!)
61
+ @ship_collections.values.each(&:reset!)
62
+ @enemy_moves = []
63
+ end
64
+
65
+ def attack!(row_index, column_index)
66
+ return unless started?
67
+ cell = opposite_grid.cell_rows[row_index][column_index]
68
+ return unless cell.hit.nil?
69
+ cell.hit = !!cell.ship
70
+ switch_player!
71
+ enemy_attack! if current_player == :enemy
72
+ end
73
+
74
+ # Enemy attack artificial intelligence
75
+ def enemy_attack!
76
+ begin
77
+ cell = nil
78
+ if @enemy_moves.any? && @enemy_moves.last.hit? && !@enemy_moves.last.ship.sunk?
79
+ if @enemy_moves[-2].nil? || !@enemy_moves[-2].hit?
80
+ orientation = Ship::ORIENTATIONS[(rand * 2).to_i]
81
+ else
82
+ orientation = @enemy_moves.last.row_index == @enemy_moves[-2].row_index ? :horizontal : :vertical
83
+ end
84
+ offset = 1 * ((rand * 2).to_i == 1 ? 1 : -1)
85
+ if orientation == :horizontal
86
+ offset *= -1 if [-1, Grid::WIDTH].include?(@enemy_moves.last.column_index + offset)
87
+ cell = opposite_grid.cell_rows[@enemy_moves.last.row_index][@enemy_moves.last.column_index + offset]
88
+ else
89
+ offset *= -1 if [-1, Grid::HEIGHT].include?(@enemy_moves.last.row_index + offset)
90
+ cell = opposite_grid.cell_rows[@enemy_moves.last.row_index + offset][@enemy_moves.last.column_index]
91
+ end
92
+ cell = nil if cell.hit?
93
+ end
94
+ if cell.nil?
95
+ random_row_index = (rand * Grid::HEIGHT).to_i
96
+ random_column_index = (rand * Grid::WIDTH).to_i
97
+ cell = opposite_grid.cell_rows[random_row_index][random_column_index]
98
+ end
99
+ end until cell.hit.nil?
100
+ attack!(cell.row_index, cell.column_index)
101
+ @enemy_moves << cell
102
+ end
103
+
104
+ def opposite_grid
105
+ grids[opposite_player]
106
+ end
107
+
108
+ def opposite_player(player = nil)
109
+ player ||= current_player
110
+ PLAYERS[(PLAYERS.index(player) + 1) % PLAYERS.size]
111
+ end
112
+
113
+ def switch_player!
114
+ self.current_player = opposite_player
115
+ end
116
+
117
+ def over=(value)
118
+ @over = value
119
+ self.started = false
120
+ end
121
+
122
+ private
123
+
124
+ def place_enemy_ships!
125
+ ship_collection = @ship_collections[:enemy]
126
+ ship_collection.ships.values.each do |ship|
127
+ until ship.top_left_cell
128
+ random_row_index = (rand * Grid::HEIGHT).to_i
129
+ random_column_index = (rand * Grid::WIDTH).to_i
130
+ enemy_grid = @grids[:enemy]
131
+ top_left_cell = enemy_grid.cell_rows[random_row_index][random_column_index]
132
+ top_left_cell.place_ship!(ship)
133
+ begin
134
+ ship.toggle_orientation! if (rand * 2).to_i == 1
135
+ rescue => e
136
+ Glimmer::Config.logger.debug(e.full_message)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'cell'
23
+
24
+ class Battleship
25
+ module Model
26
+ class Grid
27
+ HEIGHT = 10
28
+ WIDTH = 10
29
+ ROW_ALPHABETS = %w[A B C D E F G H I J]
30
+
31
+ attr_reader :game, :player, :cell_rows
32
+
33
+ def initialize(game, player)
34
+ @game = game
35
+ @player = player
36
+ build
37
+ end
38
+
39
+ def reset!
40
+ @cell_rows.flatten.each(&:reset!)
41
+ end
42
+
43
+ private
44
+
45
+ def build
46
+ @cell_rows = HEIGHT.times.map do |row_index|
47
+ WIDTH.times.map do |column_index|
48
+ Cell.new(self, row_index, column_index)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,114 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'cell'
23
+
24
+ class Battleship
25
+ module Model
26
+ class Ship
27
+ ORIENTATIONS = [:horizontal, :vertical]
28
+
29
+ attr_reader :ship_collection, :name, :length
30
+ attr_accessor :orientation, :top_left_cell, :sunk
31
+ alias sunk? sunk
32
+
33
+ def initialize(ship_collection, name, length)
34
+ @ship_collection = ship_collection
35
+ @name = name
36
+ @length = length
37
+ @orientation = :horizontal
38
+ end
39
+
40
+ def to_s
41
+ "#{name.titlecase} (#{length} cells)"
42
+ end
43
+
44
+ def top_left_cell=(a_cell)
45
+ if a_cell
46
+ raise "Top left cell #{a_cell} already occupied by ship #{a_cell.ship.name}" if a_cell.ship && a_cell.ship != self
47
+ raise "Top left cell #{a_cell} cannot fit ship #{name}" if a_cell.column_index + length > Grid::WIDTH
48
+ grid = ship_collection.game.grids[ship_collection.player]
49
+ 1.upto(length - 1).each do |index|
50
+ if orientation == :horizontal
51
+ other_cell = grid.cell_rows[a_cell.row_index][a_cell.column_index + index]
52
+ else
53
+ other_cell = grid.cell_rows[a_cell.row_index + index][a_cell.column_index]
54
+ end
55
+ raise "Cell #{other_cell} already occupied by ship #{other_cell.ship.name}" if other_cell.ship && other_cell.ship != self
56
+ end
57
+ end
58
+ @top_left_cell = a_cell
59
+ end
60
+
61
+ def orientation=(value)
62
+ if top_left_cell
63
+ if value == :horizontal
64
+ if top_left_cell.column_index + length > Grid::WIDTH
65
+ raise "Top left cell #{top_left_cell} cannot fit ship #{name}"
66
+ end
67
+ else
68
+ if top_left_cell.row_index + length > Grid::HEIGHT
69
+ raise "Top left cell #{top_left_cell} cannot fit ship #{name}"
70
+ end
71
+ end
72
+ if cells(value)[1..-1].map(&:ship).reject {|s| s == self}.any?
73
+ raise 'Orientation #{value} cells occupied by another ship'
74
+ end
75
+ if value != @orientation
76
+ cells.each(&:reset!)
77
+ @orientation = value
78
+ cells.each_with_index do |cell, index|
79
+ cell.ship = self
80
+ cell.ship_index = index
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ def cells(for_orientation = nil)
87
+ for_orientation ||= orientation
88
+ if top_left_cell
89
+ length.times.map do |index|
90
+ if for_orientation == :horizontal
91
+ top_left_cell.grid.cell_rows[top_left_cell.row_index][top_left_cell.column_index + index]
92
+ else
93
+ top_left_cell.grid.cell_rows[top_left_cell.row_index + index][top_left_cell.column_index]
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ def all_cells_hit?
100
+ cells&.map(&:hit)&.all? {|h| h == true}
101
+ end
102
+
103
+ def reset!
104
+ self.sunk = nil
105
+ self.top_left_cell = nil
106
+ self.orientation = :horizontal
107
+ end
108
+
109
+ def toggle_orientation!
110
+ self.orientation = ORIENTATIONS[(ORIENTATIONS.index(orientation) + 1) % ORIENTATIONS.length]
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'ship'
23
+
24
+ class Battleship
25
+ module Model
26
+ class ShipCollection
27
+ BATTLESHIPS = {
28
+ aircraft_carrier: 5,
29
+ battleship: 4,
30
+ submarine: 3,
31
+ cruiser: 3,
32
+ destroyer: 2
33
+ }
34
+
35
+ attr_reader :game, :player, :ships
36
+ attr_accessor :placed_count
37
+
38
+ def initialize(game, player)
39
+ @game = game
40
+ @player = player
41
+ @ships = BATTLESHIPS.reduce({}) do |hash, pair|
42
+ name, width = pair
43
+ ship = Ship.new(self, name, width)
44
+ Glimmer::DataBinding::Observer.proc do |cell_value|
45
+ self.placed_count = ships.values.map(&:top_left_cell).compact.size
46
+ end.observe(ship, :top_left_cell)
47
+ hash.merge(name => ship)
48
+ end
49
+ end
50
+
51
+ def reset!
52
+ ships.values.each(&:reset!)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,59 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class Battleship
23
+ module View
24
+ class ActionPanel
25
+ include Glimmer::UI::CustomWidget
26
+
27
+ options :game
28
+
29
+ body {
30
+ composite {
31
+ row_layout(:horizontal) {
32
+ margin_width 0
33
+ margin_height 0
34
+ }
35
+
36
+ layout_data(:center, :center, true, false)
37
+
38
+ @battle_button = button {
39
+ text 'Battle!'
40
+ enabled <= [game.ship_collections[:you], :placed_count, on_read: ->(c) {c == 5}]
41
+
42
+ on_widget_selected do
43
+ game.battle!
44
+ @battle_button.enabled = false
45
+ end
46
+ }
47
+
48
+ button {
49
+ text 'Restart'
50
+
51
+ on_widget_selected do
52
+ game.reset!
53
+ end
54
+ }
55
+ }
56
+ }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,163 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class Battleship
23
+ module View
24
+ class Cell
25
+ include Glimmer::UI::CustomWidget
26
+
27
+ class << self
28
+ attr_accessor :dragging
29
+ alias dragging? dragging
30
+ end
31
+
32
+ COLOR_WATER = rgb(156, 211, 219)
33
+ COLOR_SHIP = :gray
34
+ COLOR_PLACED = :white
35
+ COLOR_EMPTY = :black
36
+ COLOR_NO_HIT = :white
37
+ COLOR_HIT = :red
38
+
39
+ options :game, :player, :row_index, :column_index, :ship
40
+ option :type, default: :grid # other type is :ship
41
+
42
+ body {
43
+ canvas {
44
+ if type == :grid
45
+ if player == :you
46
+ background <= [model, :ship, on_read: ->(s) {s ? COLOR_SHIP : COLOR_WATER}]
47
+ else
48
+ background COLOR_WATER
49
+ end
50
+ else
51
+ background <= [ship, :sunk, on_read: ->(s) {s ? COLOR_HIT : COLOR_PLACED}]
52
+ background <= [ship, :top_left_cell, on_read: ->(c) {c ? COLOR_PLACED : COLOR_SHIP}]
53
+ end
54
+
55
+ rectangle(0, 0, [:max, -1], [:max, -1])
56
+ oval(:default, :default, 10, 10) {
57
+ foreground <= [model, :hit, on_read: ->(h) {h == nil ? COLOR_EMPTY : (h ? COLOR_HIT : COLOR_NO_HIT)}]
58
+ }
59
+ oval(:default, :default, 5, 5) {
60
+ background <= [model, :hit, on_read: ->(h) {h == nil ? COLOR_EMPTY : (h ? COLOR_HIT : COLOR_NO_HIT)}]
61
+ }
62
+
63
+ on_mouse_move do |event|
64
+ if game.started?
65
+ if type == :grid
66
+ if player == :enemy
67
+ body_root.cursor = :cross
68
+ else
69
+ body_root.cursor = :arrow
70
+ end
71
+ else
72
+ body_root.cursor = :arrow
73
+ end
74
+ end
75
+ end
76
+
77
+ if player == :enemy
78
+ on_mouse_up do
79
+ game.attack!(row_index, column_index)
80
+ end
81
+ end
82
+
83
+ if player == :you
84
+ on_drag_detected do |event|
85
+ unless game.started? || game.over?
86
+ Cell.dragging = true
87
+ body_root.cursor = :hand if type == :grid
88
+ end
89
+ end
90
+
91
+ on_drag_set_data do |event|
92
+ the_ship = ship || model&.ship
93
+ if the_ship && !game.started? && !game.over? && !(type == :ship && the_ship.top_left_cell)
94
+ event.data = the_ship.name.to_s
95
+ else
96
+ event.doit = false
97
+ Cell.dragging = false
98
+ end
99
+ end
100
+
101
+ on_mouse_up do
102
+ unless game.started? || game.over?
103
+ Cell.dragging = false
104
+ change_cursor
105
+ end
106
+ end
107
+
108
+ if type == :grid
109
+ on_mouse_move do |event|
110
+ unless game.started? || game.over?
111
+ change_cursor
112
+ end
113
+ end
114
+
115
+ on_mouse_hover do |event|
116
+ unless game.started? || game.over?
117
+ change_cursor
118
+ end
119
+ end
120
+
121
+ on_mouse_up do |event|
122
+ unless game.started? || game.over?
123
+ begin
124
+ model.ship&.toggle_orientation!
125
+ rescue => e
126
+ Glimmer::Config.logger.debug e.full_message
127
+ end
128
+ change_cursor
129
+ end
130
+ end
131
+
132
+ on_drop do |event|
133
+ unless game.started? || game.over?
134
+ ship_name = event.data
135
+ place_ship(ship_name.to_s.to_sym) if ship_name
136
+ Cell.dragging = false
137
+ change_cursor
138
+ end
139
+ end
140
+ end
141
+ end
142
+ }
143
+ }
144
+
145
+ def model
146
+ game.grids[player].cell_rows[row_index][column_index] if type == :grid
147
+ end
148
+
149
+ def place_ship(ship_name)
150
+ ship = game.ship_collections[player].ships[ship_name]
151
+ model.place_ship!(ship)
152
+ end
153
+
154
+ def change_cursor
155
+ if type == :grid && model.ship && !Cell.dragging?
156
+ body_root.cursor = model.ship.orientation == :horizontal ? :sizens : :sizewe
157
+ elsif !Cell.dragging?
158
+ body_root.cursor = :arrow
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end