smagacor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,255 @@
1
+ # -*- ruby -*-
2
+ #
3
+ # $Id$
4
+ #
5
+ # smagacor - a collection of small games in ruby
6
+ # Copyright (C) 2004 Thomas Leitner
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
9
+ # General Public License as published by the Free Software Foundation; either version 2 of the
10
+ # License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
13
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along with this program; if not,
17
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ #
19
+
20
+
21
+ begin
22
+ require 'rubygems'
23
+ require 'rake/gempackagetask'
24
+ rescue Exception
25
+ nil
26
+ end
27
+
28
+ require 'rake/clean'
29
+ require 'rake/packagetask'
30
+ require 'rake/rdoctask'
31
+ require 'rake/testtask'
32
+
33
+ # General actions ##############################################################
34
+
35
+ $:.push "lib"
36
+ require 'smagacor/controller'
37
+
38
+ PKG_NAME = "smagacor"
39
+ PKG_VERSION = Smagacor::VERSION.join( '.' )
40
+ PKG_FULLNAME = PKG_NAME + "-" + PKG_VERSION
41
+ PKG_SUMMARY = "A collection of small games in ruby"
42
+ PKG_DESCRIPTION = "Smagacor is a collection of some small games,
43
+ like TicTacToe and Pong. Adding new games should not be to hard,
44
+ as Smagacor provides some useful classes for games."
45
+
46
+
47
+ SRC_RB = FileList['lib/**/*.rb', 'bin/**/*', 'data/**/*.rb']
48
+
49
+
50
+ # The default task is run if rake is given no explicit arguments.
51
+
52
+ desc "Default Task"
53
+ task :default => :version
54
+
55
+
56
+ # End user tasks ################################################################
57
+
58
+ desc "Prepares for installation"
59
+ task :prepare do
60
+ ruby "setup.rb config"
61
+ ruby "setup.rb setup"
62
+ end
63
+
64
+
65
+ desc "Installs the package #{PKG_NAME}"
66
+ task :install => [:prepare] do
67
+ ruby "setup.rb install"
68
+ end
69
+
70
+
71
+ task :clean do
72
+ ruby "setup.rb clean"
73
+ end
74
+
75
+
76
+ CLOBBER << "doc/output" << FileList['texput.*'].to_a
77
+ desc "Builds the documentation (needs webgen installed)"
78
+ task :doc => [:rdoc, :gen_version] do
79
+ chdir "doc" do
80
+ sh "webgen -V 3"
81
+ end
82
+ end
83
+
84
+ rd = Rake::RDocTask.new do |rdoc|
85
+ rdoc.rdoc_dir = 'doc/output/rdoc'
86
+ rdoc.title = PKG_NAME
87
+ rdoc.options << '--line-numbers' << '--inline-source' << '-m README'
88
+ rdoc.rdoc_files.include( 'README' )
89
+ rdoc.rdoc_files.include( SRC_RB )
90
+ end
91
+
92
+ task 'test' do |t|
93
+ ruby "-Ilib -Itest test/runtests.rb"
94
+ end
95
+
96
+ # Developer tasks ##############################################################
97
+
98
+ PKG_FILES = FileList.new( [
99
+ 'setup.rb',
100
+ 'install.rb',
101
+ 'TODO',
102
+ 'COPYING',
103
+ 'README',
104
+ 'Rakefile',
105
+ 'ChangeLog',
106
+ 'VERSION',
107
+ 'bin/**/*',
108
+ 'lib/**/*',
109
+ 'doc/**/*',
110
+ 'test/**/*',
111
+ 'data/**/*'
112
+ ]) do |fl|
113
+ fl.exclude( /\bsvn\b/ )
114
+ fl.exclude( 'doc/output' )
115
+ end
116
+
117
+ task :package => [:gen_files] do
118
+ chdir 'pkg' do
119
+ sh "rpaadmin packport #{PKG_NAME}-#{PKG_VERSION}"
120
+ end
121
+ end
122
+
123
+ task :gen_changelog do
124
+ sh "svn log -r HEAD:1 -v > ChangeLog"
125
+ end
126
+
127
+ task :gen_version do
128
+ puts "Generating VERSION file"
129
+ File.open( 'VERSION', 'w+' ) do |file| file.write( PKG_VERSION + "\n" ) end
130
+ end
131
+
132
+ task :gen_installrb do
133
+ puts "Generating install.rb file"
134
+ File.open( 'install.rb', 'w+' ) do |file|
135
+ file.write "
136
+ require 'rpa/install'
137
+
138
+ class Install_#{PKG_NAME} < RPA::Install::FullInstaller
139
+ name '#{PKG_NAME}'
140
+ version '#{PKG_VERSION}-1'
141
+ classification Application
142
+ build do
143
+ installdocs %w[COPYING ChangeLog TODO]
144
+ installdocs 'docs'
145
+ installrdoc %w[README] + Dir['lib/**/*.rb']
146
+ installdata
147
+ end
148
+ description <<-EOF
149
+ #{PKG_SUMMARY}
150
+
151
+ #{PKG_DESCRIPTION}
152
+ EOF
153
+ end
154
+ "
155
+ end
156
+ end
157
+
158
+ task :gen_files => [:gen_changelog, :gen_version, :gen_installrb]
159
+ CLOBBER << "ChangeLog" << "VERSION" << "install.rb"
160
+
161
+ Rake::PackageTask.new( PKG_NAME, PKG_VERSION ) do |p|
162
+ p.need_tar = true
163
+ p.need_zip = true
164
+ p.package_files = PKG_FILES
165
+ end
166
+
167
+ if defined? Gem
168
+ spec = Gem::Specification.new do |s|
169
+
170
+ #### Basic information
171
+
172
+ s.name = PKG_NAME
173
+ s.version = PKG_VERSION
174
+ s.summary = PKG_SUMMARY
175
+ s.description = PKG_DESCRIPTION
176
+
177
+ #### Dependencies, requirements and files
178
+
179
+ s.files = PKG_FILES.to_a
180
+
181
+ s.autorequire = nil
182
+ s.executables = [ 'smagacor']
183
+ s.default_executable = 'smagacor'
184
+
185
+ #### Documentation
186
+
187
+ s.has_rdoc = true
188
+ s.extra_rdoc_files = rd.rdoc_files.reject do |fn| fn =~ /\.rb$/ end.to_a
189
+ s.rdoc_options = ['--line-numbers', '-m README']
190
+
191
+ #### Author and project details
192
+
193
+ s.author = "Thomas Leitner"
194
+ s.email = "t_leitner@gmx.at"
195
+ s.homepage = "smagacor.rubyforge.org"
196
+ s.rubyforge_project = "smagacor"
197
+ end
198
+
199
+ Rake::GemPackageTask.new( spec ) do |pkg|
200
+ pkg.need_zip = true
201
+ pkg.need_tar = true
202
+ end
203
+ end
204
+
205
+ =begin
206
+ desc "Creates a tag in the repository"
207
+ task :tag do
208
+ repositoryPath = File.dirname( $1 ) if `svn info` =~ /^URL: (.*)$/
209
+ fail "Tag already created in repository " if /#{PKG_FULLNAME}/ =~ `svn ls #{repositoryPath}/versions`
210
+ sh "svn cp -m 'Created version #{PKG_FULLNAME}' #{repositoryPath}/trunk/#{PKG_NAME} #{repositoryPath}/versions/#{PKG_FULLNAME}"
211
+ end
212
+ =end
213
+
214
+ desc "Upload documentation to homepage"
215
+ task :uploaddoc => [:doc] do
216
+ Dir.chdir('doc/output')
217
+ sh "scp -r * gettalong@rubyforge.org:/var/www/gforge-projects/#{PKG_NAME}/"
218
+ end
219
+
220
+
221
+ # Misc tasks ###################################################################
222
+
223
+
224
+ def count_lines( filename )
225
+ lines = 0
226
+ codelines = 0
227
+ open( filename ) do |f|
228
+ f.each do |line|
229
+ lines += 1
230
+ next if line =~ /^\s*$/
231
+ next if line =~ /^\s*#/
232
+ codelines += 1
233
+ end
234
+ end
235
+ [lines, codelines]
236
+ end
237
+
238
+
239
+ def show_line( msg, lines, loc )
240
+ printf "%6s %6s %s\n", lines.to_s, loc.to_s, msg
241
+ end
242
+
243
+ desc "Show statistics"
244
+ task :statistics do
245
+ total_lines = 0
246
+ total_code = 0
247
+ show_line( "File Name", "Lines", "LOC" )
248
+ SRC_RB.each do |fn|
249
+ lines, codelines = count_lines fn
250
+ show_line( fn, lines, codelines )
251
+ total_lines += lines
252
+ total_code += codelines
253
+ end
254
+ show_line( "Total", total_lines, total_code )
255
+ end
data/TODO ADDED
@@ -0,0 +1,19 @@
1
+ ---- CURRENT ----
2
+
3
+ * help -> help for current game
4
+ * make splitter not moveable
5
+ * make splitter hideable
6
+ * implement Pong
7
+ * implement UNDO mechanism
8
+ * implement State saver
9
+ * TicTacToe AI opponent (on base of mini-max, nega-max,...)
10
+ * complete tests
11
+
12
+ ---- FUTURE ----
13
+
14
+ * implement Sokoban
15
+
16
+ ---- DONE ----
17
+
18
+ * BUG: log window should stay behind main window
19
+ * BUG: rake install broken on windows
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/smagacor ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #
4
+ # $Id$
5
+ #
6
+ # smagacor - a collection of small games in ruby
7
+ # Copyright (C) 2004 Thomas Leitner
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10
+ # General Public License as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License along with this program; if not,
18
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+
21
+ require 'smagacor/smagacor-ui'
22
+
23
+ Smagacor::SmagacorUI.new.start
Binary file
@@ -0,0 +1,7 @@
1
+ --- !thomasleitner,2004/gameinfo
2
+ name: TicTacToe
3
+ icon: tictactoe.png
4
+ file: tictactoe.rb
5
+ classname: Smagacor::TicTacToe::TicTacToeUI
6
+ description: This is the well known game TicTacToe
7
+ category: Board Games
Binary file
@@ -0,0 +1,300 @@
1
+ #
2
+ #--
3
+ #
4
+ # $Id: tictactoe.rb 190 2005-02-02 19:26:25Z thomas $
5
+ #
6
+ # smagacor - a collection of small games in ruby
7
+ # Copyright (C) 2004 Thomas Leitner
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10
+ # General Public License as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License along with this program; if not,
18
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ #++
21
+ #
22
+ require 'observer'
23
+
24
+ module Smagacor
25
+
26
+ # TicTacToe for Smagacor
27
+ module TicTacToe
28
+
29
+ # Base player class
30
+ class Player
31
+
32
+ # Defines whether the player can currently make a move. Default is +false+.
33
+ attr_accessor :can_move
34
+
35
+ # Return a new player.
36
+ def initialize
37
+ @can_move = false
38
+ end
39
+
40
+ # Invoked by the game engine to get the move.
41
+ def move() end
42
+
43
+ end
44
+
45
+
46
+ # Human player. Provides the interface for a human to play TicTacToe.
47
+ class HumanPlayer < Player
48
+
49
+ def initialize
50
+ super
51
+ @field = -1
52
+ end
53
+
54
+ # See Player#move
55
+ def move
56
+ self.can_move = false
57
+ @field
58
+ end
59
+
60
+ # Set the +field+ which is returned by the next #move. <tt>can_move</tt> is set to +true+ so
61
+ # that the game engine knows the this player has chosen a field.
62
+ def set_field( field )
63
+ @field = field
64
+ self.can_move = true
65
+ end
66
+
67
+ end
68
+
69
+
70
+ # AI computer player. Not yet implemented!
71
+ class ComputerPlayer < Player
72
+
73
+ def move
74
+ end
75
+
76
+ end
77
+
78
+
79
+ # The TicTacToe board.
80
+ class Board < String
81
+
82
+ # Defines the empty field.
83
+ FIELD_EMPTY = ?-
84
+
85
+ def initialize( size )
86
+ super( FIELD_EMPTY.chr * size )
87
+ end
88
+
89
+ # Redefined each so that the methods from Enumerable work correctly.
90
+ def each( &block )
91
+ each_byte( &block )
92
+ end
93
+
94
+ end
95
+
96
+
97
+ # Game engine for TicTacToe. Knows how to correctly play TicTacToe.
98
+ class TicTacToe
99
+
100
+ include Observable
101
+
102
+ # The board on which is played.
103
+ attr_accessor :board
104
+
105
+ # Create a new TicTacToe game with the given +players+.
106
+ def initialize( players )
107
+ @players = players
108
+ @board = Board.new( 9 )
109
+ end
110
+
111
+ # Return the current player if the game has been initialized.
112
+ def cur_player
113
+ @players[@cur_player] if @cur_player < 2
114
+ end
115
+
116
+ # Initialize the game state.
117
+ def init
118
+ @board = Board.new( 9 )
119
+ @cur_player = 0
120
+ end
121
+
122
+ # Play one (or more) round(s) of a TicTacToe game. When the current player can make a move
123
+ # (Player#can_move), his move is verified and the board changed. Then it is the turn of the
124
+ # other player. As long as the current player can make a move (and the game is not finished),
125
+ # the method runs. When the current player cannot make a move, the method exists and it has to
126
+ # be called again, when the current player can make his move.
127
+ def play_round
128
+ while @players[@cur_player].can_move && !game_finished?
129
+ logger.info { "Current board: #{@board}" }
130
+ logger.info { "Current player: #{cur_player}" }
131
+ field = @players[@cur_player].move
132
+ logger.info { "Field selected: #{field}" }
133
+ if @board[field] == Board::FIELD_EMPTY
134
+ @board[field] = @cur_player.to_s
135
+ @cur_player = 1 - @cur_player
136
+ changed
137
+ notify_observers( :move )
138
+ end
139
+ end
140
+ if game_finished?
141
+ logger.info { " Game finished" }
142
+ changed
143
+ notify_observers( :finished, player_won )
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ # True if the board is full.
150
+ def board_full?
151
+ @board.all? {|i| i != Board::FIELD_EMPTY}
152
+ end
153
+
154
+ # Win situations.
155
+ WIN_SITUATIONS = [[0,1,2], [3,4,5], [6,7,8], [0,3,6],
156
+ [1,4,7], [2,5,8], [0,4,8], [2,4,6]]
157
+
158
+ # True if the game is over
159
+ def game_finished?
160
+ board_full? || player_won?( ?0 ) || player_won?( ?1 )
161
+ end
162
+
163
+ # Return the number of the player who has won.
164
+ #
165
+ # Returns
166
+ # 0:: player 1
167
+ # 1:: player 2
168
+ # 2:: draw
169
+ # -1:: game not finished yet
170
+ def player_won
171
+ ( player_won?( ?0 ) ? 0 : ( player_won?( ?1 ) ? 1 : ( board_full? ? 2 : -1 ) ) )
172
+ end
173
+
174
+ # Check if +player+ has won the game.
175
+ def player_won?( player )
176
+ WIN_SITUATIONS.each {|a,b,c| return true if @board[a] == player && @board[b] == player && @board[c] == player }
177
+ return false
178
+ end
179
+
180
+ end
181
+
182
+
183
+ # Widget for TicTacToe.
184
+ class TicTacToeUI < FXHorizontalFrame
185
+
186
+ attr_reader :gameinfo
187
+
188
+ def initialize( p, gameinfo )
189
+ super( p )
190
+ @gameinfo = gameinfo
191
+
192
+ @canvas = FXCanvas.new( self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y )
193
+ @canvas.connect( SEL_PAINT, method( :onPaint ) )
194
+ @canvas.connect( SEL_LEFTBUTTONRELEASE, method( :onCanvasClick ) )
195
+ FXVerticalSeparator.new( self )
196
+ options = FXVerticalFrame.new( self, LAYOUT_FILL_Y )
197
+
198
+ p = Proc.new do |name|
199
+ FXLabel.new( options, name )
200
+ box = FXComboBox.new( options, 20, 2, nil, 0, COMBOBOX_NORMAL|COMBOBOX_STATIC|FRAME_SUNKEN )
201
+ box.appendItem( 'Human', HumanPlayer )
202
+ box.appendItem( 'Computer', ComputerPlayer )
203
+ box
204
+ end
205
+ @player1 = p.call( 'Player 1' )
206
+ @player2 = p.call( 'Player 2' )
207
+
208
+ FXButton.new( options, "Start Game", nil, nil, 0, LAYOUT_FILL_X|BUTTON_NORMAL ).connect( SEL_COMMAND, method( :onStartGame ) )
209
+
210
+ @xicon = File.join( gameinfo.directory, 'x.png' )
211
+ @oicon = File.join( gameinfo.directory, 'o.png' )
212
+ end
213
+
214
+ def create
215
+ super
216
+ end
217
+
218
+ def onCanvasClick( sender, sel, event )
219
+ if !@game.nil? && @game.cur_player.respond_to?( :set_field )
220
+ width, padding = get_lengths
221
+ pos = Proc.new do |point|
222
+ case point
223
+ when 0..(padding + width/3): 0
224
+ when (padding + width/3)..(padding + width*2/3): 1
225
+ else 2
226
+ end
227
+ end
228
+ @game.cur_player.set_field( pos[event.click_x] + pos[event.click_y]*3 )
229
+ @game.play_round
230
+ end
231
+ end
232
+
233
+ def onStartGame( sender, sel, event )
234
+ p = [@player1.getItemData( @player1.currentItem ).new, @player2.getItemData( @player2.currentItem ).new ]
235
+ @canvas.update
236
+ @game = TicTacToe.new( p)
237
+ @game.add_observer( self )
238
+ @game.init
239
+ @game.play_round
240
+ end
241
+
242
+ def update( reason, winner=nil )
243
+ case reason
244
+ when :move: @canvas.update
245
+ when :finished
246
+ msg = (winner < 2 ? "Player #{winner+1}" : "Nobody" ) + " has won!"
247
+ FXMessageBox.information( self, MBOX_OK, "Result", msg )
248
+ end
249
+ end
250
+
251
+ def onPaint( sender, sel, event )
252
+ FXDCWindow.new( sender, event ) do |dc|
253
+ dc.foreground = FXColor::White
254
+ dc.fillRectangle( 0, 0, sender.width, sender.height )
255
+ paintPlayArea( dc )
256
+ paintCurGame( dc )
257
+ end
258
+ end
259
+
260
+ private
261
+
262
+ def get_lengths
263
+ width = (@canvas.width > @canvas.height ? @canvas.height : @canvas.width )
264
+ [(width * 0.8).to_i, (width * 0.1).to_i]
265
+ end
266
+
267
+ def paintPlayArea( dc )
268
+ width, padding = get_lengths
269
+ dc.foreground = FXColor::Black
270
+ dc.lineWidth = 10
271
+ dc.lineCap = CAP_ROUND
272
+ dc.drawLine( padding + width/3, padding, padding + width/3, padding + width )
273
+ dc.drawLine( padding + width*2/3, padding, padding + width*2/3, padding + width )
274
+ dc.drawLine( padding, padding + width/3, padding + width, padding + width/3 )
275
+ dc.drawLine( padding, padding + width*2/3, padding + width, padding + width*2/3 )
276
+ end
277
+
278
+ def paintCurGame( dc )
279
+ unless @game.nil?
280
+ width, padding = get_lengths
281
+ size = width/5
282
+ padding = padding + (width/3 - size)/2
283
+ @game.board.each_with_index do |item, index|
284
+ case item
285
+ when ?0
286
+ dc.foreground = FXColor::Red
287
+ dc.drawRectangle( padding + width/3 * (index % 3), padding + width/3 * (index / 3), size, size )
288
+ when ?1
289
+ dc.foreground = FXColor::Green
290
+ dc.drawCircle( padding + size/2 + width/3 * (index % 3), padding + size/2 + width/3 * (index / 3), size/2 )
291
+ end
292
+ end
293
+ end
294
+ end
295
+
296
+ end
297
+
298
+ end
299
+
300
+ end
Binary file
data/install.rb ADDED
@@ -0,0 +1,21 @@
1
+
2
+ require 'rpa/install'
3
+
4
+ class Install_smagacor < RPA::Install::FullInstaller
5
+ name 'smagacor'
6
+ version '0.0.1-1'
7
+ classification Application
8
+ build do
9
+ installdocs %w[COPYING ChangeLog TODO]
10
+ installdocs 'docs'
11
+ installrdoc %w[README] + Dir['lib/**/*.rb']
12
+ installdata
13
+ end
14
+ description <<-EOF
15
+ A collection of small games in ruby
16
+
17
+ Smagacor is a collection of some small games,
18
+ like TicTacToe and Pong. Adding new games should not be to hard,
19
+ as Smagacor provides some useful classes for games.
20
+ EOF
21
+ end