smagacor 0.0.1

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/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