ficsr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.markdown +4 -0
- data/Rakefile +2 -0
- data/autotest/discover.rb +4 -0
- data/ficsr.gemspec +26 -0
- data/lib/ficsr.rb +4 -0
- data/lib/ficsr/game.rb +74 -0
- data/lib/ficsr/session.rb +84 -0
- data/lib/ficsr/version.rb +3 -0
- data/spec-integration/ficsr_spec.rb +44 -0
- data/spec/game_spec.rb +108 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
data/Rakefile
ADDED
data/ficsr.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ficsr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ficsr"
|
7
|
+
s.version = Ficsr::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Thilko Richter"]
|
10
|
+
s.email = [""]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Ruby library for the free internet chess server}
|
13
|
+
s.description = %q{Administration of games any other various thing are possible}
|
14
|
+
|
15
|
+
s.rubyforge_project = "ficsr"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency('rspec', "~> 2.6.0")
|
23
|
+
s.add_development_dependency('autotest', "~> 4.4.6")
|
24
|
+
s.add_development_dependency('autotest-growl', "~> 0.2.9")
|
25
|
+
s.add_development_dependency('autotest-fsevent', "~> 0.2.5")
|
26
|
+
end
|
data/lib/ficsr.rb
ADDED
data/lib/ficsr/game.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module Ficsr
|
2
|
+
|
3
|
+
CATEGORIES = { :b => :blitz, :s => :standard, :B => :Bughouse, :l => :lightning,
|
4
|
+
:w => :wild, :L => :losers, :u => :untimed, :x => :atomic,
|
5
|
+
:S => :Suicide, :e => :examined_game, :z => :crazyhouse
|
6
|
+
}
|
7
|
+
class Game
|
8
|
+
def initialize(game_def)
|
9
|
+
game_regexp = %r{
|
10
|
+
(?<number>^\d*){0}
|
11
|
+
(?<white_rating>\S*){0}
|
12
|
+
(?<white_handle>\S*){0}
|
13
|
+
(?<black_rating>\S*){0}
|
14
|
+
(?<black_handle>\S*){0}
|
15
|
+
(?<private>p?){0}
|
16
|
+
(?<category>\w?){0}
|
17
|
+
(?<rated>\w?){0}
|
18
|
+
(?<start_minutes>\d*){0}
|
19
|
+
(?<increment_seconds>\d*){0}
|
20
|
+
(?<time_white>\d*:\d*:?\d*){0}
|
21
|
+
(?<time_black>\d*:\d*:?\d*){0}
|
22
|
+
(?<strength_white>\d*){0}
|
23
|
+
(?<strength_black>\d*){0}
|
24
|
+
(?<turn>[WB]){0}
|
25
|
+
(?<move_number>\d*){0}
|
26
|
+
|
27
|
+
\g<number>\s*\g<white_rating>\s*\g<white_handle>\s*\g<black_rating>\s*\g<black_handle>\s*\[\g<private>\s*
|
28
|
+
\g<category>\s*\g<rated>\s*\g<start_minutes>\s*\g<increment_seconds>\]\s*\g<time_white>\s*-\s*
|
29
|
+
\g<time_black>\s*\(\s*\g<strength_white>\s*-\s*\g<strength_black>\)\s\g<turn>:\s*\g<move_number>$
|
30
|
+
|
31
|
+
}x
|
32
|
+
|
33
|
+
match_data = game_def.match(game_regexp)
|
34
|
+
if match_data
|
35
|
+
self.number = match_data[:number].to_i
|
36
|
+
self.white_rating = match_data[:white_rating]
|
37
|
+
self.white_handle = match_data[:white_handle]
|
38
|
+
self.black_rating = match_data[:black_rating]
|
39
|
+
self.black_handle = match_data[:black_handle]
|
40
|
+
self.private = !match_data[:private].empty?
|
41
|
+
self.category_id = match_data[:category].to_sym
|
42
|
+
self.rated = match_data[:rated]
|
43
|
+
self.start_minutes = match_data[:start_minutes].to_i
|
44
|
+
self.increment_seconds = match_data[:increment_seconds].to_i
|
45
|
+
self.time_white = match_data[:time_white]
|
46
|
+
self.time_black = match_data[:time_black]
|
47
|
+
self.strength_white = match_data[:strength_white].to_i
|
48
|
+
self.strength_black = match_data[:strength_black].to_i
|
49
|
+
self.turn = match_data[:turn]
|
50
|
+
self.move_number = match_data[:move_number].to_i
|
51
|
+
else
|
52
|
+
p "ignoring game '#{game_def}'"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_accessor :number, :white_rating, :white_handle, :black_rating, :black_handle, :private, :category_id, :rated, :start_minutes, :increment_seconds, :time_white, :time_black, :strength_white, :strength_black, :turn, :move_number
|
57
|
+
|
58
|
+
def private?
|
59
|
+
self.private
|
60
|
+
end
|
61
|
+
|
62
|
+
def category
|
63
|
+
CATEGORIES[self.category_id]
|
64
|
+
end
|
65
|
+
|
66
|
+
def rated?
|
67
|
+
self.rated == "r"
|
68
|
+
end
|
69
|
+
|
70
|
+
def whites_turn?
|
71
|
+
self.turn == "W"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Ficsr
|
2
|
+
class Session
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def login(username, password="")
|
6
|
+
new(username, password)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :username, :password
|
11
|
+
|
12
|
+
def initialize(username, password)
|
13
|
+
@username = username
|
14
|
+
@password = password
|
15
|
+
|
16
|
+
send username, /password|is not a registered name/
|
17
|
+
|
18
|
+
if registered?
|
19
|
+
send password, /fics|login/
|
20
|
+
else
|
21
|
+
send "\n", /#{username}/
|
22
|
+
end
|
23
|
+
raise "Unable to login with username #{username} " unless logged_in?
|
24
|
+
end
|
25
|
+
|
26
|
+
def games
|
27
|
+
send "games", /fics/
|
28
|
+
last_result.split("\n\r").select { |line| line =~ /^\d{3}\s\w{1,4}.*$/ }.collect do |game|
|
29
|
+
Ficsr::Game.new game
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def observe(game_number, &action)
|
34
|
+
t = Thread.new do
|
35
|
+
send "observe #{game_number}", /fics/
|
36
|
+
last_result.each_line("\n\r") do |line|
|
37
|
+
action.call(line) if line =~/^<12>/
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
t.join
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def connection
|
47
|
+
@connection ||= Net::Telnet.new "Host" => host, "Port" => port, "Prompt" => default_prompt
|
48
|
+
end
|
49
|
+
|
50
|
+
def logged_in?
|
51
|
+
last_result.include?("Starting FICS session as #{username}")
|
52
|
+
end
|
53
|
+
|
54
|
+
def send(cmd, match="", opts={}, &actions)
|
55
|
+
all_opts = {"String" => cmd, "Match" => match}.merge opts
|
56
|
+
|
57
|
+
if block_given?
|
58
|
+
@last_result = connection.cmd(all_opts, &actions)
|
59
|
+
else
|
60
|
+
@last_result = connection.cmd(all_opts)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def last_result
|
65
|
+
@last_result
|
66
|
+
end
|
67
|
+
|
68
|
+
def registered?
|
69
|
+
last_result =~ /is a registered name/
|
70
|
+
end
|
71
|
+
|
72
|
+
def host
|
73
|
+
"freechess.org"
|
74
|
+
end
|
75
|
+
|
76
|
+
def port
|
77
|
+
5000
|
78
|
+
end
|
79
|
+
|
80
|
+
def default_prompt
|
81
|
+
/fics/
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "ficsr"
|
2
|
+
|
3
|
+
describe Ficsr::Session do
|
4
|
+
describe ".login" do
|
5
|
+
context "with valid credentials" do
|
6
|
+
it "performs a successful login" do
|
7
|
+
@session = Ficsr::Session.login ENV["ficsr_username"], ENV["ficsr_password"]
|
8
|
+
@session.should_not be_nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with invalid credentials" do
|
13
|
+
it "does not login" do
|
14
|
+
expect { Ficsr::Session.login "blackhacker", "xxx" }.to
|
15
|
+
raise_error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with an anonymous user" do
|
20
|
+
it "does a login" do
|
21
|
+
@session = Ficsr::Session.login "someanonymous"
|
22
|
+
@session.should_not be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:session) { Ficsr::Session.login ENV["ficsr_username"], ENV["ficsr_password"] }
|
28
|
+
|
29
|
+
describe "#games" do
|
30
|
+
it "returns a list of games" do
|
31
|
+
session.games.each { |game| game.should be_a Ficsr::Game }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#observe" do
|
36
|
+
let(:game_number) { session.games.first.number }
|
37
|
+
it "starts observing the game" do
|
38
|
+
session.observe game_number do |move|
|
39
|
+
p "MOVE: #{move}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/spec/game_spec.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require "ficsr"
|
2
|
+
|
3
|
+
GAME = "302 1221 vinayakghol ++++ Bhuvi [psr 15 20] 16:38 - 15:08 (37-39) W: 13"
|
4
|
+
|
5
|
+
describe Ficsr::Game do
|
6
|
+
describe ".new" do
|
7
|
+
it "creates a new game object from the given string" do
|
8
|
+
Ficsr::Game.new(GAME).should be_a Ficsr::Game
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:game) { Ficsr::Game.new GAME }
|
13
|
+
|
14
|
+
describe "#number" do
|
15
|
+
it "returns the number of the game " do
|
16
|
+
game.number.should == 302
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#white_handle" do
|
21
|
+
it "returns the handle of the white player " do
|
22
|
+
game.white_handle.should == "vinayakghol"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#white_rating" do
|
27
|
+
it "returns the rating of the white player " do
|
28
|
+
game.white_rating.should == "1221"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
describe "#black_handle" do
|
32
|
+
it "returns the handle of the black player " do
|
33
|
+
game.black_handle.should == "Bhuvi"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#black_rating" do
|
38
|
+
it "returns the rating of the white player " do
|
39
|
+
game.black_rating.should == "++++"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#private?" do
|
44
|
+
it "returns true if the game is private" do
|
45
|
+
game.should be_private
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#category" do
|
50
|
+
it "returns the category" do
|
51
|
+
game.category.should == :standard
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#rated?" do
|
56
|
+
it "returns true for a rated game" do
|
57
|
+
game.should be_rated
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#start_minutes" do
|
62
|
+
it "returns the minuted each player get at the beginning" do
|
63
|
+
game.start_minutes.should == 15
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#increment_seconds" do
|
68
|
+
it "returns true for a rated game" do
|
69
|
+
game.increment_seconds.should == 20
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#time_white" do
|
74
|
+
it "returns the remaining time of white" do
|
75
|
+
game.time_white.should == "16:38"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#time_black" do
|
80
|
+
it "returns the remaining time of black" do
|
81
|
+
game.time_black.should == "15:08"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#strength_white" do
|
86
|
+
it "returns the strength of white" do
|
87
|
+
game.strength_white.should == 37
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#strength_black" do
|
92
|
+
it "returns the strength of black" do
|
93
|
+
game.strength_black.should == 39
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#whites_turn?" do
|
98
|
+
it "return true if it is whites turn" do
|
99
|
+
game.should be_whites_turn
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#move_number" do
|
104
|
+
it "return the current move number of white/black" do
|
105
|
+
game.move_number == 13
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ficsr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thilko Richter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-09-22 00:00:00 +02:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 2.6.0
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: autotest
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 4.4.6
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: autotest-growl
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.2.9
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: autotest-fsevent
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.2.5
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
description: Administration of games any other various thing are possible
|
61
|
+
email:
|
62
|
+
- ""
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files: []
|
68
|
+
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- README.markdown
|
73
|
+
- Rakefile
|
74
|
+
- autotest/discover.rb
|
75
|
+
- ficsr.gemspec
|
76
|
+
- lib/ficsr.rb
|
77
|
+
- lib/ficsr/game.rb
|
78
|
+
- lib/ficsr/session.rb
|
79
|
+
- lib/ficsr/version.rb
|
80
|
+
- spec-integration/ficsr_spec.rb
|
81
|
+
- spec/game_spec.rb
|
82
|
+
has_rdoc: true
|
83
|
+
homepage: ""
|
84
|
+
licenses: []
|
85
|
+
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: "0"
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: "0"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: ficsr
|
106
|
+
rubygems_version: 1.5.2
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Ruby library for the free internet chess server
|
110
|
+
test_files:
|
111
|
+
- spec/game_spec.rb
|