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/COPYING +340 -0
- data/ChangeLog +111 -0
- data/README +48 -0
- data/Rakefile +255 -0
- data/TODO +19 -0
- data/VERSION +1 -0
- data/bin/smagacor +23 -0
- data/data/smagacor/smagacor.png +0 -0
- data/data/smagacor/tictactoe/game.info +7 -0
- data/data/smagacor/tictactoe/o.png +0 -0
- data/data/smagacor/tictactoe/tictactoe.png +0 -0
- data/data/smagacor/tictactoe/tictactoe.rb +300 -0
- data/data/smagacor/tictactoe/x.png +0 -0
- data/install.rb +21 -0
- data/lib/smagacor/controller.rb +129 -0
- data/lib/smagacor/smagacor-ui.rb +230 -0
- data/setup.rb +1331 -0
- data/test/games/tictactoe/game.info +7 -0
- data/test/runtests.rb +2 -0
- data/test/smagacor/tc_controller.rb +48 -0
- metadata +69 -0
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
|
Binary file
|
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
|