bangkok 0.1.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.
@@ -0,0 +1,5 @@
1
+ 2005-03-24 Jim Menard <jimm@io.com>
2
+
3
+ * Initial project creation.
4
+
5
+
data/Credits ADDED
@@ -0,0 +1,6 @@
1
+ Bangkok is developed by Jim Menard <jimm@io.com> and originated from ideas and
2
+ conversations with Tom Peak <himself@tompeak.com>.
3
+
4
+ Additional bug fixes and suggestions have come from:
5
+
6
+ [nobody yet, since this is the first release.]
data/README ADDED
@@ -0,0 +1,227 @@
1
+ = Bangkok
2
+
3
+ Bangkok reads chess game descriptions and re-play the games. Notice of events
4
+ (moves, captures, checks, etc.) are sent to a listener. Bangkok comes with a
5
+ listener that generates a MIDI file. In other words, the chess game is turned
6
+ into music.
7
+
8
+ Bangkok originated as the code for an art project by Tom Peak
9
+ <himself@tompeak.com>.
10
+
11
+ The Web site of Bangkok is (http://bangkok.rubyforge.org). The RubyForge
12
+ project page is http://rubyforge.org/projects/bangkok, where the latest
13
+ version of bangkok may be downloaded. bangkok is also available as a RubyGem.
14
+
15
+
16
+ === Recent Changes
17
+
18
+ Since this is the first release, there's nothing to say.
19
+
20
+
21
+ == Dependencies
22
+
23
+ The MIDI generation portion of Bangkok requires midilib 0.8.4 or later. If you
24
+ install Bangkok as a RubyGem, it will fetch and install midilib for you.
25
+
26
+ The test suite in the tests directory requires the testing framework TestUnit,
27
+ which comes with Ruby 1.8 and later and can also be found in the Ruby
28
+ Application Archive (http://raa.ruby-lang.org).
29
+
30
+ To rebuild the gem or RDocs or run the tests easily, you can use the Rakefile
31
+ which requires Rake (http://rake.rubyforge.org).
32
+
33
+
34
+ == Installation
35
+
36
+ === RubyGems Installation
37
+
38
+ To install Bangkok as a gem, type
39
+
40
+ % gem install bangkok
41
+
42
+ You may need root privileges to install the gem.
43
+
44
+ === Manual Installation
45
+
46
+ After downloading and expanding the archive, you can install Bangkok with the
47
+ command
48
+
49
+ % ruby install.rb
50
+ (or)
51
+ % ruby install.rb --install-dir=my_directory
52
+
53
+ You may need root privileges to install Bangkok.
54
+
55
+
56
+ == Testing
57
+
58
+ % rake test
59
+
60
+ runs all of the tests in the test directory.
61
+
62
+
63
+ == Overview
64
+
65
+ Bangkok replays a chess game. It reads chess game .pgn files. Interesting
66
+ events during each game (moves, captures, checks, etc.) are sent to a
67
+ listener.
68
+
69
+ Bangkok comes with a GameListener that creates a MIDI sequence. The listener
70
+ is given to a ChessGame object, which then reads a .pgn file, creates a board,
71
+ gives the moves to the board so it can move the pieces, and tells the listener
72
+ when the game is over. At that time, the GameListener writes the MIDI sequence
73
+ out to a MIDI file.
74
+
75
+
76
+ == How to Use
77
+
78
+ === From the command line
79
+
80
+ Here is how to generate a MIDI file from a chess match file, using the
81
+ built-in GameListener. (This command line is awkward, and needs to get
82
+ simpler.)
83
+
84
+ % bangkok [-c my_program_changes.rb] chess_game_file.pgn
85
+
86
+ Running that command creates the MIDI file chess_game_file.mid. The optional
87
+ configuration file my_program_changes.rb lets you change the default program
88
+ numbers used for each of the pieces. See examples/program_changes.rb for an
89
+ example file.
90
+
91
+ For example, to run bangkok on the chess game in the examples directory, type
92
+
93
+ % bangkok examples/game.pgn
94
+
95
+ === Example Scripts and Files
96
+
97
+ Here are short descriptions of each of the files found in the examples
98
+ directory.
99
+
100
+ * examples/announcer.rb creates a new listener that "announces" the game by
101
+ printing some descriptive text for everything that happens during the game.
102
+
103
+ * examples/game.pgn is an example chess match.
104
+
105
+ * examples/program_changes.rb is an example configuration file that shows you
106
+ how to change the default program change values. The values in this file are
107
+ the same as the default values used by GameListener.
108
+
109
+
110
+ == The Code
111
+
112
+ Only one class has anything to do with MIDI at all: GameListener. The rest of
113
+ the classes in Bangkok know only about chess moves. This separation allows you
114
+ to use Bangkok for your own nefarious chess-related purposes, whether musical
115
+ or un-.
116
+
117
+ GameListener creates a MIDI sequence from the chess game's moves. When a piece
118
+ moves, MIDI notes are generated and a few controller values are set. Any
119
+ listener you write must implement the methods
120
+ * start_game(io)
121
+ * end_game
122
+ * move(piece, from_square, to_square)
123
+ * capture(attacker_piece, loser_piece)
124
+ * check
125
+ * checkmate
126
+ * pawn_to_queen(pawn)
127
+
128
+ For each move, the GameListener generates three sets of MIDI events: one for
129
+ the move start, one for a point halfway between the start and the destination,
130
+ and one for the destination. GameListener#midi_for_position creates a pan
131
+ value (left = queenside, right = kingside), a volume value (max = center of
132
+ board, min = top and bottom of board), and a quarter note. The note is from a
133
+ C scale, where the low C = the color's home rank and the high C = the opposite
134
+ color's home rank.
135
+
136
+ SPEAKER midi 1 - 8 SPEAKER (black)
137
+
138
+ low
139
+ ^
140
+ |
141
+ high
142
+ volume
143
+ |
144
+ v
145
+ low
146
+
147
+ <---- panning ---->
148
+
149
+ SPEAKER midi 9 - 16 SPEAKER (white)
150
+
151
+ ChessGame takes a listener in its constructor and creates a Board. The method
152
+ ChessGame#read_moves reads game data. Calling ChessGame#play moves the pieces,
153
+ which in turn sends messages to the listener so it can react. See bin/bangkok
154
+ and examples/announcer.rb for examples of how to use a ChessGame object.
155
+
156
+ Board creates pieces and hands moves to pieces. It tells the listener about
157
+ things like captures and castles.
158
+
159
+ A Square represents a location on a Board.
160
+
161
+ A Piece has a color and a Square. It tells the listener about its moves.
162
+ Subclasses of Piece such as Queen and Knight override
163
+ Piece#could_perform_move, which checks to see if that piece could move from
164
+ its current position to the move's destination square. could_perform_move is
165
+ called by the Board to determine which piece on the board needs to be moved.
166
+
167
+ A Move has a color, a destination square, an optional starting rank or file,
168
+ and optional modifiers such as check or capture. A castle Move has no
169
+ destination square (the Board moves the pieces).
170
+
171
+
172
+ == Resources
173
+
174
+ The Ruby Web site (http://www.ruby-lang.org/en/index.html) contains an
175
+ introduction to Ruby, the Ruby Application Archive (RAA) at
176
+ http://raa.ruby-lang.org, and pointers to more information.
177
+
178
+
179
+ _Programming Ruby, The Pragmatic Programmer's Guide_, by David Thomas
180
+ and Andrew Hunt, is a well-written and practical introduction to Ruby. Its Web
181
+ page at http://www.rubycentral.com/book also contains a wealth of Ruby
182
+ information. Though the book is available online, I encourage you to purchase
183
+ a copy of the second edition, available at
184
+ http://pragmaticprogrammer.com/titles/ruby/.
185
+
186
+ midilib's home is http://midilib.rubyforge.org.
187
+
188
+
189
+ = To Do
190
+
191
+ :include: TODO
192
+
193
+
194
+ = Support
195
+
196
+ * Visit the forums, bug list, and mailing list pages at
197
+ http://rubyforge.org/projects/bangkok
198
+
199
+ * Send email to Jim Menard at mailto:jimm@io.com
200
+
201
+ * Ask on the ruby-talk mailing list
202
+
203
+
204
+ = Administrivia
205
+
206
+ Author:: Jim Menard (mailto:jimm@io.com)
207
+ Copyright:: Copyright (c) 2005 Jim Menard
208
+ License:: Distributed under the same license as Ruby.
209
+
210
+
211
+ == Copying
212
+
213
+ Bangkok is copyrighted free software by Jim Menard and is released under the
214
+ same license as Ruby. See the Ruby license at
215
+ http://www.ruby-lang.org/en/LICENSE.txt.
216
+
217
+ Bangkok may be freely copied in its entirety providing this notice, all
218
+ source code, all documentation, and all other files are included.
219
+
220
+ Bangkok is Copyright (c) 2005 by Jim Menard.
221
+
222
+
223
+ == Warranty
224
+
225
+ This software is provided "as is" and without any express or implied
226
+ warranties, including, without limitation, the implied warranties of
227
+ merchantability and fitness for a particular purpose.
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require_gem 'rake'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/contrib/rubyforgepublisher'
6
+ require 'rake/runtest'
7
+
8
+ PROJECT_NAME = 'bangkok'
9
+ RUBYFORGE_USER = 'jimm'
10
+ RDOC_DIR = 'html'
11
+
12
+ PKG_FILES = FileList[ 'ChangeLog', 'Credits', 'README', 'Rakefile', 'TODO',
13
+ 'examples/**/*',
14
+ 'html/**/*',
15
+ 'install.rb',
16
+ 'lib/**/*.rb',
17
+ 'test/**/*.rb']
18
+
19
+ task :default => [:package]
20
+
21
+ spec = Gem::Specification.new do |s|
22
+ s.platform = Gem::Platform::RUBY
23
+ s.name = PROJECT_NAME
24
+ s.version = `ruby -Ilib -e 'require "bangkok/info"; puts Version'`.strip
25
+ s.requirements << 'midilib'
26
+ s.add_dependency('midilib', '>= 0.8.4')
27
+
28
+ s.require_path = 'lib'
29
+ s.autorequire = PROJECT_NAME
30
+
31
+ s.files = PKG_FILES.to_a
32
+ s.executables = ['bangkok']
33
+ s.bindir = 'bin'
34
+
35
+ s.has_rdoc = true
36
+ s.rdoc_options << '--main' << 'README'
37
+ s.extra_rdoc_files = ['README', 'TODO']
38
+
39
+ s.author = 'Jim Menard'
40
+ s.email = 'jimm@io.com'
41
+ s.homepage = 'http://bangkok.rubyforge.org'
42
+ s.rubyforge_project = PROJECT_NAME
43
+
44
+ s.summary = "Chess game file reader and player; can turn games into MIDI files"
45
+ s.description = <<EOF
46
+ Bangkok can read chess game descriptions and re-play the games. Notice of
47
+ events (moves, captures, checks, etc.) are sent to a listener. Bangkok comes
48
+ with a listener that generates a MIDI file. In other words, the chess game is
49
+ turned into music.
50
+ EOF
51
+ end
52
+
53
+ # Creates a :package task (also named :gem). Also useful are :clobber_package
54
+ # and :repackage.
55
+ Rake::GemPackageTask.new(spec) do |pkg|
56
+ pkg.need_zip = true
57
+ pkg.need_tar = true
58
+ end
59
+
60
+ # require 'rbconfig'
61
+ # if Config::CONFIG['target_os'] =~ /mswin/i
62
+ # RDOC_FILES = FileList['README', 'TODO', 'lib/**/*.rb']
63
+ # RDOC_FILES.each { | f | file f }
64
+ # task :rdoc => RDOC_FILES do
65
+ # ruby "#{File.join(Config::CONFIG['bindir'], 'rdoc')} -o html " +
66
+ # " --main 'README' --title '#{PROJECT_NAME}' -T 'html' #{RDOC_FILES}"
67
+ # end
68
+ # else
69
+ # creates an "rdoc" task
70
+ Rake::RDocTask.new do | rd |
71
+ rd.main = 'README'
72
+ rd.title = PROJECT_NAME
73
+ rd.rdoc_files.include('README', 'TODO', 'lib/**/*.rb')
74
+ end
75
+ # end
76
+
77
+ task :rubyforge => [:rdoc] do
78
+ Rake::RubyForgePublisher.new(PROJECT_NAME, RUBYFORGE_USER).upload
79
+ end
80
+
81
+ task :test do
82
+ Rake::run_tests
83
+ end
data/TODO ADDED
@@ -0,0 +1,26 @@
1
+ == Bugs
2
+
3
+ - Pawn#could_perform_move does not check for en passant.
4
+
5
+ - Move#initialize does not handle "e.p." or "ep" in move text.
6
+
7
+ == To Do
8
+
9
+ - better way to specify configs/program numbers; file must not live in same
10
+ directory as source code
11
+
12
+ - write "-c" code in bin/bangkok and examples
13
+
14
+ - test bankgok -c examples/program_changes.rb examples/game.pgn
15
+
16
+ - implement check for en passant in Pawn#could_perform_move. Might need a new
17
+ ivar @moved_two_spaces_on_first_move.
18
+
19
+ - glide between squares
20
+
21
+ - time to move relative to distance travelled (quarter note per unit;
22
+ length_to_delta(dist))
23
+
24
+ - configuration file: volume offset, min, max; other params
25
+
26
+ - more tests
@@ -0,0 +1,40 @@
1
+ require 'getoptlong'
2
+ begin
3
+ require 'bangkok/chessgame'
4
+ rescue LoadError
5
+ require 'rubygems'
6
+ require_gem 'bangkok/chessgame'
7
+ end
8
+
9
+ def usage
10
+ $stderr.puts <<EOS
11
+ usage: bangkok [-v] chessgame.pgn ...
12
+ -v Verbose (prints each move)
13
+ -h This message
14
+
15
+ Using the default GameListener, creates chessgame.mid for every chessgame.pgn.
16
+ To use your own GameListener, see the Bangkok README file.
17
+ EOS
18
+
19
+ exit 1
20
+ end
21
+
22
+ $verbose = false
23
+ g = GetoptLong.new(['-v', '--verbose', GetoptLong::NO_ARGUMENT],
24
+ ['-h', '--help', GetoptLong::NO_ARGUMENT])
25
+ g.each { | opt, arg |
26
+ case opt
27
+ when '-v'
28
+ $verbose = true
29
+ else
30
+ usage
31
+ end
32
+ }
33
+ usage if ARGV.length == 0
34
+
35
+ ARGV.each { | fname |
36
+ game = ChessGame.new
37
+ File.open(fname, 'r') { | f | game.read_moves(f) }
38
+ midi_file_name = File.basename(fname).sub(/(\..+)?$/
39
+ File.open(midi_file_name, '.mid'), 'wb') { | f | game.play(f) }
40
+ }
@@ -0,0 +1,71 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'getoptlong'
4
+ begin
5
+ require 'bangkok/chessgame'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require_gem 'bangkok/chessgame'
9
+ end
10
+
11
+ class Announcer
12
+ def start_game(io)
13
+ @out = io
14
+ @out.puts 'Start of game'
15
+ end
16
+
17
+ def end_game
18
+ @out.puts 'End of game'
19
+ end
20
+
21
+ def move(piece, from, to)
22
+ @out.puts "Piece #{piece} moving to #{to}"
23
+ end
24
+
25
+ def capture(attacker, loser)
26
+ @out.puts "#{attacker} captures #{loser}"
27
+ end
28
+
29
+ def check
30
+ @out.puts "Check"
31
+ end
32
+
33
+ def checkmate
34
+ @out.puts "Checkmate"
35
+ end
36
+
37
+ def pawn_to_queen(pawn)
38
+ @out.puts "#{pawn} has been turned into a queen"
39
+ end
40
+ end
41
+
42
+ def usage
43
+ $stderr.puts <<EOS
44
+ usage: announcer [-v] chessgame.pgn ...
45
+ -v Verbose (prints each move)
46
+ -h This message
47
+
48
+ For each chess game, prints each event to stdout.
49
+ EOS
50
+
51
+ exit 1
52
+ end
53
+
54
+ $verbose = false
55
+ g = GetoptLong.new(['-v', '--verbose', GetoptLong::NO_ARGUMENT],
56
+ ['-h', '--help', GetoptLong::NO_ARGUMENT])
57
+ g.each { | opt, arg |
58
+ case opt
59
+ when '-v'
60
+ $verbose = true
61
+ else
62
+ usage
63
+ end
64
+ }
65
+ usage if ARGV.length == 0
66
+
67
+ ARGV.each { | fname |
68
+ game = ChessGame.new(Announcer.new)
69
+ File.open(fname, 'r') { | f | game.read_moves(f) }
70
+ game.play($stdout)
71
+ }