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 ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ DeepBeige
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 David Bochenski
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.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = deepbeige
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 David Bochenski. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "deepbeige"
8
+ gem.summary = "An AI learning program that plays board games"
9
+ gem.description = "An AI learning program that plays board games"
10
+ gem.email = "david@bochenski.co.uk"
11
+ gem.homepage = "http://github.com/bochenski/deepbeige"
12
+ gem.authors = ["David Bochenski"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "deepbeige #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/arena.rb ADDED
@@ -0,0 +1,6 @@
1
+ #an arena is where tournaments are held
2
+ #Arenas can define and start tour
3
+ class Arena
4
+ def initialize
5
+ end
6
+ end
data/deep_beige.rb ADDED
@@ -0,0 +1,213 @@
1
+ require 'neural_net'
2
+
3
+ class DeepBeige
4
+
5
+ def initialize
6
+ @neural_net = NeuralNet.new
7
+ @population =[]
8
+ end
9
+
10
+ def id
11
+ @neural_net.id
12
+ end
13
+
14
+ def start_game game_name
15
+ @game_name = game_name
16
+ case game_name
17
+ when "NoughtsAndCrosses"
18
+ @neural_net.generate 9, 1, 3
19
+ @neural_net.load_from_file "DeepBeige/NoughtsAndCrosses/best.txt"
20
+ when "PickANumber"
21
+ @neural_net.generate 3,1,2
22
+ @neural_net.load_from_file "DeepBeige/PickANumber/best.txt"
23
+ end
24
+ end
25
+
26
+ def get_move position, moves
27
+ game = game_from_name @game_name
28
+ game.quiet = true
29
+ game.reload_position moves
30
+
31
+ best_move = ""
32
+ best_score = -2
33
+ game.legal_moves.each do |move|
34
+ game2 = game_from_name @game_name
35
+ game2.quiet = true
36
+ game2.reload_position moves
37
+ game2.play_move game.next_player, move
38
+ input = game2.current_position.values
39
+
40
+ if game.next_player == 1
41
+ input = []
42
+ game2.current_position.values.each do |value|
43
+ input << -value
44
+ end
45
+ end
46
+
47
+ @neural_net.input = input
48
+ @neural_net.evaluate
49
+ score = @neural_net.output_value
50
+ #p "move #{move} evaluated as #{score}"
51
+ if score > best_score
52
+ best_score = score
53
+ best_move = move
54
+ end
55
+ end
56
+ best_move
57
+ end
58
+
59
+ def learn game
60
+ generate_population 30, game.name
61
+ end
62
+
63
+ def train generations, game
64
+ @game_name = game.name
65
+ @population = load_population game.name
66
+
67
+ #reset scores
68
+ scores = {}
69
+ @population.each do |neuralnet|
70
+ scores[neuralnet.id] = 0
71
+ end
72
+
73
+ generation_number = 1
74
+ generations.times do
75
+ puts "Evolving Generation #{generation_number}"
76
+ player_number = 0
77
+ @population.each do |neuralnet|
78
+ player1 = DeepBeige.new
79
+ player1.neural_net = neuralnet
80
+ player1.game_name = @game_name
81
+
82
+ 5.times do
83
+ game = game.class.new
84
+ game.quiet = true
85
+ opponent_number = rand(@population.count)
86
+ #puts "#{player_number} versus opponent #{opponent_number}"
87
+ opponent_net = @population[opponent_number]
88
+ player2 = DeepBeige.new
89
+ player2.neural_net = opponent_net
90
+ player2.game_name = @game_name
91
+
92
+ players = [player1,player2]
93
+ table = Table.new game, players
94
+ table.quiet = true
95
+ table.play_game
96
+ if game.drawn?
97
+ players.each do |player|
98
+ scores[player.id] +=1
99
+ end
100
+
101
+ elsif game.won?
102
+ winner = players[game.winner]
103
+ players.each do |player|
104
+ if player.id == winner.id
105
+ scores[player.id] +=2
106
+ else
107
+ scores[player.id] -=2
108
+ end
109
+ end
110
+ end
111
+
112
+ end
113
+ player_number += 1
114
+ end
115
+ leaderboard = scores.sort_by {|id, count| count}
116
+ position = 1
117
+ 5.times do
118
+ leader = leaderboard[leaderboard.count - position]
119
+ puts "#{position}. pts: #{leader[1]}, #{leader[0]}"
120
+ position +=1
121
+ end
122
+ @population.each do |neural_net|
123
+ if neural_net.id == leaderboard.last[0]
124
+ neural_net.save_to_file "DeepBeige/#{@game_name}/best.txt"
125
+ end
126
+ end
127
+ i = 0
128
+ while i < 15 do
129
+ @population.delete_if {|neural_net| neural_net.id == leaderboard[i][0]}
130
+ i +=1
131
+ end
132
+
133
+ new_nets = []
134
+ @population.each do |neural_net|
135
+ new_net = neural_net.clone
136
+ new_net.mutate
137
+ new_nets << new_net
138
+ end
139
+ @population.concat new_nets
140
+
141
+ scores = {}
142
+ @population.each do |neural_net|
143
+ scores[neural_net.id] = 0
144
+ end
145
+
146
+ generation_number +=1
147
+ end
148
+
149
+ save_population game.name
150
+ end
151
+
152
+ protected
153
+ def neural_net= value
154
+ @neural_net = value
155
+ end
156
+ def game_name= value
157
+ @game_name = value
158
+ end
159
+
160
+ private
161
+ def game_from_name name
162
+ game = nil
163
+ case name
164
+ when "NoughtsAndCrosses"
165
+ game = NoughtsAndCrosses.new
166
+ when "PickANumber"
167
+ game = PickANumber.new
168
+ end
169
+ game
170
+ end
171
+
172
+ def load_population name
173
+ @population = []
174
+ Dir["deepbeige/#{name}/*[0-9].txt"].each do |filename|
175
+ candidate = NeuralNet.new
176
+ candidate.load_from_file filename
177
+ @population << candidate
178
+ end
179
+ @population
180
+ end
181
+
182
+ def save_population name
183
+ #and at the end of that, we ought to save our population
184
+ i = 0
185
+ @population.each do |neural_net|
186
+ neural_net.save_to_file "DeepBeige/#{name}/#{i}.txt"
187
+ i += 1
188
+ end
189
+ end
190
+
191
+ def generate_population size, name
192
+ #Generate Population
193
+ dir_name = "DeepBeige/#{name}"
194
+ unless FileTest::directory?(dir_name)
195
+ Dir::mkdir(dir_name)
196
+ end
197
+ @population = []
198
+ scores = {}
199
+ size.times do
200
+ neural_net = NeuralNet.new
201
+ case name
202
+ when "NoughtsAndCrosses"
203
+ neural_net.generate 9,1,3
204
+ when "PickANumber"
205
+ neural_net.generate 3,1,2
206
+ end
207
+ @population << neural_net
208
+ end
209
+ save_population name
210
+ end
211
+ end
212
+
213
+
data/deepbeige.gemspec ADDED
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{deepbeige}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["David Bochenski"]
12
+ s.date = %q{2010-09-04}
13
+ s.description = %q{An AI learning program that plays board games}
14
+ s.email = %q{david@bochenski.co.uk}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "arena.rb",
27
+ "deep_beige.rb",
28
+ "deepbeige.gemspec",
29
+ "game.rb",
30
+ "human.rb",
31
+ "lib/deepbeige.rb",
32
+ "main.rb",
33
+ "match.rb",
34
+ "neural_net.rb",
35
+ "node.rb",
36
+ "noughts_and_crosses.rb",
37
+ "pick_a_number.rb",
38
+ "player.rb",
39
+ "population/best.txt",
40
+ "table.rb",
41
+ "test/helper.rb",
42
+ "test/test_deepbeige.rb",
43
+ "tournament.rb",
44
+ "ui/Rakefile",
45
+ "ui/config/build.yml",
46
+ "ui/lib/application.rb",
47
+ "ui/lib/menu.rb",
48
+ "ui/resources/DeepBeige.icns"
49
+ ]
50
+ s.homepage = %q{http://github.com/bochenski/deepbeige}
51
+ s.rdoc_options = ["--charset=UTF-8"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = %q{1.3.7}
54
+ s.summary = %q{An AI learning program that plays board games}
55
+ s.test_files = [
56
+ "test/helper.rb",
57
+ "test/test_deepbeige.rb"
58
+ ]
59
+
60
+ if s.respond_to? :specification_version then
61
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
66
+ else
67
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
68
+ end
69
+ else
70
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
71
+ end
72
+ end
73
+
data/game.rb ADDED
@@ -0,0 +1,18 @@
1
+ class Game
2
+
3
+ def initialize
4
+ end
5
+
6
+ def display message
7
+ unless @quiet
8
+ p message
9
+ end
10
+ end
11
+
12
+ def reload_position moves
13
+ moves.each do |player, move|
14
+ self.play_move player, move
15
+ end
16
+ end
17
+
18
+ end
data/human.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'player'
2
+
3
+ class Human < Player
4
+ def initialize game
5
+ @game = game
6
+ end
7
+
8
+ def get_move position, moves
9
+ game = @game.class.new
10
+ game.reload_position moves
11
+ print game.show_board
12
+ move = gets.chop
13
+ end
14
+ end
data/lib/deepbeige.rb ADDED
File without changes
data/main.rb ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'game'
4
+ require 'pick_a_number'
5
+ require 'noughts_and_crosses'
6
+ require 'human'
7
+ require 'deep_beige'
8
+ require 'table'
9
+
10
+ def play_game game, p1, p2, options
11
+ players = [p1,p2]
12
+ table = Table.new game, players
13
+
14
+ options.each do |option|
15
+ if option == "verbose"
16
+ game.verbose = true
17
+ elsif option == "quiet"
18
+ game.quiet = true
19
+ table.quiet = true
20
+ end
21
+ end
22
+
23
+ table.play_game
24
+ end
25
+
26
+ def player_vs_deepbeige db, game
27
+ #ok so now I'm interested in playing my best creation
28
+ db.start_game game.name
29
+ me = Human.new game
30
+ play_game game, me, db, []
31
+ end
32
+
33
+ def player_vs_player game
34
+ p1 = Human.new game
35
+ p2 = Human.new game
36
+ play_game game, p1,p2, []
37
+ end
38
+
39
+ def options
40
+ puts
41
+ puts "What would you like to do?"
42
+ puts " 1. Player vs DeepBeige"
43
+ puts " 2. Train DeepBeige"
44
+ puts " 3. Reset DeepBeige"
45
+ puts " 4. Player vs Player"
46
+ puts " 5. Exit Application"
47
+ end
48
+
49
+ def game_choice
50
+ puts
51
+ puts "Which Game?"
52
+ puts " 1. Noughts and Crosses"
53
+ puts " 2. Pick A Number"
54
+ game = nil
55
+ case gets.chop
56
+ when "1"
57
+ game = NoughtsAndCrosses.new
58
+ when "2"
59
+ game = PickANumber.new
60
+ else
61
+ puts "Sorry, didn't understand you there."
62
+ end
63
+ game
64
+ end
65
+
66
+ #This is the main execution loop of our program
67
+ def main
68
+
69
+ db = DeepBeige.new
70
+
71
+ version = "0.1.1"
72
+ puts
73
+ puts "Welcome to DeepBeige v#{version}"
74
+
75
+ exit = false
76
+ until exit do
77
+ options
78
+ case input = gets.chop
79
+ when "1"
80
+ game = game_choice
81
+ player_vs_deepbeige db, game
82
+ when "2"
83
+ game = game_choice
84
+ puts "How Many Generations?"
85
+ generations = gets.chop.to_i
86
+ db.train generations, game
87
+ when "3"
88
+ game = game_choice
89
+ db.learn game
90
+ puts "DeepBeige Reset sucessfully"
91
+ when "4"
92
+ game = game_choice
93
+ player_vs_player game
94
+ when "5"
95
+ puts "Bye Bye"
96
+ exit = true
97
+ else
98
+ puts "Sorry I didn't understand you"
99
+ end
100
+ end
101
+ end
102
+
103
+ main unless $Cocoa
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
data/match.rb ADDED
@@ -0,0 +1,43 @@
1
+ #A match is a series of games between players
2
+ require 'rubygems'
3
+ require 'uuid'
4
+ require 'table'
5
+
6
+ class Match
7
+ def initialize players, first_to, game
8
+ @game = game
9
+ @players = players
10
+ @first_to = first_to
11
+ @player_wins = {}
12
+ players.each do |player|
13
+ @player_wins[player.id] = 0
14
+ end
15
+ end
16
+
17
+ def play
18
+ while leading_player[1] < @first_to
19
+ game = @game.class.new
20
+ table = Table.new game, @players
21
+ table.play_game
22
+ if game.winner
23
+ @player_wins[@players[game.winner].id] += 2
24
+ p "#{game.winner} won that game and has #{ @player_wins[@players[game.winner].id] } wins"
25
+ p "leading player is #{leading_player[0]} with #{leading_player[1]} wins"
26
+ elsif game.drawn?
27
+ @players.each do |player|
28
+ @player_wins[player.id] += 1
29
+ end
30
+ end
31
+ gets
32
+ end
33
+ end
34
+
35
+ def result
36
+ end
37
+
38
+ private
39
+ def leading_player
40
+ leaderboard = @player_wins.sort_by {|id, count| count}
41
+ leaderboard.last
42
+ end
43
+ end