stzjb_server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1a5a39c936a6d498c4a683d88a6efdb6aa6734f1
4
+ data.tar.gz: 57f4d24d1c468109e186b02610dde4f26466ec79
5
+ SHA512:
6
+ metadata.gz: 19a27b121f10421f5302c2c5581a590f529fa6c674bad37e4d13a151943e9c0a7317b12239c1b19d12d161813d0abb5e95cf067318289db1bde70a86389b237b
7
+ data.tar.gz: 39e8a0b4b86171e23f698fd9e04d8eb8e10c28139dc03d8b08f346e1a5dce569e6feb3a34e85dcb062dd019ee49a5243757ac94f9366285524e743eb405d0a14
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ application.yml
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://ruby.taobao.org'
2
+
3
+ # Specify your gem's dependencies in stzjb_server.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ # StjzbServer
2
+
3
+ 石头剪子布服务端
4
+
5
+ ## Installation
6
+
7
+ $ gem install stjzb_server
8
+
9
+ ## Run
10
+
11
+ $ cd stjzb_server && ruby application.rb
12
+
13
+ ## Play
14
+
15
+ see https://github.com/takafan/stjzb
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,40 @@
1
+ # 1. 简易登录
2
+ # 2. 随机对战 pvp1
3
+ # 3. 好友对战 pvp2
4
+ # 4. 对电脑 pve
5
+
6
+ require File.expand_path('../lib/stjzb_server', __FILE__)
7
+
8
+ players = {} # login: websocket
9
+
10
+ EM::WebSocket.start(host: Settings.host, port: Settings.port) do |ws|
11
+ ws.onopen { |handshake|
12
+ ws.send_message_welcome
13
+ puts "#{ws.object_id} opened"
14
+ }
15
+
16
+ ws.onclose {
17
+ ws.logout(players)
18
+ puts "#{ws.object_id} closed"
19
+ }
20
+
21
+ ws.onmessage { |msg|
22
+ act, val = Oj.load(msg)
23
+ case act
24
+ when 'simple-login' # 简易登录
25
+ ws.simple_login(val, players)
26
+ when 'logout' # 登出
27
+ ws.logout(players)
28
+ when 'pvp1' # 随机对战
29
+ ws.pvp1(players)
30
+ when 'pvp2'
31
+ ws.pvp2(val, players)
32
+ when 'cancel-matching'
33
+ ws.cancel_matching
34
+ when 'escape-pvp'
35
+ ws.escape_pvp
36
+ when 'stjzb'
37
+ ws.stjzb(val)
38
+ end
39
+ }
40
+ end
@@ -0,0 +1,2 @@
1
+ host: 0.0.0.0
2
+ port: 8080
@@ -0,0 +1,215 @@
1
+ module EventMachine
2
+ module WebSocket
3
+ class Connection
4
+ attr_accessor :loginname, :current_opponent, :current_friend_loginname, :pvp_state, :pvp1_wins, :matching_retry_times,
5
+ :current_battle, :current_win_rounds, :current_action
6
+
7
+ IDLE = 1
8
+ MATCHING = 2
9
+ BATTLING = 3
10
+
11
+ def simple_login(loginname, players)
12
+ if loginname.nil? || loginname.empty?
13
+ loginname = players['takafan'] ? 'ayumi' : 'takafan'
14
+ end
15
+
16
+ old_ws = players[loginname]
17
+ if old_ws && old_ws != self
18
+ old_ws.logout players, '你在别的地方登录了'
19
+ end
20
+ players[loginname] = self
21
+ @loginname = loginname
22
+ @current_opponent = nil
23
+ @pvp_state = IDLE
24
+ @pvp1_wins = 0
25
+ send_message_simple_logined
26
+ puts "#{loginname} logined, players.size: #{players.size}"
27
+ end
28
+
29
+ def logout(players, reason = nil)
30
+ if @loginname
31
+ loginname = @loginname
32
+ escape_pvp
33
+ cancel_matching
34
+
35
+ @loginname = nil
36
+ @pvp1_wins = 0
37
+ send_message_loggedout(reason)
38
+
39
+ players.delete loginname
40
+ puts "#{loginname} logged out, players.size: #{players.size}"
41
+
42
+ loginname
43
+ end
44
+ end
45
+
46
+ # 随机对战
47
+ def pvp1(players)
48
+ if @loginname && players[@loginname]
49
+ @pvp_state = MATCHING
50
+ @matching_retry_times = 0
51
+ send_message_pvp1_ready
52
+ puts "#{@loginname} random battle ready, state: #{@pvp_state}"
53
+
54
+ matching1(players)
55
+ end
56
+ end
57
+
58
+ # 好友对战
59
+ def pvp2(friend_loginname, players)
60
+ if @loginname && players[@loginname] && friend_loginname && !friend_loginname.empty? && @loginname != friend_loginname
61
+ @pvp_state = MATCHING
62
+ @matching_retry_times = 0
63
+ @current_friend_loginname = friend_loginname
64
+ send_message_pvp2_ready friend_loginname
65
+ puts "#{@loginname} friend battle ready, state: #{@pvp_state}"
66
+
67
+ matching2(players)
68
+ end
69
+ end
70
+
71
+ def cancel_matching(reason = nil)
72
+ if @pvp_state == MATCHING
73
+ friend_loginname = @current_friend_loginname
74
+ @pvp_state = IDLE
75
+ @current_friend_loginname = nil
76
+ send_message_matching_canceled(reason)
77
+
78
+ friend_loginname
79
+ end
80
+ end
81
+
82
+ def escape_pvp
83
+ if @pvp_state == BATTLING && @current_opponent
84
+ @current_opponent.win("#{@loginname} 逃跑了")
85
+ end
86
+ end
87
+
88
+ def win(reason = nil)
89
+ @current_battle = nil
90
+ @pvp_state = IDLE
91
+ if @current_friend_loginname
92
+ @current_friend_loginname = nil
93
+ else
94
+ @pvp1_wins += 1
95
+ end
96
+ send_message_won(reason)
97
+ @current_opponent.current_battle = nil
98
+ @current_opponent.pvp_state = IDLE
99
+ @current_opponent.current_friend_loginname = nil
100
+ @current_opponent.send_message_lost
101
+ end
102
+
103
+ def stjzb(action)
104
+ @current_battle.act(self, action) if @current_battle
105
+ end
106
+
107
+ def battling!
108
+ @pvp_state = BATTLING
109
+ end
110
+
111
+ def send_message_welcome
112
+ send_message 'msg1', "欢迎来到 石头剪子布 大战!"
113
+ end
114
+
115
+ def send_message_simple_logined
116
+ send_message 'simple-logined', @loginname
117
+ end
118
+
119
+ def send_message_loggedout(reason = nil)
120
+ send_message 'loggedout', reason || '已退出'
121
+ end
122
+
123
+ def send_message_pvp1_ready
124
+ send_message 'pvp-ready', '匹配对手中'
125
+ end
126
+
127
+ def send_message_pvp2_ready(friend_loginname)
128
+ send_message 'pvp-ready', "匹配 #{friend_loginname} 中"
129
+ end
130
+
131
+ def send_message_matching
132
+ send_message 'matching', '.'
133
+ end
134
+
135
+ def send_message_matching_canceled(reason = nil)
136
+ part = '匹配被取消'
137
+ send_message 'matching-canceled',
138
+ reason ? [ reason, part ].join(', ') : part
139
+ end
140
+
141
+ def send_message_matched(instruction)
142
+ send_message 'matched', "#{@loginname} 对 #{@current_opponent.loginname}, #{instruction}"
143
+ end
144
+
145
+ def send_message_won(reason = nil)
146
+ word = '赢了!'
147
+ send_message 'won',
148
+ [
149
+ reason ? [ reason, word ].join(', ') : word,
150
+ @pvp1_wins
151
+ ]
152
+ end
153
+
154
+ def send_message_lost
155
+ send_message 'lost', '输了。'
156
+ end
157
+
158
+ def send_message_round_finished(round, compare)
159
+ send_message 'round-finished',
160
+ [ round, compare, @loginname, @current_action, @current_win_rounds, @current_opponent.loginname, @current_opponent.current_action, @current_opponent.current_win_rounds ]
161
+ end
162
+
163
+ private
164
+
165
+ # pvp1匹配,隔3秒主动匹配1次,重试10次,不成功cancel
166
+ def matching1(players)
167
+ EM.add_timer(3) {
168
+ if @loginname && @pvp_state == MATCHING
169
+ puts "#{@loginname} matching, retry: #{@matching_retry_times}"
170
+ opponent = players.values.select{|_ws| _ws != self and _ws.pvp_state == MATCHING and _ws.current_friend_loginname.nil? }.sample
171
+ if opponent
172
+ StjzbServer::Stjzb.new(self, opponent)
173
+ elsif @matching_retry_times < 10
174
+ send_message_matching
175
+ @matching_retry_times += 1
176
+ matching1(players)
177
+ else
178
+ cancel_matching('没有找到对手')
179
+ puts "no opponent, matching canceled, state: #{@pvp_state}"
180
+ end
181
+ else
182
+ puts "ignore matching"
183
+ end
184
+ }
185
+ end
186
+
187
+ # pvp2匹配
188
+ def matching2(players)
189
+ puts "#{@loginname} matching #{@current_friend_loginname}, retry: #{@matching_retry_times}"
190
+ if @pvp_state == MATCHING
191
+ opponent = players[@current_friend_loginname]
192
+ if opponent && opponent.pvp_state == MATCHING && opponent.current_friend_loginname == @loginname
193
+ StjzbServer::Stjzb.new(self, opponent)
194
+ elsif @matching_retry_times < 10
195
+ send_message_matching
196
+ @matching_retry_times += 1
197
+ EM.add_timer(3) {
198
+ matching2(players)
199
+ }
200
+ else
201
+ friend_loginname = cancel_matching("#{@current_friend_loginname} 没有反应")
202
+ puts "#{friend_loginname} not pong, matching canceled, state: #{@pvp_state}"
203
+ end
204
+ else
205
+ puts "ignore, state: #{@pvp_state}"
206
+ end
207
+ end
208
+
209
+ def send_message(act, msg)
210
+ send Oj.dump([ act, msg ])
211
+ end
212
+
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,3 @@
1
+ class Settings < Settingslogic
2
+ source File.expand_path('../../../application.yml', __FILE__)
3
+ end
@@ -0,0 +1,65 @@
1
+ module StjzbServer
2
+ class Stjzb
3
+ attr_accessor :players, :round
4
+
5
+ SHI_TOU = 1
6
+ JIAN_ZI = 2
7
+ BU = 3
8
+
9
+ # 5局3胜
10
+ def initialize(player1, player2)
11
+ player1.current_win_rounds = 0
12
+ player2.current_win_rounds = 0
13
+ player1.current_action = nil
14
+ player2.current_action = nil
15
+ @players = [ player1, player2 ]
16
+ @round = 1
17
+ @target = 3
18
+
19
+ player1.current_battle = player2.current_battle = self
20
+ player1.current_opponent, player2.current_opponent = player2, player1
21
+ player1.battling!
22
+ player2.battling!
23
+
24
+ instruction = "#{@target * 2 - 1}局#{@target}胜"
25
+ player2.send_message_matched(instruction)
26
+ player1.send_message_matched(instruction)
27
+ puts "#{player1.loginname} vs #{player2.loginname}, #{@target}/#{@target * 2 - 1}"
28
+ end
29
+
30
+ def act(player, action)
31
+ player.current_action = action.to_i
32
+ if player.current_opponent.current_action
33
+ act1, act2 = player.current_action, player.current_opponent.current_action
34
+ case act1 <=> act2
35
+ when -1
36
+ act1 - act2 == -1 ? bigger(player, player.current_opponent) : bigger(player.current_opponent, player)
37
+ when 0
38
+ draw(player, player.current_opponent)
39
+ when 1
40
+ act1 - act2 == 2 ? bigger(player, player.current_opponent) : bigger(player.current_opponent, player)
41
+ end
42
+
43
+ player.current_action = player.current_opponent.current_action = nil
44
+ @round += 1
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def draw(player1, player2)
51
+ player1.send_message_round_finished(@round, '=')
52
+ player2.send_message_round_finished(@round, '=')
53
+ end
54
+
55
+ def bigger(player1, player2)
56
+ player1.current_win_rounds += 1
57
+ player1.send_message_round_finished(@round, '>')
58
+ player2.send_message_round_finished(@round, '<')
59
+ if player1.current_win_rounds >= @target
60
+ player1.win
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module StjzbServer
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ require 'em-websocket'
2
+ require 'oj'
3
+ require 'settingslogic'
4
+
5
+ %w[
6
+ version
7
+ connection
8
+ settings
9
+ stjzb
10
+ ].each do |file|
11
+ require File.expand_path("../ss/#{file}", __FILE__)
12
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ss/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "stzjb_server"
8
+ spec.version = StjzbServer::VERSION
9
+ spec.authors = ["takafan"]
10
+ spec.email = ["takafan@163.com"]
11
+ spec.summary = %q{石头剪子布服务端}
12
+ spec.description = nil
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_dependency "em-websocket"
24
+ spec.add_dependency "oj"
25
+ spec.add_dependency "settingslogic"
26
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stzjb_server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - takafan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: em-websocket
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: oj
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: settingslogic
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: ''
84
+ email:
85
+ - takafan@163.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - application.rb
96
+ - application.yml.example
97
+ - lib/ss/connection.rb
98
+ - lib/ss/settings.rb
99
+ - lib/ss/stjzb.rb
100
+ - lib/ss/version.rb
101
+ - lib/stjzb_server.rb
102
+ - stjzb_server.gemspec
103
+ homepage: ''
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.2.1
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: "石头剪子布服务端"
127
+ test_files: []