deepbeige 0.2.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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/arena.rb +6 -0
- data/deep_beige.rb +213 -0
- data/deepbeige.gemspec +73 -0
- data/game.rb +18 -0
- data/human.rb +14 -0
- data/lib/deepbeige.rb +0 -0
- data/main.rb +114 -0
- data/match.rb +43 -0
- data/neural_net.rb +174 -0
- data/node.rb +106 -0
- data/noughts_and_crosses.rb +141 -0
- data/pick_a_number.rb +97 -0
- data/player.rb +4 -0
- data/population/best.txt +20 -0
- data/table.rb +22 -0
- data/test/helper.rb +10 -0
- data/test/test_deepbeige.rb +7 -0
- data/tournament.rb +1 -0
- data/ui/Rakefile +5 -0
- data/ui/config/build.yml +8 -0
- data/ui/lib/application.rb +47 -0
- data/ui/lib/menu.rb +32 -0
- data/ui/resources/DeepBeige.icns +0 -0
- metadata +106 -0
data/neural_net.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'uuid'
|
3
|
+
require 'node'
|
4
|
+
|
5
|
+
class NeuralNet
|
6
|
+
attr_accessor :input, :id
|
7
|
+
attr_reader :network
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@id = UUID.new.to_s.split(':')[1].chop
|
11
|
+
@network = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def evaluate
|
15
|
+
#we expect to find one input value in input for each of our input nodes
|
16
|
+
input_nodes = @network.first
|
17
|
+
|
18
|
+
i = 0
|
19
|
+
input_nodes.each do |node|
|
20
|
+
node.input_value = @input[i]
|
21
|
+
i += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
@network.each do |tier|
|
25
|
+
tier.each do |node|
|
26
|
+
node.evaluate
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
self.output
|
31
|
+
end
|
32
|
+
|
33
|
+
def output
|
34
|
+
@network.last
|
35
|
+
end
|
36
|
+
|
37
|
+
def output_value
|
38
|
+
value = 0
|
39
|
+
self.output.each do |node|
|
40
|
+
value += node.output_value
|
41
|
+
end
|
42
|
+
value
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate inputs, outputs, tiers
|
46
|
+
@network = []
|
47
|
+
input_nodes = []
|
48
|
+
inputs.times do
|
49
|
+
input_nodes << Node.new
|
50
|
+
end
|
51
|
+
if input_nodes.count > 0
|
52
|
+
@network << input_nodes
|
53
|
+
end
|
54
|
+
(tiers - 2).times do
|
55
|
+
tier = []
|
56
|
+
10.times do
|
57
|
+
tier << Node.new
|
58
|
+
end
|
59
|
+
@network << tier
|
60
|
+
end
|
61
|
+
|
62
|
+
output_nodes = []
|
63
|
+
outputs.times do
|
64
|
+
output_nodes << Node.new
|
65
|
+
end
|
66
|
+
if output_nodes.count >0
|
67
|
+
@network << output_nodes
|
68
|
+
end
|
69
|
+
link_tiers
|
70
|
+
end
|
71
|
+
|
72
|
+
def fingerprint
|
73
|
+
topline = ""
|
74
|
+
fingerprint = ""
|
75
|
+
@network.each do |tier|
|
76
|
+
topline << "#{tier.count},"
|
77
|
+
tier.each do |node|
|
78
|
+
fingerprint << node.fingerprint
|
79
|
+
end
|
80
|
+
end
|
81
|
+
topline.chop + "\n" + fingerprint
|
82
|
+
end
|
83
|
+
|
84
|
+
def reload fingerprint
|
85
|
+
#fingerprint contains an array of strings
|
86
|
+
i = 0
|
87
|
+
tiers = fingerprint[i].split(',').to_a
|
88
|
+
i += 1
|
89
|
+
|
90
|
+
@network = []
|
91
|
+
tiers.each do |tier|
|
92
|
+
nodes = []
|
93
|
+
tier.to_i.times do
|
94
|
+
node_fingerprint = fingerprint[i]
|
95
|
+
i += 1
|
96
|
+
node = Node.new
|
97
|
+
node.reload node_fingerprint
|
98
|
+
nodes << node
|
99
|
+
end
|
100
|
+
@network << nodes
|
101
|
+
end
|
102
|
+
|
103
|
+
link_tiers
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
#Nets can make small changes (mutations) to themselves
|
108
|
+
def mutate
|
109
|
+
#for the time being we won't take on
|
110
|
+
#the ability to mutate the number of
|
111
|
+
#nodes and their configuration
|
112
|
+
#focussing instead on simple node weight mutation
|
113
|
+
@network.each do |tier|
|
114
|
+
tier.each do |node|
|
115
|
+
node.mutate
|
116
|
+
end
|
117
|
+
end
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
def clone
|
122
|
+
clone = NeuralNet.new
|
123
|
+
#iterate in through each tier
|
124
|
+
@network.each do |tier|
|
125
|
+
nodes = []
|
126
|
+
tier.each do |node|
|
127
|
+
cloned_node = node.clone
|
128
|
+
cloned_node.detatch_all_forward_nodes
|
129
|
+
nodes << cloned_node
|
130
|
+
end
|
131
|
+
clone.network << nodes
|
132
|
+
end
|
133
|
+
#now relink the network
|
134
|
+
clone.link_tiers
|
135
|
+
#and send back our clone
|
136
|
+
clone
|
137
|
+
end
|
138
|
+
|
139
|
+
def save_to_file file
|
140
|
+
File.open(file, 'w') do |f|
|
141
|
+
f.puts id
|
142
|
+
f.write(self.fingerprint)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def load_from_file file
|
147
|
+
fingerprint = []
|
148
|
+
File.open(file, 'r') do |f|
|
149
|
+
@id = f.gets.chop
|
150
|
+
while line = f.gets do
|
151
|
+
fingerprint << line
|
152
|
+
end
|
153
|
+
end
|
154
|
+
reload fingerprint
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
def link_tiers
|
159
|
+
#first cut lets link every node on a tier to each node on the subsequent tier
|
160
|
+
i = 1
|
161
|
+
@network.each do |tier|
|
162
|
+
if i < @network.count
|
163
|
+
tier.each do |node|
|
164
|
+
j = 0
|
165
|
+
@network[i].each do |next_node|
|
166
|
+
node.attach_forward_node next_node, j
|
167
|
+
j += 1
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
i +=1
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/node.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
class Node
|
2
|
+
attr_reader :forward_nodes, :output_value
|
3
|
+
attr_accessor :input_value, :deviation, :weights
|
4
|
+
def initialize
|
5
|
+
@forward_nodes = {}
|
6
|
+
@weights =[]
|
7
|
+
@input_value = 0
|
8
|
+
@deviation = rand / 4
|
9
|
+
end
|
10
|
+
#take our input value, pass it through our sigmoid function (tanh)
|
11
|
+
#and then pass on our output value to each of our forward nodes
|
12
|
+
def evaluate
|
13
|
+
@output_value = Math.tanh(@input_value)
|
14
|
+
#p "output value #{@output_value}"
|
15
|
+
@forward_nodes.each do |node, weight|
|
16
|
+
#p "weight #{weight} old input #{node.input_value}"
|
17
|
+
node.input_value += @output_value * weight
|
18
|
+
#p "new input #{node.input_value}"
|
19
|
+
end
|
20
|
+
@input_value = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def attach_forward_node node, sequence
|
24
|
+
if @weights.count <= sequence
|
25
|
+
@weights << rand
|
26
|
+
end
|
27
|
+
|
28
|
+
@forward_nodes[node] = @weights[sequence]
|
29
|
+
end
|
30
|
+
|
31
|
+
def detatch_all_forward_nodes
|
32
|
+
@forward_nodes = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def mutate
|
36
|
+
new_weights = []
|
37
|
+
@weights.each do |weight|
|
38
|
+
new_weights << gaussian_random * @deviation + weight # new_random_number = gaussian_rand * standard_deviation + average
|
39
|
+
end
|
40
|
+
@weights = new_weights
|
41
|
+
if @forward_values
|
42
|
+
i = 0
|
43
|
+
@forward_values.each do |key,value|
|
44
|
+
@forward_values[key] = @weights[i]
|
45
|
+
i += 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#and now mutate the deviation
|
50
|
+
@deviation = (gaussian_random * @deviation)/2 + @deviation
|
51
|
+
end
|
52
|
+
|
53
|
+
def breed
|
54
|
+
end
|
55
|
+
|
56
|
+
def clone
|
57
|
+
clone = Node.new
|
58
|
+
|
59
|
+
clone.deviation = self.deviation
|
60
|
+
@weights.each do |weight|
|
61
|
+
clone.weights << weight
|
62
|
+
end
|
63
|
+
|
64
|
+
#being pure we clone the forward node refs as well
|
65
|
+
#although in practice these are about to be updated with new nodes
|
66
|
+
self.forward_nodes.each do |key,value|
|
67
|
+
clone.forward_nodes[key] = value
|
68
|
+
end
|
69
|
+
|
70
|
+
clone
|
71
|
+
end
|
72
|
+
|
73
|
+
def fingerprint
|
74
|
+
fingerprint = "#{@deviation}:"
|
75
|
+
@weights.each do |weight|
|
76
|
+
fingerprint += "#{weight.to_s},"
|
77
|
+
end
|
78
|
+
fingerprint = fingerprint.chop + "\n"
|
79
|
+
end
|
80
|
+
|
81
|
+
def reload fingerprint
|
82
|
+
self.detatch_all_forward_nodes
|
83
|
+
@weights = []
|
84
|
+
self.deviation = fingerprint.split(':')[0].to_f
|
85
|
+
if fingerprint.split(":").count == 2
|
86
|
+
fingerprint.split(":")[1].split(',').each do |weight|
|
87
|
+
@weights << weight.to_f
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def gaussian_random
|
94
|
+
u1 = u2 = w = g1 = g2 = 0 # declare
|
95
|
+
begin
|
96
|
+
u1 = 2 * rand - 1
|
97
|
+
u2 = 2 * rand - 1
|
98
|
+
w = u1 * u1 + u2 * u2
|
99
|
+
end while w >= 1
|
100
|
+
|
101
|
+
w = Math::sqrt( ( -2 * Math::log(w)) / w )
|
102
|
+
g2 = u1 * w;
|
103
|
+
g1 = u2 * w;
|
104
|
+
# g1 is returned
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'game'
|
2
|
+
class NoughtsAndCrosses < Game
|
3
|
+
|
4
|
+
attr_reader :winner, :move_list, :next_player
|
5
|
+
attr_accessor :quiet, :verbose
|
6
|
+
def initialize
|
7
|
+
@position = {:A1 => 0, :B1 => 0, :C1 => 0, :A2 => 0, :B2 => 0, :C2 => 0, :A3 => 0, :B3 => 0, :C3 => 0}
|
8
|
+
@next_player = 0
|
9
|
+
@move_list = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
"NoughtsAndCrosses"
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_board
|
17
|
+
board = " - - - \n"
|
18
|
+
i = 0
|
19
|
+
@position.each do |move|
|
20
|
+
i += 1
|
21
|
+
board += "|"
|
22
|
+
if move[1] == 0
|
23
|
+
board += " "
|
24
|
+
elsif move[1] == 1
|
25
|
+
board += "X"
|
26
|
+
else
|
27
|
+
board += "O"
|
28
|
+
end
|
29
|
+
|
30
|
+
if i == 3
|
31
|
+
board += "|\n _ _ _\n"
|
32
|
+
i = 0
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
board
|
37
|
+
end
|
38
|
+
|
39
|
+
def legal_moves
|
40
|
+
legal_moves = []
|
41
|
+
@position.each do |move|
|
42
|
+
if move[1] == 0
|
43
|
+
legal_moves << move[0].to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
legal_moves
|
47
|
+
end
|
48
|
+
|
49
|
+
def play_move(player, move)
|
50
|
+
sym_move = move.to_sym
|
51
|
+
unless player == @next_player
|
52
|
+
display "not player #{player}'s turn"
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
unless @position[sym_move] == 0
|
56
|
+
display "illegal move by player #{player}"
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
if won?
|
60
|
+
display "player #{winner} has already won"
|
61
|
+
return false
|
62
|
+
elsif drawn?
|
63
|
+
display "game was drawn"
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
|
67
|
+
@move_list << [player,move]
|
68
|
+
|
69
|
+
if player == 1
|
70
|
+
@position[sym_move] = 1
|
71
|
+
else
|
72
|
+
@position[sym_move] = -1
|
73
|
+
end
|
74
|
+
if won?
|
75
|
+
display "player #{player} wins!"
|
76
|
+
@winner = player
|
77
|
+
elsif drawn?
|
78
|
+
display "game drawn"
|
79
|
+
end
|
80
|
+
|
81
|
+
if @next_player == 1
|
82
|
+
@next_player = 0
|
83
|
+
else
|
84
|
+
@next_player = 1
|
85
|
+
end
|
86
|
+
if @verbose
|
87
|
+
display show_board
|
88
|
+
display @position
|
89
|
+
end
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
def current_position
|
94
|
+
return @position
|
95
|
+
end
|
96
|
+
|
97
|
+
def won?
|
98
|
+
if @position[:A1] != 0
|
99
|
+
if @position[:A1] == @position[:A2] && @position[:A2] == @position[:A3]
|
100
|
+
return true
|
101
|
+
elsif @position[:A1] == @position[:B2] && @position[:B2] == @position[:C3]
|
102
|
+
return true
|
103
|
+
elsif @position[:A1] == @position[:B1] && @position[:B1] == @position[:C1]
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
if @position[:B1] != 0
|
108
|
+
if @position[:B1] == @position[:B2] && @position[:B2] == @position[:B3]
|
109
|
+
return true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
if @position[:C1] != 0
|
113
|
+
if @position[:C1] == @position[:C2] && @position[:C2] == @position[:C3]
|
114
|
+
return true
|
115
|
+
elsif @position[:C1] == @position[:B2] && @position[:B2] == @position[:A3]
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if @position[:A2] != 0
|
120
|
+
if @position[:A2] == @position[:B2] && @position[:B2] == @position[:C2]
|
121
|
+
return true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
if @position[:A3] != 0
|
125
|
+
if @position[:A3] == @position[:B3] && @position[:B3] == @position[:C3]
|
126
|
+
return true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
false
|
130
|
+
end
|
131
|
+
|
132
|
+
def drawn?
|
133
|
+
unless legal_moves.count == 0
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
if won?
|
137
|
+
return false
|
138
|
+
end
|
139
|
+
true
|
140
|
+
end
|
141
|
+
end
|
data/pick_a_number.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'game'
|
2
|
+
|
3
|
+
class PickANumber < Game
|
4
|
+
|
5
|
+
attr_reader :winner, :move_list, :next_player
|
6
|
+
attr_accessor :quiet, :verbose
|
7
|
+
def initialize
|
8
|
+
@position = {"1" => 0,"2" => 0, "3" => 0}
|
9
|
+
@next_player = 0
|
10
|
+
@move_list = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
"PickANumber"
|
15
|
+
end
|
16
|
+
|
17
|
+
def legal_moves
|
18
|
+
legal_moves = []
|
19
|
+
@position.each do |move|
|
20
|
+
if move[1] == 0
|
21
|
+
legal_moves << move[0].to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
legal_moves
|
25
|
+
end
|
26
|
+
|
27
|
+
def show_board
|
28
|
+
board = "Please Pick from the following Numbers:\n"
|
29
|
+
|
30
|
+
@position.each do |move|
|
31
|
+
if move[1] == 0
|
32
|
+
board += "#{move[0]},"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
board +"\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
def play_move(player, move)
|
39
|
+
unless player == @next_player
|
40
|
+
display "not player #{player}'s turn"
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
unless @position[move] == 0
|
44
|
+
display "illegal move by player #{player}"
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
if won?
|
48
|
+
display "player #{winner} has already won"
|
49
|
+
return false
|
50
|
+
elsif drawn?
|
51
|
+
display "game was drawn"
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
|
55
|
+
@move_list << [player,move]
|
56
|
+
|
57
|
+
if player == 1
|
58
|
+
@position[move] = 1
|
59
|
+
else
|
60
|
+
@position[move] = -1
|
61
|
+
end
|
62
|
+
if won?
|
63
|
+
display "player #{player} wins!"
|
64
|
+
@winner = player
|
65
|
+
elsif drawn?
|
66
|
+
display "game drawn"
|
67
|
+
end
|
68
|
+
|
69
|
+
if @next_player == 1
|
70
|
+
@next_player = 0
|
71
|
+
else
|
72
|
+
@next_player = 1
|
73
|
+
end
|
74
|
+
if @verbose
|
75
|
+
display @position
|
76
|
+
end
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def current_position
|
81
|
+
return @position
|
82
|
+
end
|
83
|
+
|
84
|
+
def won?
|
85
|
+
if @position["3"] != 0
|
86
|
+
return true
|
87
|
+
end
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
def drawn?
|
92
|
+
if @position["2"] != 0
|
93
|
+
return true
|
94
|
+
end
|
95
|
+
false
|
96
|
+
end
|
97
|
+
end
|
data/player.rb
ADDED
data/population/best.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
9,9,1
|
2
|
+
1.9888959877114751:1.1713694063264486,0.2131550943633837,-1.4389857774549193,-2.3761064404471623,1.4125388307828852,1.7962657856192086,3.98673652586089,-0.710563267563527,-4.693733927431782
|
3
|
+
-0.5537104997469708:4.353881179541187,-3.7749306975412615,3.9092173844936307,-1.5574066495330294,-1.9867317023123854,2.4016056161982515,0.19093366894771083,2.583574894805702,-0.7814428807197851
|
4
|
+
-3.718402720378594:0.21375589104869108,-0.5952570280952669,3.163222183572866,-2.0666315462205604,1.8466894347641758,2.5737190736563127,0.09083797921525782,-1.7152005515495705,-1.9147906116034963
|
5
|
+
-1.1774113223565559:0.9684176432281265,1.2633322113651906,0.9105205858738161,0.9952880033669778,2.428832023642873,1.1378171183057832,1.2346794709653666,1.614577823722882,-0.5727461748243102
|
6
|
+
-4.240095691598348:5.619686966308787,2.496099436318761,4.236594219999468,-4.089909848411157,-8.583782402447191,7.909784634413837,3.709149525845639,-0.1221209138110586,-1.7739191236891263
|
7
|
+
-0.45644848049775455:0.7525477703501269,0.4416094908434702,0.5151634042799693,0.6494784464984971,-0.21066540646710413,0.9328293326003011,0.4934365894119864,-0.5075989699963754,0.2534248521563641
|
8
|
+
2.000438515839109:-0.18715599814429473,-4.079321241532847,3.0082374216290035,1.6554995963981736,1.2134208468740142,-0.7234607792621472,0.9168360804604427,-0.5284806911574953,3.6316017295618748
|
9
|
+
0.9920544697574241:-0.15133215482382756,0.9977877837645512,-0.06456539820799904,-1.0288035250624143,0.9008138652841244,0.6826185088601288,0.8553527568600676,0.21975379677495055,1.0495630337690707
|
10
|
+
3.8437737235828924:-2.429075885974877,3.0482320934712477,-9.512832982617503,-8.273686259303359,1.5413233764892178,-2.2156195050047747,-7.2849426757667315,5.202236097167509,-0.9365606034293558
|
11
|
+
2.4821899389695874:2.1743832447567346
|
12
|
+
-2.9564446473766672:-3.2541845089551904
|
13
|
+
3.2605627963240384:-0.20795953070592393
|
14
|
+
2.605813320828736:3.154050922464929
|
15
|
+
-0.4579599997104075:2.349414728456047
|
16
|
+
2.653465191369256:4.365018317781122
|
17
|
+
0.6373485836872791:1.7163198231060346
|
18
|
+
0.711515408592374:0.8702577537323323
|
19
|
+
-1.7351499679943323:1.24799151515672
|
20
|
+
2.902919261517124
|
data/table.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#A Table is where players come to play a game (possibly as part of a match as part of a tournament if required)
|
2
|
+
#Essentially a Table is a Game Controller
|
3
|
+
class Table
|
4
|
+
attr_reader :players, :games
|
5
|
+
attr_accessor :quiet
|
6
|
+
|
7
|
+
def initialize game, players
|
8
|
+
@game = game
|
9
|
+
@players = players
|
10
|
+
end
|
11
|
+
|
12
|
+
def play_game
|
13
|
+
until @game.won? || @game.drawn?
|
14
|
+
next_player = @players[@game.next_player]
|
15
|
+
move = next_player.get_move @game.current_position, @game.move_list
|
16
|
+
unless @quiet
|
17
|
+
p "player #{@game.next_player} plays move #{move }"
|
18
|
+
end
|
19
|
+
@game.play_move @game.next_player, move
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/helper.rb
ADDED
data/tournament.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
#A tournament is a series of matches between a set of players
|
data/ui/Rakefile
ADDED
data/ui/config/build.yml
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
$Cocoa = true
|
2
|
+
require 'rubygems'
|
3
|
+
require 'hotcocoa'
|
4
|
+
$: << File.expand_path(File.dirname(__FILE__)) + "/../../"
|
5
|
+
require 'main.rb'
|
6
|
+
|
7
|
+
|
8
|
+
class Application
|
9
|
+
|
10
|
+
include HotCocoa
|
11
|
+
|
12
|
+
def start
|
13
|
+
application :name => "Deep Beige" do |app|
|
14
|
+
app.delegate = self
|
15
|
+
window :frame => [100, 100, 500, 500], :title => "Test" do |win|
|
16
|
+
win << label(:text => "Hello from Deep Beige", :layout => {:start => false})
|
17
|
+
win.will_close { exit }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# file/open
|
23
|
+
def on_open(menu)
|
24
|
+
end
|
25
|
+
|
26
|
+
# file/new
|
27
|
+
def on_new(menu)
|
28
|
+
end
|
29
|
+
|
30
|
+
# help menu item
|
31
|
+
def on_help(menu)
|
32
|
+
end
|
33
|
+
|
34
|
+
# This is commented out, so the minimize menu item is disabled
|
35
|
+
#def on_minimize(menu)
|
36
|
+
#end
|
37
|
+
|
38
|
+
# window/zoom
|
39
|
+
def on_zoom(menu)
|
40
|
+
end
|
41
|
+
|
42
|
+
# window/bring_all_to_front
|
43
|
+
def on_bring_all_to_front(menu)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Application.new.start
|
data/ui/lib/menu.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module HotCocoa
|
2
|
+
def application_menu
|
3
|
+
menu do |main|
|
4
|
+
main.submenu :apple do |apple|
|
5
|
+
apple.item :about, :title => "About #{NSApp.name}"
|
6
|
+
apple.separator
|
7
|
+
apple.item :preferences, :key => ","
|
8
|
+
apple.separator
|
9
|
+
apple.submenu :services
|
10
|
+
apple.separator
|
11
|
+
apple.item :hide, :title => "Hide #{NSApp.name}", :key => "h"
|
12
|
+
apple.item :hide_others, :title => "Hide Others", :key => "h", :modifiers => [:command, :alt]
|
13
|
+
apple.item :show_all, :title => "Show All"
|
14
|
+
apple.separator
|
15
|
+
apple.item :quit, :title => "Quit #{NSApp.name}", :key => "q"
|
16
|
+
end
|
17
|
+
main.submenu :file do |file|
|
18
|
+
file.item :new, :key => "n"
|
19
|
+
file.item :open, :key => "o"
|
20
|
+
end
|
21
|
+
main.submenu :window do |win|
|
22
|
+
win.item :minimize, :key => "m"
|
23
|
+
win.item :zoom
|
24
|
+
win.separator
|
25
|
+
win.item :bring_all_to_front, :title => "Bring All to Front", :key => "o"
|
26
|
+
end
|
27
|
+
main.submenu :help do |help|
|
28
|
+
help.item :help, :title => "#{NSApp.name} Help"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
Binary file
|