├── .gitignore ├── examples ├── ai_edward32tnt.py ├── ai_halida.py ├── ai_jun.lu.rb ├── ailib.py ├── edward32tnt │ ├── AStar.py │ └── astarsnake.py ├── ray │ ├── __init__.py │ └── player.py ├── resty-daze │ ├── README │ ├── snake-ai.py │ ├── todo │ └── utils.py ├── simple_snake.py └── simple_snake.rb ├── makefile ├── map-builder ├── public │ ├── client.coffee │ ├── css │ │ ├── style.css │ │ └── style.sass │ └── js │ │ ├── client.coffee │ │ ├── client.js │ │ └── jquery-1.6.1.js └── views │ ├── index.haml │ └── layout.haml ├── readme.rst ├── rubyweb ├── .gitignore ├── .rspec ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app │ ├── admin │ │ ├── dashboards.rb │ │ ├── maps.rb │ │ ├── replays.rb │ │ ├── rooms.rb │ │ └── users.rb │ ├── assets │ │ └── javascripts │ │ │ ├── application.coffee │ │ │ ├── chatroom.coffee │ │ │ ├── map_builder.coffee │ │ │ ├── room.coffee │ │ │ └── simple_snake.coffee │ ├── controllers │ │ ├── application_controller.rb │ │ ├── home_controller.rb │ │ ├── maps_controller.rb │ │ ├── replays_controller.rb │ │ └── rooms_controller.rb │ ├── helpers │ │ ├── application_helper.rb │ │ ├── chat_helper.rb │ │ ├── replays_helper.rb │ │ └── rooms_helper.rb │ ├── models │ │ ├── admin_user.rb │ │ ├── map.rb │ │ ├── replay.rb │ │ ├── room.rb │ │ └── user.rb │ ├── stylesheets │ │ ├── _base.sass │ │ ├── chat.sass │ │ ├── ie.sass │ │ ├── main.sass │ │ ├── map_builder.sass │ │ ├── middle.sass │ │ ├── narrow.sass │ │ ├── print.sass │ │ ├── room.sass │ │ └── screen.sass │ └── views │ │ ├── home │ │ ├── _event1.haml │ │ ├── _event2.haml │ │ ├── _event3.haml │ │ ├── index.html.haml │ │ └── scoreboard.html.haml │ │ ├── layouts │ │ └── application.html.haml │ │ ├── maps │ │ ├── _form.html.haml │ │ ├── index.html.haml │ │ ├── new.html.haml │ │ └── show.html.haml │ │ ├── replays │ │ └── index.html.haml │ │ ├── rooms │ │ ├── _controls.haml │ │ ├── _replays.haml │ │ ├── _tips.haml │ │ └── show.html.haml │ │ └── users │ │ ├── confirmations │ │ └── new.html.haml │ │ ├── mailer │ │ ├── confirmation_instructions.html.haml │ │ ├── reset_password_instructions.html.haml │ │ └── unlock_instructions.html.haml │ │ ├── passwords │ │ ├── edit.html.haml │ │ └── new.html.haml │ │ ├── registrations │ │ ├── edit.html.haml │ │ └── new.html.haml │ │ ├── sessions │ │ └── new.html.haml │ │ └── unlocks │ │ └── new.html.haml ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── compass.rb │ ├── cucumber.yml │ ├── database.yml │ ├── database.yml.example │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── active_record_defaults.rb │ │ ├── backtrace_silencers.rb │ │ ├── devise.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ └── zeromq.rb │ ├── locales │ │ ├── devise.en.yml │ │ └── en.yml │ └── routes.rb ├── db │ ├── migrate │ │ ├── 20110625045622_devise_create_users.rb │ │ ├── 20110625052210_create_rooms.rb │ │ ├── 20110625072033_create_replays.rb │ │ ├── 20110626025151_add_map_to_replays.rb │ │ ├── 20110626063853_add_field_to_users.rb │ │ ├── 20110626064926_devise_create_admin_users.rb │ │ ├── 20110626144926_create_admin_notes.rb │ │ ├── 20110626144927_move_admin_notes_to_comments.rb │ │ └── 20111130040507_create_maps.rb │ ├── schema.rb │ └── seeds.rb ├── doc │ └── README_FOR_APP ├── features │ ├── map_editor_create.feature │ ├── step_definitions │ │ └── web_steps.rb │ └── support │ │ ├── env.rb │ │ ├── paths.rb │ │ └── selectors.rb ├── lib │ └── tasks │ │ ├── .gitkeep │ │ └── cucumber.rake ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── assets │ │ ├── 04B.ttf │ │ ├── Planet_Conquer_Big.jpg │ │ ├── Planet_Conquer_thumbnail.jpg │ │ ├── Snake_Challenge_Big.jpg │ │ ├── Snake_Challenge_thumbnail.jpg │ │ ├── active_admin.js │ │ ├── active_admin │ │ │ ├── admin_notes_icon.png │ │ │ ├── loading.gif │ │ │ ├── nested_menu_arrow.gif │ │ │ ├── nested_menu_arrow_dark.gif │ │ │ └── orderable.png │ │ ├── active_admin_vendor.js │ │ ├── bg.gif │ │ ├── bg.jpg │ │ ├── brainstorming.png │ │ ├── category_dead.gif │ │ ├── category_python.gif │ │ ├── category_ruby.gif │ │ ├── choose_room.png │ │ ├── close.png │ │ ├── douban.png │ │ ├── ekohe.png │ │ ├── electronica_nine.ttf │ │ ├── favicon.ico │ │ ├── follow_us.png │ │ ├── footer.gif │ │ ├── footer.png │ │ ├── gurudigger.png │ │ ├── header_bg.png │ │ ├── icons │ │ │ ├── egg.gif │ │ │ └── gem.gif │ │ ├── intridea.png │ │ ├── jiantou.png │ │ ├── jquery.js │ │ ├── jquery_ujs.js │ │ ├── json.js │ │ ├── juggernaut.js │ │ ├── logo.png │ │ ├── main_bg.png │ │ ├── memeber_icon_dorian.gif │ │ ├── memeber_icon_linjunhalida.gif │ │ ├── memeber_icon_quake.gif │ │ ├── p.gif │ │ ├── portal.gif │ │ ├── python_vs_ruby.png │ │ ├── pythons_food.gif │ │ ├── pythons_team_title.gif │ │ ├── r.gif │ │ ├── rubys_food.gif │ │ ├── rubys_team_title.gif │ │ ├── rubyvspythonlogo.png │ │ ├── skeleton.gif │ │ ├── snda.png │ │ ├── sohu.png │ │ ├── sponsor.png │ │ ├── taobao.png │ │ ├── time_adr.png │ │ ├── time_gh.png │ │ └── title_bar_bg.gif │ └── favicon.ico ├── script │ ├── cucumber │ ├── loadmap.rb │ └── rails ├── spec │ ├── models │ │ └── admin_user_spec.rb │ └── spec_helper.rb ├── test │ ├── fixtures │ │ ├── replays.yml │ │ ├── rooms.yml │ │ └── users.yml │ ├── functional │ │ ├── chat_controller_test.rb │ │ ├── replays_controller_test.rb │ │ └── rooms_controller_test.rb │ ├── performance │ │ └── browsing_test.rb │ ├── test_helper.rb │ └── unit │ │ ├── helpers │ │ ├── chat_helper_test.rb │ │ ├── replays_helper_test.rb │ │ ├── room_helper_test.rb │ │ └── rooms_helper_test.rb │ │ ├── replay_test.rb │ │ ├── room_test.rb │ │ └── user_test.rb └── vendor │ └── plugins │ └── .gitkeep ├── srcs ├── __init__.py ├── db.py ├── dynamic_wall.py ├── game.py ├── game_controller.py ├── lib.py ├── map │ ├── __init__.py │ ├── campain.yml │ ├── castle.yml │ ├── empty.yml │ ├── flat.yml │ ├── image2map.py │ ├── lost_temple.yml │ ├── map.py │ ├── portal.yml │ ├── test.yml │ └── tron.yml ├── pygame_show.py ├── random_wall.py ├── simple.py ├── snake_game.py ├── snake_profile.py ├── web_server.py ├── zmq_game_server.py ├── zmq_logger.py ├── zmq_pygame_show.py └── zmq_replayer.py └── tmp └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.orig 2 | *.pyc 3 | *_ui.py 4 | *~ 5 | *.qm 6 | *.log 7 | *.txt 8 | *.cfg 9 | *.bak 10 | *.out 11 | 12 | tmp 13 | 14 | # rubyweb 15 | 16 | rubyweb/public/assets/*.css 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/ai_halida.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: ai simple 5 | a simple ai demo 6 | """ 7 | from ailib import * 8 | 9 | class AI(BaseAI): 10 | def __init__(self): 11 | self.name = 'simple ai %d' % random.randint(1, 1000) 12 | types = ['python', 'ruby'] 13 | self.type = types[random.randint(0, 1)] 14 | self.SPRINT = random.random() > 0.5 15 | self.count = 0 16 | self.round = -1 17 | 18 | def setmap(self, map): 19 | self.map = map 20 | 21 | def get_nearest_bean(self, beans, h, size): 22 | r_bean, r_dis, r_dir = None, None, None 23 | 24 | for b in beans: 25 | dis, dir = get_distance(b, h, size) 26 | 27 | if not r_bean or dis < r_dis: 28 | r_bean = b 29 | r_dis = dis 30 | r_dir = dir 31 | 32 | return r_bean, r_dir 33 | 34 | def check_hit(self, next): 35 | # it is bad to hit a wall 36 | if next in self.map['walls']: 37 | return True 38 | # also bad to hit another snake 39 | for s in self.info['snakes']: 40 | if next in s['body']: 41 | return True 42 | 43 | def step(self, info): 44 | """ 45 | caculate next direction by use rating 46 | -10: wall, or hit 47 | x+1, y+1: target bean direction 48 | -1: not target bean 49 | """ 50 | self.info = info 51 | size = self.map['size'] 52 | self_snake = info['snakes'][self.seq] 53 | head = self_snake['body'][0] 54 | w, h = self.map['size'] 55 | dirs = get_dirs(self_snake['body']) 56 | 57 | # not check when cannot move 58 | if self_snake['sprint'] < 0: 59 | return {'op': 'turn', 'direction': 0} 60 | 61 | if self.type == 'python': 62 | target_beans, nontarget_beans = info['eggs'], info['gems'] 63 | else: 64 | target_beans, nontarget_beans = info['gems'], info['eggs'] 65 | 66 | # find the nearest bean, and target direction 67 | nearest_bean, bean_direction = self.get_nearest_bean(target_beans, head, size) 68 | 69 | # rating for each direction 70 | ratings = [0, ] * len(dirs) 71 | 72 | # sprint when torgeting bean and nears! 73 | if ( self.SPRINT and 74 | nearest_bean and 75 | ((head[0] == nearest_bean[0] and self_snake['direction'] in (1, 3) and abs(head[1] - nearest_bean[1]) < 15) or 76 | (head[1] == nearest_bean[1] and self_snake['direction'] in (0, 2) and abs(head[0] - nearest_bean[0]) < 15) 77 | ) and 78 | not any([self.check_hit(n) 79 | for n in get_nexts(6, head, DIRECT[self_snake['direction']], size)]) 80 | ): 81 | # print get_nexts(6, head, d, size) 82 | # print [self.check_hit(n) 83 | # for n in get_nexts(6, head, DIRECT[self_snake['direction']], size)] 84 | return {'op': 'sprint'} 85 | 86 | for i, d in enumerate(dirs): 87 | # it is good if targeting a bean 88 | if nearest_bean: 89 | if d[0] == bean_direction[0]: ratings[i] += 2 90 | if d[1] == bean_direction[1]: ratings[i] += 2 91 | 92 | # find next positon 93 | next = get_next(head, d, size) 94 | 95 | # it is bad to hit a target 96 | if self.check_hit(next): 97 | ratings[i] = -10 98 | continue 99 | 100 | # sprint check! 101 | if (self_snake['sprint'] > 1 and 102 | any([self.check_hit(n) 103 | for n in get_nexts(2, next, d, size)])): 104 | print get_nexts(6, head, d, size) 105 | print [self.check_hit(n) 106 | for n in get_nexts(6, head, d, size)] 107 | ratings[i] = -10 108 | continue 109 | 110 | # bad to near other snakes head 111 | for s in info['snakes']: 112 | if s == self_snake: continue 113 | if near(next, s['body'][0], size): 114 | ratings[i] = -2 115 | continue 116 | 117 | # bad to eat other types of bean 118 | if next in nontarget_beans: ratings[i] -= 2 119 | 120 | # bad to near too many walls 121 | # near_walls = sum([near(next, w, size) 122 | # for w in self.map['walls']]) 123 | # ratings[i] -= near_walls 124 | 125 | # return the best direction 126 | d = max(zip(ratings, dirs), key=lambda x: x[0])[1] 127 | return {'op': 'turn', 'direction': DIRECT.index(d)} 128 | 129 | 130 | if __name__=="__main__": 131 | cmd_run(AI) 132 | -------------------------------------------------------------------------------- /examples/edward32tnt/AStar.py: -------------------------------------------------------------------------------- 1 | # Version 1.1 2 | # 3 | # Changes in 1.1: 4 | # In order to optimize the list handling I implemented the location id (lid) attribute. 5 | # This will make the all list serahces to become extremely more optimized. 6 | 7 | class Path: 8 | def __init__(self,nodes, totalCost): 9 | self.nodes = nodes; 10 | self.totalCost = totalCost; 11 | 12 | def getNodes(self): 13 | return self.nodes 14 | 15 | def getTotalMoveCost(self): 16 | return self.totalCost 17 | 18 | class Node: 19 | def __init__(self,location,mCost,lid,parent=None): 20 | self.location = location # where is this node located 21 | self.mCost = mCost # total move cost to reach this node 22 | self.parent = parent # parent node 23 | self.score = 0 # calculated score for this node 24 | self.lid = lid # set the location id - unique for each location in the map 25 | 26 | def __eq__(self, n): 27 | if n.lid == self.lid: 28 | return 1 29 | else: 30 | return 0 31 | 32 | class AStar: 33 | 34 | def __init__(self,maphandler): 35 | self.mh = maphandler 36 | 37 | def _getBestOpenNode(self): 38 | bestNode = None 39 | for n in self.on: 40 | if not bestNode: 41 | bestNode = n 42 | else: 43 | if n.score<=bestNode.score: 44 | bestNode = n 45 | return bestNode 46 | 47 | def _tracePath(self,n): 48 | nodes = []; 49 | totalCost = n.mCost; 50 | p = n.parent; 51 | nodes.insert(0,n); 52 | 53 | while 1: 54 | if p.parent is None: 55 | break 56 | 57 | nodes.insert(0,p) 58 | p=p.parent 59 | 60 | return Path(nodes,totalCost) 61 | 62 | def _handleNode(self,node,end): 63 | i = self.o.index(node.lid) 64 | self.on.pop(i) 65 | self.o.pop(i) 66 | self.c.append(node.lid) 67 | 68 | nodes = self.mh.getAdjacentNodes(node,end) 69 | 70 | for n in nodes: 71 | if n.location.x % self.mh.w == end.x and n.location.y % self.mh.h == end.y: 72 | # reached the destination 73 | return n 74 | elif n.lid in self.c: 75 | # already in close, skip this 76 | continue 77 | elif n.lid in self.o: 78 | # already in open, check if better score 79 | i = self.o.index(n.lid) 80 | on = self.on[i]; 81 | if n.mCost=self.w or y<0 or y>=self.h: 138 | #return None 139 | x = x % self.w 140 | y = y % self.h 141 | 142 | d = self.m[(y*self.w)+x] 143 | if d == -1: 144 | return None 145 | 146 | return Node(location,d,((y*self.w)+x)); 147 | 148 | def getAdjacentNodes(self, curnode, dest): 149 | """MUST BE IMPLEMENTED""" 150 | result = [] 151 | 152 | cl = curnode.location 153 | dl = dest 154 | 155 | n = self._handleNode(cl.x+1,cl.y,curnode,dl.x,dl.y) 156 | if n: result.append(n) 157 | n = self._handleNode(cl.x-1,cl.y,curnode,dl.x,dl.y) 158 | if n: result.append(n) 159 | n = self._handleNode(cl.x,cl.y+1,curnode,dl.x,dl.y) 160 | if n: result.append(n) 161 | n = self._handleNode(cl.x,cl.y-1,curnode,dl.x,dl.y) 162 | if n: result.append(n) 163 | 164 | return result 165 | 166 | def _handleNode(self,x,y,fromnode,destx,desty): 167 | n = self.getNode(SQ_Location(x,y)) 168 | if n is not None: 169 | dx = min(abs(x - destx), self.w - abs(x-destx)) 170 | dy = min(abs(y - desty), self.h - abs(y-desty)) 171 | emCost = dx+dy 172 | n.mCost += fromnode.mCost 173 | n.score = n.mCost+emCost 174 | n.parent=fromnode 175 | return n 176 | 177 | return None 178 | -------------------------------------------------------------------------------- /examples/ray/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/examples/ray/__init__.py -------------------------------------------------------------------------------- /examples/resty-daze/README: -------------------------------------------------------------------------------- 1 | resty's snake AI 2 | 3 | see rubyvspython.org 4 | -------------------------------------------------------------------------------- /examples/resty-daze/todo: -------------------------------------------------------------------------------- 1 | 1. Controll Logic: 当一局结束后,再add一个新的,参考现有程序 2 | 2. 当自己足够长的时候(超过最长的10个)就不急着去捡了,而是去干扰 (考虑围着目标转) 3 | 3. 如果当前走1步可以害到敌人的话,就害1步:如果对面最近K步有一步只能到W,而我刚好能路过一下,那么果断了~` 4 | 如果能趁别人等待的时候围死的话就围? 5 | 4. 如果只有自己一个人,那么如果>3就去捡变短的 6 | 5. 写一个非WEBSOCKET而是HTTP的CONTROLLER 7 | 6. 重新定义下DANGER: 8 | 默认:2 - ((计算面积 - 1) / 自己长度) ^ 0.8 * 0.3 9 | 如果能够走到TAIL : -1 10 | 如果面积 >= 90%空地 : -0.5 11 | 如果最近K步会被对方害:[自己走k步而位置固定,而对手离此处 -1, :direction => d 38 | end 39 | 40 | def step 41 | snake = @info['snakes'][@me["seq"]] 42 | head = snake['body'][0] 43 | dir = DIRS[@d] 44 | nexts = [1,2,3,4].map do |i| 45 | [head[0] + dir[0]*i, 46 | head[1] + dir[1]*i] 47 | end 48 | 49 | blocks = [] 50 | blocks += @map['walls'] 51 | for snake in @info['snakes'] 52 | blocks += snake['body'] 53 | end 54 | 55 | # change direction when there is block ahead 56 | for n in nexts 57 | for b in blocks 58 | if b[0] == n[0] and b[1] == n[1] 59 | return @d = (@d + 1) % 4 60 | end 61 | end 62 | end 63 | return @d 64 | end 65 | end 66 | 67 | 68 | rs = SimpleSnake.new 69 | rs.cmd_map 70 | puts rs.cmd_add 71 | 72 | while true 73 | sleep 0.3 74 | rs.cmd_info 75 | puts rs.cmd_turn rs.step 76 | end 77 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | unittest: 3 | python srcs/snake_game.py 4 | python srcs/game_controller.py 5 | python srcs/ailib.py 6 | 7 | # run the game server 8 | game: 9 | python srcs/zmq_game_server.py local 10 | webgame: 11 | python srcs/zmq_game_server.py web 12 | 13 | # run the website 14 | website: 15 | cd rubyweb; bundle exec rails server -p 2000 16 | 17 | # run http interface server 18 | http: 19 | cd srcs; python web_server.py 20 | 21 | # run a test ai 22 | ai: 23 | python examples/ai_halida.py zero 0 24 | 25 | # run lots of test ai 26 | ais: 27 | python examples/ai_halida.py zero 0 4 28 | 29 | # pygame show local game 30 | pygame: 31 | python srcs/pygame_show.py 32 | show: 33 | python srcs/zmq_pygame_show.py 0 34 | 35 | # record/replay log 36 | record: 37 | python srcs/zmq_logger.py zero 0 test.log 38 | replay: 39 | python srcs/zmq_replayer.py test.log 40 | -------------------------------------------------------------------------------- /map-builder/public/client.coffee: -------------------------------------------------------------------------------- 1 | # hi 2 | $ = jQuery 3 | 4 | $ () -> 5 | alert("welcome to map builder") -------------------------------------------------------------------------------- /map-builder/public/css/style.css: -------------------------------------------------------------------------------- 1 | #builder .box { 2 | border: 1px solid #aaaaaa; 3 | height: 18px; 4 | width: 18px; 5 | display: inline-block; } 6 | #builder .box:hover { 7 | border: 1px solid red; } 8 | #builder .box.wall { 9 | background: #aaaaaa; } 10 | -------------------------------------------------------------------------------- /map-builder/public/css/style.sass: -------------------------------------------------------------------------------- 1 | #builder 2 | .box 3 | border: 1px solid #AAA 4 | height: 18px 5 | width: 18px 6 | display: inline-block 7 | .box:hover 8 | border: 1px solid red 9 | .box.wall 10 | background: #AAA -------------------------------------------------------------------------------- /map-builder/public/js/client.coffee: -------------------------------------------------------------------------------- 1 | # hi 2 | $ = jQuery 3 | 4 | $ () -> 5 | window.builder = new MapBuilder("#builder",15,15) 6 | 7 | class MapBuilder 8 | constructor: (e,w,h) -> 9 | @e = e = $(e) 10 | @width = w 11 | @height = h 12 | @create_grid() 13 | walls: () -> 14 | walls = [] 15 | for row in @rows 16 | for box in row 17 | if box.is_wall() 18 | walls.push(box.position()) 19 | walls 20 | to_json: () -> 21 | {walls: @walls()} 22 | create_grid: () -> 23 | @rows = [] 24 | i = 0 25 | while(i < @height) 26 | row = $("
") 27 | @e.append(row) 28 | boxes = [] 29 | @rows.push(boxes) 30 | j = 0 31 | while(j < @width) 32 | div = $("
") 33 | row.append(div) 34 | box = new Box(div,j,i) 35 | boxes.push(box) 36 | j += 1 37 | i += 1 38 | 39 | class Box 40 | constructor: (box,x,y) -> 41 | @box = box 42 | @x = x 43 | @y = y 44 | @box.bind "click", () => 45 | @box.toggleClass("wall") 46 | position: () -> 47 | [@x,@y] 48 | is_wall: () -> 49 | @box.hasClass("wall") 50 | 51 | 52 | -------------------------------------------------------------------------------- /map-builder/public/js/client.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var $, Box, MapBuilder; 3 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 4 | $ = jQuery; 5 | $(function() { 6 | return window.builder = new MapBuilder("#builder", 15, 15); 7 | }); 8 | MapBuilder = (function() { 9 | function MapBuilder(e, w, h) { 10 | this.e = e = $(e); 11 | this.width = w; 12 | this.height = h; 13 | this.create_grid(); 14 | } 15 | MapBuilder.prototype.walls = function() { 16 | var box, row, walls, _i, _j, _len, _len2, _ref; 17 | walls = []; 18 | _ref = this.rows; 19 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 20 | row = _ref[_i]; 21 | for (_j = 0, _len2 = row.length; _j < _len2; _j++) { 22 | box = row[_j]; 23 | if (box.is_wall()) { 24 | walls.push(box.position()); 25 | } 26 | } 27 | } 28 | return walls; 29 | }; 30 | MapBuilder.prototype.to_json = function() { 31 | return { 32 | walls: this.walls() 33 | }; 34 | }; 35 | MapBuilder.prototype.create_grid = function() { 36 | var box, boxes, div, i, j, row, _results; 37 | this.rows = []; 38 | i = 0; 39 | _results = []; 40 | while (i < this.height) { 41 | row = $("
"); 42 | this.e.append(row); 43 | boxes = []; 44 | this.rows.push(boxes); 45 | j = 0; 46 | while (j < this.width) { 47 | div = $("
"); 48 | row.append(div); 49 | box = new Box(div, j, i); 50 | boxes.push(box); 51 | j += 1; 52 | } 53 | _results.push(i += 1); 54 | } 55 | return _results; 56 | }; 57 | return MapBuilder; 58 | })(); 59 | Box = (function() { 60 | function Box(box, x, y) { 61 | this.box = box; 62 | this.x = x; 63 | this.y = y; 64 | this.box.bind("click", __bind(function() { 65 | return this.box.toggleClass("wall"); 66 | }, this)); 67 | } 68 | Box.prototype.position = function() { 69 | return [this.x, this.y]; 70 | }; 71 | Box.prototype.is_wall = function() { 72 | return this.box.hasClass("wall"); 73 | }; 74 | return Box; 75 | })(); 76 | }).call(this); 77 | -------------------------------------------------------------------------------- /map-builder/views/index.haml: -------------------------------------------------------------------------------- 1 | #builder 2 | 3 | 4 | -------------------------------------------------------------------------------- /map-builder/views/layout.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %head 3 | %script{"src":"/js/jquery-1.6.1.js"} 4 | %script{"src":"/js/client.js"} 5 | %link{"type":"text/css", "href":"/css/style.css", "rel": "stylesheet"} 6 | %body 7 | != body 8 | -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | snake-challenge项目说明 2 | ==================================== 3 | 见 wiki: https://github.com/halida/snake-challenge/wiki 4 | -------------------------------------------------------------------------------- /rubyweb/.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | db/*.sqlite3 3 | log/*.log 4 | tmp/ 5 | -------------------------------------------------------------------------------- /rubyweb/.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | -------------------------------------------------------------------------------- /rubyweb/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'rails', '3.1' 4 | 5 | gem "sqlite3" 6 | gem "mysql2" 7 | 8 | # Gems used only for assets and not required 9 | # in production environments by default. 10 | group :assets do 11 | gem 'sass-rails', " ~> 3.1.0" 12 | gem 'therubyracer' 13 | gem 'coffee-rails', "~> 3.1.0" 14 | gem 'coffee-filter' 15 | gem 'uglifier', '>= 1.0.3' 16 | gem 'haml' 17 | gem "compass", ">= 0.11.5" 18 | end 19 | 20 | gem 'jquery-rails' 21 | 22 | # gem 'simple_form', '1.4.1' 23 | # gem 'mini_magick', '3.3' 24 | # gem 'carrierwave', '0.5.4' 25 | # gem 'kaminari', '0.12.4' 26 | # gem 'memcache-client', '1.8.5' 27 | # gem 'colorize', '0.5.8' 28 | gem 'zmq', "2.1.3" 29 | gem 'json', '1.5.3' 30 | 31 | gem 'activeadmin', "0.3" 32 | gem 'meta_search', '>= 1.1.0.pre' 33 | 34 | gem "unicorn" 35 | 36 | group :test, :development do 37 | end 38 | -------------------------------------------------------------------------------- /rubyweb/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | actionmailer (3.1.0) 5 | actionpack (= 3.1.0) 6 | mail (~> 2.3.0) 7 | actionpack (3.1.0) 8 | activemodel (= 3.1.0) 9 | activesupport (= 3.1.0) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | i18n (~> 0.6) 13 | rack (~> 1.3.2) 14 | rack-cache (~> 1.0.3) 15 | rack-mount (~> 0.8.2) 16 | rack-test (~> 0.6.1) 17 | sprockets (~> 2.0.0) 18 | activeadmin (0.3.0) 19 | devise (>= 1.1.2) 20 | fastercsv 21 | formtastic (>= 1.1.0) 22 | inherited_resources 23 | kaminari (>= 0.12.4) 24 | meta_search (>= 0.9.2) 25 | rails (>= 3.0.0) 26 | sass (>= 3.1.0) 27 | activemodel (3.1.0) 28 | activesupport (= 3.1.0) 29 | bcrypt-ruby (~> 3.0.0) 30 | builder (~> 3.0.0) 31 | i18n (~> 0.6) 32 | activerecord (3.1.0) 33 | activemodel (= 3.1.0) 34 | activesupport (= 3.1.0) 35 | arel (~> 2.2.1) 36 | tzinfo (~> 0.3.29) 37 | activeresource (3.1.0) 38 | activemodel (= 3.1.0) 39 | activesupport (= 3.1.0) 40 | activesupport (3.1.0) 41 | multi_json (~> 1.0) 42 | arel (2.2.1) 43 | bcrypt-ruby (3.0.1) 44 | builder (3.0.0) 45 | chunky_png (1.2.5) 46 | coffee-filter (0.1.1) 47 | coffee-script (>= 2.2.0) 48 | haml (>= 3.0.18) 49 | coffee-rails (3.1.1) 50 | coffee-script (>= 2.2.0) 51 | railties (~> 3.1.0) 52 | coffee-script (2.2.0) 53 | coffee-script-source 54 | execjs 55 | coffee-script-source (1.1.3) 56 | compass (0.11.5) 57 | chunky_png (~> 1.2) 58 | fssm (>= 0.2.7) 59 | sass (~> 3.1) 60 | devise (1.4.9) 61 | bcrypt-ruby (~> 3.0) 62 | orm_adapter (~> 0.0.3) 63 | warden (~> 1.0.3) 64 | erubis (2.7.0) 65 | execjs (1.2.9) 66 | multi_json (~> 1.0) 67 | fastercsv (1.5.4) 68 | formtastic (2.0.2) 69 | rails (~> 3.0) 70 | fssm (0.2.7) 71 | haml (3.1.3) 72 | has_scope (0.5.1) 73 | hike (1.2.1) 74 | i18n (0.6.0) 75 | inherited_resources (1.3.0) 76 | has_scope (~> 0.5.0) 77 | responders (~> 0.6.0) 78 | jquery-rails (1.0.17) 79 | railties (~> 3.0) 80 | thor (~> 0.14) 81 | json (1.5.3) 82 | kaminari (0.12.4) 83 | rails (>= 3.0.0) 84 | kgio (2.6.0) 85 | libv8 (3.3.10.2) 86 | mail (2.3.0) 87 | i18n (>= 0.4.0) 88 | mime-types (~> 1.16) 89 | treetop (~> 1.4.8) 90 | meta_search (1.1.1) 91 | actionpack (~> 3.1.0) 92 | activerecord (~> 3.1.0) 93 | activesupport (~> 3.1.0) 94 | polyamorous (~> 0.5.0) 95 | mime-types (1.17.2) 96 | multi_json (1.0.3) 97 | mysql2 (0.3.7) 98 | orm_adapter (0.0.5) 99 | polyamorous (0.5.0) 100 | activerecord (~> 3.0) 101 | polyglot (0.3.3) 102 | rack (1.3.5) 103 | rack-cache (1.0.3) 104 | rack (>= 0.4) 105 | rack-mount (0.8.3) 106 | rack (>= 1.0.0) 107 | rack-ssl (1.3.2) 108 | rack 109 | rack-test (0.6.1) 110 | rack (>= 1.0) 111 | rails (3.1.0) 112 | actionmailer (= 3.1.0) 113 | actionpack (= 3.1.0) 114 | activerecord (= 3.1.0) 115 | activeresource (= 3.1.0) 116 | activesupport (= 3.1.0) 117 | bundler (~> 1.0) 118 | railties (= 3.1.0) 119 | railties (3.1.0) 120 | actionpack (= 3.1.0) 121 | activesupport (= 3.1.0) 122 | rack-ssl (~> 1.3.2) 123 | rake (>= 0.8.7) 124 | rdoc (~> 3.4) 125 | thor (~> 0.14.6) 126 | raindrops (0.8.0) 127 | rake (0.9.2.2) 128 | rdoc (3.11) 129 | json (~> 1.4) 130 | responders (0.6.4) 131 | sass (3.1.10) 132 | sass-rails (3.1.4) 133 | actionpack (~> 3.1.0) 134 | railties (~> 3.1.0) 135 | sass (>= 3.1.4) 136 | sprockets (~> 2.0.0) 137 | tilt (~> 1.3.2) 138 | sprockets (2.0.3) 139 | hike (~> 1.2) 140 | rack (~> 1.0) 141 | tilt (~> 1.1, != 1.3.0) 142 | sqlite3 (1.3.4) 143 | therubyracer (0.9.4) 144 | libv8 (~> 3.3.10) 145 | thor (0.14.6) 146 | tilt (1.3.3) 147 | treetop (1.4.10) 148 | polyglot 149 | polyglot (>= 0.3.1) 150 | tzinfo (0.3.31) 151 | uglifier (1.0.4) 152 | execjs (>= 0.3.0) 153 | multi_json (>= 1.0.2) 154 | unicorn (4.1.1) 155 | kgio (~> 2.4) 156 | rack 157 | raindrops (~> 0.6) 158 | warden (1.0.6) 159 | rack (>= 1.0) 160 | zmq (2.1.3) 161 | 162 | PLATFORMS 163 | ruby 164 | 165 | DEPENDENCIES 166 | activeadmin (= 0.3) 167 | coffee-filter 168 | coffee-rails (~> 3.1.0) 169 | compass (>= 0.11.5) 170 | haml 171 | jquery-rails 172 | json (= 1.5.3) 173 | meta_search (>= 1.1.0.pre) 174 | mysql2 175 | rails (= 3.1) 176 | sass-rails (~> 3.1.0) 177 | sqlite3 178 | therubyracer 179 | uglifier (>= 1.0.3) 180 | unicorn 181 | zmq (= 2.1.3) 182 | -------------------------------------------------------------------------------- /rubyweb/README.md: -------------------------------------------------------------------------------- 1 | INSTALL 2 | ======== 3 | 4 | for chat system 5 | 6 | Ubuntu: install node.js redis 7 | ArchLinux: pacman -S nodejs redis 8 | npm install -g juggernaut 9 | 10 | 11 | RUN 12 | === 13 | 14 | for chat system 15 | 16 | ArchLinux: /etc/rc.d/redis start 17 | juggernaut 18 | 19 | 20 | -------------------------------------------------------------------------------- /rubyweb/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | require 'rake' 6 | 7 | Rubyweb::Application.load_tasks 8 | -------------------------------------------------------------------------------- /rubyweb/app/admin/dashboards.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin::Dashboards.build do 2 | 3 | # Define your dashboard sections here. Each block will be 4 | # rendered on the dashboard in the context of the view. So just 5 | # return the content which you would like to display. 6 | 7 | # == Simple Dashboard Section 8 | # Here is an example of a simple dashboard section 9 | # 10 | # section "Recent Posts" do 11 | # ul do 12 | # Post.recent(5).collect do |post| 13 | # li link_to(post.title, admin_post_path(post)) 14 | # end 15 | # end 16 | # end 17 | 18 | # == Render Partial Section 19 | # The block is rendererd within the context of the view, so you can 20 | # easily render a partial rather than build content in ruby. 21 | # 22 | # section "Recent Posts" do 23 | # render 'recent_posts' # => this will render /app/views/admin/dashboard/_recent_posts.html.erb 24 | # end 25 | 26 | # == Section Ordering 27 | # The dashboard sections are ordered by a given priority from top left to 28 | # bottom right. The default priority is 10. By giving a section numerically lower 29 | # priority it will be sorted higher. For example: 30 | # 31 | # section "Recent Posts", :priority => 10 32 | # section "Recent User", :priority => 1 33 | # 34 | # Will render the "Recent Users" then the "Recent Posts" sections on the dashboard. 35 | 36 | end 37 | -------------------------------------------------------------------------------- /rubyweb/app/admin/maps.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Map do 2 | 3 | end 4 | -------------------------------------------------------------------------------- /rubyweb/app/admin/replays.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Replay do 2 | 3 | end 4 | -------------------------------------------------------------------------------- /rubyweb/app/admin/rooms.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Room do 2 | 3 | end 4 | -------------------------------------------------------------------------------- /rubyweb/app/admin/users.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register User do 2 | 3 | end 4 | -------------------------------------------------------------------------------- /rubyweb/app/assets/javascripts/application.coffee: -------------------------------------------------------------------------------- 1 | if MozWebSocket? 2 | window.WS = MozWebSocket 3 | else 4 | window.WS = WebSocket 5 | 6 | window.init = ()-> 7 | flash = $('.flash') 8 | if flash.length > 0 9 | setTimeout( ()-> 10 | flash.fadeIn(800) 11 | , 3000) 12 | 13 | window.error = (msg)-> 14 | error = $('#flash_error') 15 | error.html(msg) 16 | error.fadeIn(800) 17 | console.log(msg) 18 | setTimeout( 19 | ()-> 20 | error.fadeOut(800) 21 | , 10000) 22 | 23 | window.notice = (msg)-> 24 | notice = $('#flash_notice') 25 | notice.html(msg) 26 | notice.fadeIn(800) 27 | console.log(msg) 28 | setTimeout( 29 | ()-> 30 | notice.fadeOut(800) 31 | , 3000) 32 | 33 | 34 | window.random_color = (text)-> 35 | v = 0 36 | for k in text 37 | v += k.charCodeAt() 38 | v *= 13 39 | v %= 101477 40 | r = (v % 2207 ) % 0x7f 41 | g = (v % 2607 ) % 0x7f 42 | b = (v % 3323 ) % 0x7f 43 | color = '#' + ((r << 16) + (g<<8) + b).toString(16) 44 | -------------------------------------------------------------------------------- /rubyweb/app/assets/javascripts/chatroom.coffee: -------------------------------------------------------------------------------- 1 | chat_ws = [] 2 | 3 | append = (msg) -> 4 | return unless msg 5 | mark = msg.substring(0, msg.indexOf(' ')) 6 | color = random_color('p' + mark) 7 | $("#msgs").prepend "
" 8 | $("#msgs").prepend (''+msg+"") 9 | 10 | window.chat_init = (server, name, room) -> 11 | chat_ws = new window.WS(server) 12 | 13 | chat_ws.onopen = -> 14 | chat_ws.send JSON.stringify( 15 | name: name 16 | room: room 17 | ) 18 | 19 | chat_ws.onmessage = (e) -> 20 | append e.data 21 | 22 | chat_ws.onclose = -> 23 | append "closed" 24 | 25 | $("#send-msg").show() 26 | 27 | window.chat_send = -> 28 | msg = $("#msg").val() 29 | return unless msg 30 | chat_ws.send JSON.stringify(msg: msg) 31 | $("#msg").val "" 32 | -------------------------------------------------------------------------------- /rubyweb/app/assets/javascripts/map_builder.coffee: -------------------------------------------------------------------------------- 1 | $ = jQuery 2 | 3 | json = (e) -> 4 | $.parseJSON $(e).text() 5 | 6 | exists = (e) -> 7 | $(e).size() > 0 8 | 9 | $ () -> 10 | window.builder = new MapBuilder("#map_builder") if exists("#map_builder") 11 | if exists("ul#maps") 12 | window.previews = $("ul#maps li").map (i,e) -> 13 | new MapPreview(e) 14 | window.pr = window.previews[0] 15 | 16 | class Map 17 | constructor: (e) -> 18 | @e = $(e) 19 | at: (x,y) -> 20 | (row = @boxes[y]) && row[x] 21 | draw: (data) -> 22 | # remove old instance of the drawn grid if it exists 23 | grid = @e.find(".grid") 24 | grid.remove() if grid.size() > 0 25 | @draw_grid(data.width,data.height) 26 | @draw_walls(data.walls) 27 | draw_walls: (walls) -> 28 | for [x,y] in walls 29 | @at(x,y)?.be_wall() 30 | draw_grid: (w,h) -> 31 | @grid = $("
") 32 | @boxes = for y in [0...h] 33 | row = $("
") 34 | @grid.append row 35 | for x in [0...w] 36 | div = $("
") 37 | row.append div 38 | new Box(div,x,y) 39 | @e.append @grid 40 | 41 | class MapPreview 42 | constructor: (e) -> 43 | @e = $(e) 44 | @data = json @e.find(".data") 45 | @preview = @e.find(".preview") 46 | @map = new Map(@preview) 47 | @map.draw(@data) 48 | 49 | class MapBuilder 50 | constructor: (e) -> 51 | @e = e = $(e) 52 | @grid = e.find(".grid") 53 | 54 | @setup_form() 55 | @_height = e.find("#map_height").change () => 56 | @adjust_dimension() 57 | @_width = e.find("#map_width").change () => 58 | @adjust_dimension() 59 | 60 | @data = json @e.find(".data") 61 | @map = new Map(@e.find(".map")) 62 | @map.draw(@data) 63 | 64 | walls: () -> 65 | walls = [] 66 | for row in @map.boxes 67 | for box in row 68 | if box.is_wall() 69 | walls.push(box.position()) 70 | walls 71 | to_json: () -> 72 | walls: @walls() 73 | width: @_width.val() 74 | height: @_height.val() 75 | adjust_dimension: () -> 76 | @map.draw(@to_json()) 77 | setup_form: () -> 78 | @form = @e.find("form") 79 | @form.find(":submit").click () => 80 | @form.find("#map_builder_data").val(JSON.stringify @to_json()) 81 | 82 | class Box 83 | constructor: (box,x,y) -> 84 | @box = box 85 | @x = x 86 | @y = y 87 | @box.bind "click", () => 88 | @be_wall() 89 | be_wall: () -> 90 | @box.toggleClass("wall") 91 | position: () -> 92 | [@x,@y] 93 | is_wall: () -> 94 | @box.hasClass("wall") 95 | 96 | 97 | -------------------------------------------------------------------------------- /rubyweb/app/assets/javascripts/simple_snake.coffee: -------------------------------------------------------------------------------- 1 | simple_snake = 2 | d: 0 3 | dirs: [[-1, 0], [0, -1], [1, 0], [0, 1]] 4 | map: undefined 5 | user_seq: undefined 6 | 7 | init: (us)-> 8 | this.user_seq = us 9 | 10 | setmap: (map)-> 11 | this.map = map 12 | 13 | step: (info)-> 14 | snake = info.snakes[this.user_seq] 15 | head = snake.body[0] 16 | dir = this.dirs[this.d] 17 | nexts = ([ 18 | head[0] + dir[0]*i, 19 | head[1] + dir[1]*i 20 | ] for i in [1..4]) 21 | blocks = this.map.walls.concat [] 22 | for snake in info.snakes 23 | blocks.push.apply(blocks, snake.body) 24 | 25 | for n in nexts 26 | for b in blocks 27 | if b[0] == n[0] and b[1] == n[1] 28 | this.d = (this.d + 1) % 4 29 | return this.d 30 | 31 | return this.d 32 | 33 | window.simple_snake = simple_snake -------------------------------------------------------------------------------- /rubyweb/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /rubyweb/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | 3 | class HomeController < ApplicationController 4 | require 'sqlite3' 5 | @@db = SQLite3::Database.new '../tmp/game.db' 6 | 7 | def index 8 | @replays = Replay.recent.limit(5) 9 | @event = params[:event] || 3 10 | end 11 | 12 | def scoreboard 13 | params = {op: 'scores', room: 0} 14 | @data = JSON.load Net::HTTP.post_form(URI.parse("http://#{Room::GAME_SERVER}/cmd"), params).body 15 | puts @data 16 | end 17 | 18 | def replay 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /rubyweb/app/controllers/maps_controller.rb: -------------------------------------------------------------------------------- 1 | class MapsController < ApplicationController 2 | def index 3 | @maps = Map.all 4 | end 5 | 6 | def new 7 | @map = Map.new 8 | end 9 | 10 | def show 11 | @map = Map.find(params[:id]) 12 | print @map.title, @map.data 13 | return render json: JSON.load(@map.data) if params[:json] 14 | end 15 | 16 | def create 17 | @map = Map.new params[:map] 18 | if @map.save 19 | flash[:notice] = "A new map was created" 20 | redirect_to @map 21 | else 22 | flash[:error] = "Error creating the map" 23 | render "new" 24 | end 25 | end 26 | 27 | def update 28 | map 29 | data = JSON.parse params[:map_builder_data] 30 | data = data.merge(params[:map].slice("width","height")) 31 | p data 32 | 33 | if map.update_attributes data 34 | flash[:notice] = "Map was updated" 35 | else 36 | flash[:error] = "Map was not updated" 37 | end 38 | redirect_to map 39 | end 40 | 41 | def map 42 | @map ||= Map.find params[:id] 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /rubyweb/app/controllers/replays_controller.rb: -------------------------------------------------------------------------------- 1 | class ReplaysController < ApplicationController 2 | def index 3 | @replays = Replay.recent.page(params[:page]).per(20) 4 | end 5 | 6 | def show 7 | @replay = Replay.find(params[:id]) 8 | return render json: JSON.load(@replay.json) if params[:json] 9 | @room_id = 0 10 | render "rooms/show" 11 | end 12 | 13 | def create 14 | @replay = Replay.new(params[:replay]) 15 | @replay.user = current_user 16 | 17 | if @replay.save 18 | render json: {status: 'replay saved.', id: @replay.id} 19 | else 20 | render json: {status: 'replay save failed', } 21 | end 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /rubyweb/app/controllers/rooms_controller.rb: -------------------------------------------------------------------------------- 1 | require "json" 2 | require 'zmq' 3 | 4 | class RoomsController < ApplicationController 5 | 6 | def index 7 | end 8 | 9 | def add 10 | add_result = zmq_req_send('add', 11 | {:name => params[:name], 12 | :type => params[:type]}) 13 | render :text => add_result 14 | end 15 | 16 | def show 17 | @room_id = params[:id] 18 | @game_server = Room::GAME_SERVER 19 | @chat_server = Room::CHAT_SERVER 20 | end 21 | 22 | def map 23 | result = zmq_req_send 'map' 24 | render :text => result 25 | end 26 | 27 | def info 28 | result = zmq_req_send 'info' 29 | render :text => result 30 | end 31 | 32 | def turn 33 | turn_result = zmq_req_send('turn', {:id => params[:snake_id], :direction => params[:direction].to_i, :round => params[:round].to_i}) 34 | 35 | render :text => turn_result 36 | end 37 | 38 | private 39 | def zmq_req_send(op, options = {}) 40 | $zmq_req.send(options.merge(:op => op, :room => params[:room_id].to_i).to_json) 41 | $zmq_req.recv 42 | end 43 | 44 | def zmq_sub_set 45 | $zmq_sub.setsockopt(ZMQ::SUBSCRIBE, "room:#{params[:room_id]} ") 46 | end 47 | 48 | def zmq_sub_recv 49 | $zmq_sub.recv[7..-1] 50 | end 51 | 52 | end 53 | -------------------------------------------------------------------------------- /rubyweb/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /rubyweb/app/helpers/chat_helper.rb: -------------------------------------------------------------------------------- 1 | module ChatHelper 2 | end 3 | -------------------------------------------------------------------------------- /rubyweb/app/helpers/replays_helper.rb: -------------------------------------------------------------------------------- 1 | module ReplaysHelper 2 | end 3 | -------------------------------------------------------------------------------- /rubyweb/app/helpers/rooms_helper.rb: -------------------------------------------------------------------------------- 1 | module RoomsHelper 2 | end 3 | -------------------------------------------------------------------------------- /rubyweb/app/models/admin_user.rb: -------------------------------------------------------------------------------- 1 | class AdminUser < ActiveRecord::Base 2 | # Include default devise modules. Others available are: 3 | # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable 4 | devise :database_authenticatable, 5 | :recoverable, :rememberable, :trackable, :validatable 6 | 7 | # Setup accessible (or protected) attributes for your model 8 | attr_accessible :email, :password, :password_confirmation, :remember_me 9 | # Include default devise modules. Others available are: 10 | # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable 11 | devise :database_authenticatable, 12 | :recoverable, :rememberable, :trackable, :validatable 13 | 14 | # Setup accessible (or protected) attributes for your model 15 | attr_accessible :email, :password, :password_confirmation, :remember_me 16 | end 17 | -------------------------------------------------------------------------------- /rubyweb/app/models/map.rb: -------------------------------------------------------------------------------- 1 | class Map < ActiveRecord::Base 2 | include_root_in_json = false 3 | 4 | validates_presence_of :title 5 | validates_uniqueness_of :title 6 | 7 | validates :height, { 8 | :presence => true, 9 | :inclusion => { :in => 10..150 } 10 | } 11 | validates :width, { 12 | :presence => true, 13 | :inclusion => { :in => 10..150 } 14 | } 15 | 16 | serialize :walls 17 | # {"walls"=>[[8, 7], [10, 7], [6, 8]], "height"=>15, "width"=>15} 18 | end 19 | -------------------------------------------------------------------------------- /rubyweb/app/models/replay.rb: -------------------------------------------------------------------------------- 1 | class Replay < ActiveRecord::Base 2 | scope :recent, :order => "id desc" 3 | 4 | belongs_to :user 5 | 6 | end 7 | -------------------------------------------------------------------------------- /rubyweb/app/models/room.rb: -------------------------------------------------------------------------------- 1 | class Room < ActiveRecord::Base 2 | 3 | CHAT_SERVER = 'localhost:9999' 4 | GAME_SERVER = 'localhost:9999' 5 | 6 | end 7 | -------------------------------------------------------------------------------- /rubyweb/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | # Include default devise modules. Others available are: 3 | # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable 4 | devise :database_authenticatable, :registerable, 5 | :recoverable, :rememberable, :trackable, :validatable 6 | 7 | # Setup accessible (or protected) attributes for your model 8 | attr_accessible :name, :bio, :twitter, :blog, 9 | :email, :password, :password_confirmation, :remember_me 10 | 11 | end 12 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/_base.sass: -------------------------------------------------------------------------------- 1 | @import compass/css3, compass/utilities 2 | @import "compass/layout/stretching" 3 | @import "compass/css3/transform" 4 | @import "compass/css3/transition" 5 | 6 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/chat.sass: -------------------------------------------------------------------------------- 1 | #chat 2 | -webkit-box-flex: 1 3 | -moz-box-flex: 1 4 | box-flex: 1 5 | display: -webkit-box 6 | -webkit-box-orient: vertical 7 | -webkit-box-align: stretch 8 | display: -moz-box 9 | -moz-box-orient: vertical 10 | -moz-box-align: stretch 11 | width: 750px 12 | .items 13 | height: 200px 14 | list-style: none 15 | margin: 0 16 | padding: 0 17 | -webkit-box-flex: 1 18 | -moz-box-flex: 1 19 | box-flex: 1 20 | overflow: auto 21 | background: #fcfcfc 22 | background: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#efefef)) 23 | background: -moz-linear-gradient(top, #fcfcfc, #efefef) 24 | background: linear-gradient(top, #fcfcfc, #efefef) 25 | color: #373737 26 | text-shadow: 0 1px 1px #ffffff 27 | .item 28 | position: relative 29 | -moz-box-shadow: 0 1px 1px #fcfcfc 30 | -webkit-box-shadow: 0 1px 1px #fcfcfc 31 | box-shadow: 0 1px 1px #fcfcfc 32 | display: block 33 | overflow: hidden 34 | .name 35 | width: 90px 36 | padding: 10px 20px 37 | font-weight: bold 38 | text-align: left 39 | .new 40 | width: 100% 41 | -webkit-box-flex: 0 42 | -moz-box-flex: 0 43 | box-flex: 0 44 | border-top: 1px solid rgba(0, 0, 0, 0.4) 45 | display: -webkit-box 46 | -webkit-box-orient: horizontal 47 | -webkit-box-align: stretch 48 | -webkit-box-pack: left 49 | display: -moz-box 50 | -moz-box-orient: horizontal 51 | -moz-box-align: stretch 52 | -moz-box-pack: left 53 | background: #e6e6e7 54 | background: -webkit-gradient(linear, left top, left bottom, from(#e6e6e7), to(#fafafa)) 55 | background: -moz-linear-gradient(top, #e6e6e7, #fafafa) 56 | background: linear-gradient(top, #e6e6e7, #fafafa) 57 | input 58 | &.message 59 | padding: 10px 60 | -webkit-box-flex: 1 61 | -moz-box-flex: 1 62 | box-flex: 1 63 | display: block 64 | -moz-border-radius: 0 65 | -webkit-border-radius: 0 66 | border-radius: 0 67 | background: none 68 | border: 0 69 | font-family: Helvetica, Arial, "MS Trebuchet", sans-serif 70 | &:focus 71 | outline: none 72 | &[value="Send"] 73 | margin: 5px 74 | color: #ffffff 75 | text-shadow: 0 -1px 1px #46677f 76 | background: #7bb5db 77 | background: -webkit-gradient(linear, left top, left bottom, from(#7bb5db), to(#4775b8)) 78 | background: -moz-linear-gradient(top, #7bb5db, #4775b8) 79 | background: linear-gradient(top, #7bb5db, #4775b8) 80 | border: 1px solid rgba(0, 0, 0, 0.1) 81 | button:active 82 | border-left-color: #a8a8a8 83 | background: #7bb5db 84 | -moz-box-shadow: inset 0 0 10px #4775b8 85 | -webkit-box-shadow: inset 0 0 10px #4775b8 86 | box-shadow: inset 0 0 10px #4775b8 87 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/ie.sass: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. Use this file to write IE specific override styles. 2 | * Import this file using the following HTML or equivalent: 3 | * 6 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/map_builder.sass: -------------------------------------------------------------------------------- 1 | .grid 2 | .row 3 | line-height: 5px 4 | .box 5 | background: white 6 | display: inline-block 7 | height: 5px 8 | width: 5px 9 | &.wall 10 | background: #aaaaaa 11 | 12 | #maps li 13 | margin-bottom: 1em 14 | .data 15 | display: none 16 | 17 | #map_builder 18 | .data, #map_builder_data 19 | display: none 20 | .grid .box 21 | border: 1px solid #aaaaaa 22 | height: 18px 23 | width: 18px 24 | display: inline-block 25 | &:hover 26 | border: 1px solid red 27 | &.wall 28 | background: #aaaaaa 29 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/middle.sass: -------------------------------------------------------------------------------- 1 | #python-vs-ruby-img 2 | display: none 3 | 4 | header 5 | background: none 6 | 7 | #main 8 | padding-top: 5px 9 | 10 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/narrow.sass: -------------------------------------------------------------------------------- 1 | #main 2 | padding-top: 0px 3 | 4 | #left 5 | width: 100% 6 | #content, #place 7 | width: initial 8 | 9 | #place .left_content 10 | width: initial 11 | 12 | #right 13 | float: left 14 | 15 | #place .right_nav 16 | float: none 17 | margin: 20px 30px 20px 30px 18 | border: none 19 | .title_bar_r, #room_icons, #game_replay, #sponsor_icon 20 | border: none 21 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/print.sass: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. Use this file to define print styles. 2 | * Import this file using the following HTML or equivalent: 3 | * 4 | -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/room.sass: -------------------------------------------------------------------------------- 1 | @import "base" 2 | 3 | #left 4 | float: left 5 | width: 100% 6 | max-width: 740px 7 | 8 | #right 9 | width: 100% 10 | max-width: 320px 11 | float: right 12 | 13 | #left, #right 14 | margin-bottom: 10px 15 | 16 | #room-canvas 17 | background: white 18 | width: 100% 19 | 20 | .title_bar 21 | background: #0f9fbc url(/assets/title_bar_bg.gif) no-repeat right 22 | padding: 10px 23 | 24 | .title_bar, #map_name, #map_round, #map_status 25 | color: #2c3047 26 | font-family: 'electronica Nine', Arial, Helvetica, sans-serif 27 | font-weight: bold 28 | font-size: 18px 29 | 30 | #score_board 31 | overflow: auto 32 | max-height: 200px 33 | li 34 | float: left 35 | height: 25px 36 | width: 100% 37 | border-bottom: 1px solid #999 38 | padding-top: 12px 39 | .head 40 | margin-left: 12px 41 | display: inline-block 42 | width: 15px 43 | height: 15px 44 | border-width: 4px 45 | .head-inner 46 | width: 7px 47 | height: 7px 48 | display: inline-block 49 | margin: 4px 50 | .name 51 | margin-left: 12px 52 | display: inline-block 53 | color: #6b6969 54 | font-weight: bold 55 | .step 56 | float: right 57 | margin-right: 10px 58 | padding-right: 20px 59 | font 60 | color: #333 61 | font-weight: bold 62 | .python .step 63 | background: url(/assets/p.gif) no-repeat right 64 | .ruby .step 65 | background: url(/assets/r.gif) no-repeat right 66 | .dead .step 67 | background: url(/assets/skeleton.gif) no-repeat right 68 | .dead 69 | background: #e9e9e9 70 | font 71 | color: #848484 72 | .no_border 73 | border: none 74 | 75 | #user-control 76 | #control-select 77 | margin: 4px auto 10px 78 | text-align: center 79 | #control-select a 80 | min-width: 100px 81 | padding: 6px 82 | &:hover 83 | color: black 84 | #control-select a.curr 85 | background-color: #0F9FBC 86 | +border-radius(4px) 87 | color: white 88 | 89 | #control-body 90 | width: 3 * 320px 91 | position: relative 92 | +single-transition(left, 0.5s) 93 | 94 | .control-panel 95 | width: 312px 96 | float: left 97 | 98 | #add-user, #record-panel, #change-map 99 | margin: 4px 100 | 101 | #record-panel 102 | #replay-count, #record-count 103 | color: black 104 | #record 105 | #local-load 106 | float: right 107 | 108 | #user-control-panel 109 | display: none 110 | position: relative 111 | margin: auto 112 | text-align: center 113 | #keyboard-shortcut-hint 114 | padding: 10px 115 | .op 116 | width: 50px 117 | height: 30px 118 | margin: 2px 2px 4px 119 | display: inline-block 120 | 121 | #teams 122 | display: table 123 | padding-top: 10px 124 | color: #848484 125 | font-family: '04B', Arial, Helvetica, sans-serif 126 | font-weight: 900 127 | font-size: 2px 128 | 129 | .color 130 | height: 14px 131 | width: 47px 132 | #pythons_team, #rubys_team 133 | text-align: center 134 | 135 | #pythons_team 136 | border-right: 1px solid #d9e0e6 137 | float: left 138 | height: 34px 139 | padding: 0 20px 140 | width: 103px 141 | img 142 | display: block 143 | margin: 0 auto 10px auto 144 | .color_1 145 | background: #a5c9e7 146 | float: left 147 | .color_2 148 | background: #88db99 149 | float: right 150 | 151 | #rubys_team 152 | float: left 153 | height: 34px 154 | padding: 0 20px 155 | width: 103px 156 | img 157 | display: block 158 | margin: 0 auto 10px auto 159 | .color_1 160 | background: #eb88a9 161 | float: left 162 | .color_2 163 | background: #f45e5e 164 | float: right 165 | 166 | #team_food 167 | border-bottom: 1px solid #d9e0e6 168 | border-top: 1px solid #d9e0e6 169 | height: 24px 170 | margin-top: 10px 171 | padding: 10px 0px 0px 20px 172 | img 173 | padding-right: 10px 174 | 175 | #team_category 176 | padding: 10px 0px 10px 20px 177 | img 178 | padding-right: 10px 179 | 180 | .clear 181 | clear: both 182 | 183 | 184 | #map_name, #map_author, #map_round, #map_status 185 | display: inline-block 186 | 187 | #map_round, #map_status 188 | padding-left: 30px 189 | 190 | #chat 191 | #msg 192 | width: 218px 193 | #msgs 194 | margin: 4px 195 | color: black 196 | min-height: 100px 197 | height: 150px 198 | overflow: auto 199 | #send-msg 200 | margin: 4px 201 | 202 | .right-block 203 | width: 100% 204 | margin-bottom: 10px 205 | background: #fff 206 | display: table 207 | .title_bar 208 | cursor: pointer 209 | .right_body 210 | overflow: hidden 211 | max-width: 320px 212 | 213 | #user_bar 214 | max-width: 1068px 215 | 216 | #control-remind 217 | margin: 10px 218 | text-align: center 219 | 220 | #save-data 221 | textarea 222 | width: 298px 223 | height: 50px 224 | margin: 2px 225 | 226 | 227 | #record-by 228 | font-size: 12px -------------------------------------------------------------------------------- /rubyweb/app/stylesheets/screen.sass: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. 2 | * In this file you should write your main styles. (or centralize your imports) 3 | * Import this file using the following HTML or equivalent: 4 | * 5 | 6 | @import compass/reset 7 | -------------------------------------------------------------------------------- /rubyweb/app/views/home/_event1.haml: -------------------------------------------------------------------------------- 1 | .mini_title 2 | %h1 3 | June 24th - June 26th Sprint of Snake Challenge @GuruDigger 4 | %br/ 5 | %br/ 6 | 2F, Building 16, Lane 30, North shanxi road, Shanghai, China 7 | .challenge_info 8 | %p.info 9 | PythonVSRuby (Or RubyVSPython) is an organization who will concentrate on better technical commnucation between Pythoners and Rubyiests. 10 | %br/ 11 | %br/ 12 | Every year we will organize a contest to see which side has the smartest engineer. It will take place annually around the end of March or the beginning of April. 13 | %br/ 14 | %br/ 15 | For the sake of making ourselves keep innovating, we will incubate a project as the contest platform every year and will stay with the project for a year. 16 | %br/ 17 | %br/ 18 | %h1 Upcoming Event 19 | %p.info 20 | PythonVSRuby 2011 Episode II - Sprint of Snake Challenge 21 | %br/ 22 | Source Code - 23 | %a{:href => "https://github.com/halida/snake-challenge", :target => "_blank"} https://bitbucket.org/linjunhalida/snake-challenge/wiki/Home 24 | %br/ 25 | Time: June 24th - June 26th 26 | %br/ 27 | %br/ 28 | We want to select 12 Geeks joining this sprint. We call them runners. If you are interested in being a runner, please contact me on 29 | = succeed "." do 30 | %a{:href => "mailto:mike@gurudigger.com", :target => "_blank"} mike@GuruDigger.com 31 | If we think you are qualified, we will pay you the flight , hotel and everything else for joining the event. 32 | %br/ 33 | %br/ 34 | If you want to join our brainstorming for this event, please click 35 | = succeed "." do 36 | %a{:href => "http://gurudigger.com/idea/detail?iid=31474"} here 37 | %br/ 38 | ( You need GuruDigger account to visit the brainstorming page, please contact 39 | %a{:href => "mailto:mike@gurudigger.com", :target => "_blank"} mike@GuruDigger.com 40 | for any GD account issues.) 41 | %br/ 42 | %br/ 43 | %h1 Agenda 44 | %br/ 45 | %table#schedule{:width => "100%"} 46 | %tr 47 | %td June 24th, Friday 48 | %td June 25th, Saturday 49 | %td June 26th, Sunday 50 | %tr 51 | %td 52 | %td 8:30 am, Breakfirst Start 53 | %td 8:30 am, Breakfirst Start 54 | %tr 55 | %td 56 | %td 57 | 9:00 am -12:00 pm, 58 | %br 59 | Brainstorming + Todo List + Task Assign /O*/I* 60 | %td 61 | From Wake up -12:00 pm, 62 | %br 63 | Coding /RO* 64 | %tr 65 | %td 66 | %td 12 :00 pm, Lunch Start /O* 67 | %td 12:00 pm, Lunch Start /O* 68 | %tr 69 | %td 70 | %td 71 | 12:00 pm - Midnight, 72 | %br 73 | Coding /RO* 74 | %td 75 | 12:00 pm - 5:00 pm, 76 | %br 77 | Coding /RO* 78 | %tr 79 | %td 80 | 9: 00 pm - Later, 81 | %br 82 | Warm Up /O* 83 | %td 84 | 6:00 pm, 85 | %br Dinner Start /O* 86 | %td 87 | 5pm, 88 | %br BBQ + Happy Time Start /O* 89 | %br/ 90 | \/O *=Open 91 | %br/ 92 | That means everybody could come, if you are not a runner, you have to pass our small quiz otherwise you have to make a donation for PythonVSRuby.org. Same as last time. ;) 93 | %br/ 94 | %br/ 95 | \/I*= Internet 96 | %br/ 97 | This time if you could not come to Shanghai, you could join us via internet. 98 | %br/ 99 | %br/ 100 | \/RO* = Runners Only 101 | %br/ 102 | For the sake of getting a good coding environment, we don't accept anybody who is not a runner come to visit us when we are coding. 103 | %br/ 104 | %br/ 105 | -------------------------------------------------------------------------------- /rubyweb/app/views/home/_event2.haml: -------------------------------------------------------------------------------- 1 | .mini_title 2 | %h1 3 | Snake Challenge 2011 Final Contest will be on Dec 18th, 2011 at Shanghai 4 | %p 5 | If you want to join our final contest, please contact us. 6 | 7 | .challenge_info 8 | %h1 About Us 9 | %p 10 | PythonVSRuby (Or RubyVSPython) is an organization who concentrate on better technical commnucation between Pythoners and Rubyiests. 11 | %p 12 | Every year we will organize 3 events. 13 | %br/ 14 | On April - New Platform "Celebrating" Contest 15 | %br/ 16 | On August - Hackathon to make a sprint of the platform. 17 | %br/ 18 | On December - Final Contest to decide the name will be "RubyVSPython" or "PythonVSRuby" for next year. 19 | %br/ 20 | %br/ 21 | 22 | 23 | %h1 Upcoming Event 24 | %p 25 | RubyVsPython 2011 Final Contest - Snake Challenge Platform 26 | %br/ 27 | Wiki - 28 | = link_to "https://github.com/halida/snake-challenge/wiki", "https://github.com/halida/snake-challenge/wiki", target: "_blank" 29 | %br/ 30 | Source Code - 31 | = link_to "https://github.com/halida/snake-challenge", "https://github.com/halida/snake-challenge", target: "_blank" 32 | %br/ 33 | Time: Dec 18th, 2011 34 | %br/ 35 | Venue: TBA (City: Shanghai) 36 | %br/ 37 | %br/ 38 | There will be 8 attendees (4 Rubyists and 4 Pythoners ) for the final contest. 39 | %br/ 40 | %br/ 41 | 1st Round 42 | %br/ 43 | The 8 attendees will be divided into 2 groups. Each group with 2 pythoners and 2 rubyiests. After this round, 2 attendees of each groups will be delegated. 44 | %br/ 45 | %br/ 46 | 2nd Round 47 | %br/ 48 | The 4 attendees will take the 2nd round. The winner of this round will decide the name of our organization to be RubyVSPython or PythonVSRuby for the year of 2012. 49 | %br/ 50 | %br/ 51 | The Final Round - AI VS Human Being 52 | %br/ 53 | We will pick up one of the audience who will control the creature manually to fight with the winner of the 2nd round. If the winner of the 2nd round win the game, he/she could get the prize of 2011 which worth 2000 RMB. 54 | 55 | %br/ 56 | %br/ 57 | If you want to join our final contest, please contact us. 58 | %br/ 59 | If you want to join our brainstorming for the Snake Challenge platform, please click 60 | = succeed "." do 61 | %a{:href => "http://gurudigger.com/ideas/20888"} here 62 | %br/ 63 | -------------------------------------------------------------------------------- /rubyweb/app/views/home/_event3.haml: -------------------------------------------------------------------------------- 1 | .mini_title 2 | %h1 3 | Lu Jun who represent RUBY win the final contest of year 2011!
4 | %p 5 | We will name ourselves as RubyVSPython in year of 2012! 6 | 7 | .challenge_info 8 | %h1 About Us 9 | %p 10 | PythonVSRuby (Or RubyVSPython) is an organization who concentrate on better technical commnucation between Pythoners and Rubyiests. 11 | %p 12 | Every year we will organize 3 events. 13 | %br/ 14 | On April - New Platform "Celebrating" Contest 15 | %br/ 16 | On August - Hackathon to make a sprint of the platform. 17 | %br/ 18 | On December - Final Contest to decide the name will be "RubyVSPython" or "PythonVSRuby" for next year. 19 | %br/ 20 | %br/ 21 | 22 | 23 | %h1 What We Will Do Next 24 | %p 25 | We are on the way of developing the contest platform for 2012 and we need more volunteers. If you are interested in that, please contact mike[at]gurudigger[dot]com. 26 | 27 | %h1 Contest Platform 28 | 29 | .platform{platform_id: 1} 30 | = image_tag "Planet_Conquer_thumbnail.jpg", class: "platform-img" 31 | .platform-desc 32 | %p Planet Conquer 33 | %p Year: 2012 34 | %p Launch Date: Mar 28th, 2012 35 | 36 | .platform{platform_id: 2} 37 | = image_tag "Snake_Challenge_thumbnail.jpg", class: "platform-img" 38 | .platform-desc 39 | %p= link_to "Snake Challege", "https://github.com/halida/snake-challenge/wiki", target: "_blank" 40 | %p Year: 2011 41 | %p Winner: Lu Jun 42 | 43 | .clearfix 44 | 45 | - content_for :javascripts do 46 | .platform-img-dialog{platform_id: 1} 47 | = image_tag "close.png", class: "dlg-close" 48 | = image_tag "Planet_Conquer_Big.jpg", class: "platform-img-big" 49 | .platform-img-dialog{platform_id: 2} 50 | = image_tag "close.png", class: "dlg-close" 51 | = image_tag "Snake_Challenge_Big.jpg", class: "platform-img-big" 52 | 53 | :coffeescript 54 | $('.platform-img').click ()-> 55 | parent = $($(this).parent()) 56 | platform_id = parent.attr('platform_id') 57 | $(".platform-img-dialog[platform_id="+platform_id+"]").toggleClass('on') 58 | $('.hide-all').toggleClass('on') 59 | 60 | $('.platform-img-dialog').click ()-> 61 | $(this).toggleClass('on') 62 | $('.hide-all').toggleClass('on') 63 | 64 | close_all = (e)-> 65 | $('.hide-all').removeClass('on') 66 | $('.platform-img-dialog').removeClass('on') 67 | e.preventDefault() 68 | 69 | $('.hide-all').click close_all 70 | 71 | -------------------------------------------------------------------------------- /rubyweb/app/views/home/index.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | 3 | .right_nav 4 | -# .title_bar_r 5 | -# %h1 Play Online 6 | 7 | -# #room_icons 8 | -# - for i in 1..4 9 | -# %a.room_icon{:href => "/room/#{i-1}/", id:"room-#{i}"} 10 | -# .number= "%02d" % i 11 | -# .room 12 | -# %div GAME 13 | -# %div ROOM 14 | -# #scoreboard-link= link_to "SCORE BOARD", "/home/scoreboard" 15 | 16 | -# - if !@replays.blank? 17 | -# .title_bar_r 18 | -# %h1 Game Replay 19 | -# #game_replay 20 | -# %ul 21 | -# - @replays.each do |item| 22 | -# %li 23 | -# %a{:href => replay_path(item.id)}= item.title 24 | -# %li.more 25 | -# %a{:href => replays_path} More... 26 | .title_bar_r 27 | %h1 Sponsors 28 | 29 | #sponsor_icon 30 | %a{:href => "http://gurudigger.com", :target => "_blank"} 31 | %img#sponsor{:src => image_path("gurudigger.png")}/ 32 | -# %a{:href => "http://douban.com", :target => "_blank"} 33 | -# %img#sponsor{:src => image_path("douban.png")}/ 34 | -# %a{:href => "http://snda.com", :target => "_blank"} 35 | -# %img#sponsor{:src => image_path("snda.png"), style:"margin-top:25px;"}/ 36 | -# %a{:href => "http://banner.alimama.com/", :target => "_blank"} 37 | -# %img#sponsor{:src => image_path("taobao.png"), style:"margin-top:25px;"}/ 38 | 39 | #follow 40 | %a{:href => "http://twitter.com/rubyvspython", :target => "_blank"} 41 | %img#twitter{:src => image_path("follow_us.png")}/ 42 | 43 | .left_content 44 | = link_to image_tag("brainstorming.png", class: "brainstorming"), "http://gurudigger.com/products/20888" 45 | = render partial: "event#{@event}" 46 | .clearfix 47 | 48 | -------------------------------------------------------------------------------- /rubyweb/app/views/home/scoreboard.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | #scoreboard 3 | - for name, data in [['daily', @data['dailys']], ['weekly', @data['weeklys']], ['monthly', @data['monthlys']]] 4 | %table{border: "1", cellpadding: "2", cellspacing: "2", class: name} 5 | %tr 6 | %th{COLSPAN: "2"}= "#{name} score" 7 | 8 | - for name, count in data 9 | %tr 10 | %td.name= name 11 | %td.score= count 12 | -------------------------------------------------------------------------------- /rubyweb/app/views/layouts/application.html.haml: -------------------------------------------------------------------------------- 1 | !!! Strict 2 | %html{:lang => "en"} 3 | %head 4 | %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/ 5 | %title Ruby VS Python Official Site 6 | %link{:href => "/assets/favicon.ico", :rel => "shortcut icon", :type => "image/x-icon"}/ 7 | 8 | = stylesheet_link_tag "main" 9 | = yield :styles 10 | = javascript_include_tag "jquery", "json", "application", "map_builder", "chatroom" 11 | = stylesheet_link_tag "narrow", media: "screen and (max-width: 768px)" 12 | 13 | = csrf_meta_tag 14 | :javascript 15 | init(); 16 | 17 | %body 18 | .hide-all 19 | #flash_error.flash{style: "display: none"} 20 | - if flash[:error] 21 | = flash[:error] 22 | :coffeescript 23 | $('#flash_error').show() 24 | setTimeout((-> $('.flash').fadeOut(500)), 10000) 25 | #flash_notice.flash{style: "display: none"} 26 | - if flash[:notice] 27 | = flash[:notice] 28 | :coffeescript 29 | $('#flash_notice').show() 30 | setTimeout((-> $('.flash').fadeOut(500)), 3000) 31 | 32 | %header 33 | -# %a{:href => "/", :title => "Go home"}= image_tag("logo.png", id:"logo-img") 34 | -# %br/ 35 | %a{:href => "/", :title => "Go home"}= image_tag("rubyvspythonlogo.png", id:"python-vs-ruby-img", style:"width: 220px") 36 | #main 37 | -# #user_bar 38 | -# - if current_user.blank? 39 | -# %a{:href => "/users/sign_up"} Sign Up 40 | -# | 41 | -# %a{:href => "/users/sign_in"} Sign In 42 | -# - else 43 | -# Hello, #{current_user.name} 44 | -# %a{:href => "/users/sign_out"} Sign out 45 | 46 | #content 47 | = yield 48 | 49 | %footer 50 | -# #member_icon 51 | -# %table 52 | -# %tr 53 | -# %td= link_to image_tag("memeber_icon_linjunhalida.gif"), "http://blog.linjunhalida.com/", :title=> "linjunhalida", :target=>"_blank" 54 | -# %td= link_to image_tag("memeber_icon_quake.gif"), "http://quake.javaeye.com/", :title=> "quake", :target=>"_blank" 55 | -# %td= link_to image_tag("memeber_icon_dorian.gif"), "#", :title=> "dorian" 56 | -# #footer-desc= image_tag("footer.png") 57 | 58 | = yield :javascripts 59 | 60 | :javascript 61 | var _gaq = _gaq || []; 62 | _gaq.push(['_setAccount', 'UA-22394366-1']); 63 | _gaq.push(['_trackPageview']); 64 | 65 | (function() { 66 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; 67 | ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 68 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); 69 | })(); -------------------------------------------------------------------------------- /rubyweb/app/views/maps/_form.html.haml: -------------------------------------------------------------------------------- 1 | = form_for(@map) do |f| 2 | %p 3 | = f.label :title 4 | = f.text_field :title 5 | = f.submit 6 | -------------------------------------------------------------------------------- /rubyweb/app/views/maps/index.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | .left_content 3 | .mini_title 4 | %h1 Snake Custom Maps 5 | = link_to("Create New Map",new_map_path) 6 | %ul#maps 7 | - @maps.each do |map| 8 | %li 9 | .title= link_to(map.title,map) 10 | .data= map.to_json 11 | .preview 12 | -------------------------------------------------------------------------------- /rubyweb/app/views/maps/new.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | .left_content 3 | .mini_title 4 | %h1 Create A New Map 5 | = render "form" -------------------------------------------------------------------------------- /rubyweb/app/views/maps/show.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | .left_content 3 | = link_to("All Maps",maps_path) 4 | .mini_title 5 | %h1 Map Editor: #{@map.title} 6 | %h1 created by Anonymous 7 | #map_builder 8 | .map 9 | .data= @map.to_json 10 | = form_for(@map) do |f| 11 | = text_area_tag :map_builder_data 12 | %p 13 | = f.label :height 14 | = f.text_field :height 15 | %br 16 | = f.label :width 17 | = f.text_field :width 18 | = f.submit 19 | -------------------------------------------------------------------------------- /rubyweb/app/views/replays/index.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | #replays 3 | %h1 Listing Replays 4 | %ul 5 | - @replays.each do |replay| 6 | %li 7 | = "from #{replay.user.name}: " if replay.user 8 | = link_to replay.title, replay 9 | = paginate @replays 10 | -------------------------------------------------------------------------------- /rubyweb/app/views/rooms/_controls.haml: -------------------------------------------------------------------------------- 1 | #user-control.right-block 2 | .title_bar CONTROL 3 | .right_body 4 | - unless signed_in? 5 | #control-remind 6 | You need 7 | %a{:href => "/users/sign_in"} Sign In 8 | or 9 | %a{:href => "/users/sign_up"} Sign Up 10 | to do more controls. 11 | - else 12 | #control-select 13 | %a.curr user control 14 | %a record 15 | %a set map 16 | :coffeescript 17 | $('#control-select a').click ()-> 18 | i = $(this).index() 19 | $('#control-select a.curr').removeClass('curr') 20 | $(this).addClass('curr') 21 | $('#control-body').css('left', -i*320 + 'px') 22 | 23 | #control-body 24 | .control-panel#add-user 25 | #add-user-panel 26 | %input{:onclick => "javascript:add_user('#{current_user.name}', $('#snake-type').val());", :type => "submit", :value => "ADD USER"}/ 27 | %select#snake-type 28 | %option python 29 | %option ruby 30 | 31 | #user-control-panel 32 | %p left, right, up, down or HLKJ to turn snake 33 | %p and S for sprint 34 | 35 | %p 36 | %input{type: "submit", onclick: "sprint()", class: "op", value: "sprint", id:"sprint"}/ 37 | %input{type: "submit", onclick: "turn(1)", class: "op", id: "turn-up", value: "^"}/ 38 | %input{type: "submit", onclick: "set_ai('simple_ai')", class: "op", value: "use ai", id:"setai"}/ 39 | %p 40 | %input{type: "submit", onclick: "turn(0)", class: "op", id: "turn-left", value: "<"}/ 41 | %input{type: "submit", onclick: "turn(3)", class: "op", id: "turn-down", value: "V"}/ 42 | %input{type: "submit", onclick: "turn(2)", class: "op", id: "turn-right", value: ">"}/ 43 | 44 | 45 | .control-panel#record-panel 46 | = form_for(Replay.new) do |f| 47 | .form 48 | 49 | #record 50 | %input{type: "submit", onclick: "javascript:toggle_record()", value: "RECORD", id: 'record-button'}/ 51 | %input{type: "submit", onclick: "javascript:toggle_replay()", value: "REPLAY", id: 'replay-button'}/ 52 | %span#replay-count 0 53 | = "/" 54 | %span#record-count 0 55 | %input{type: "submit", onclick: "javascript:load_replay_locally()", value: "LOAD", id: "local-load"}/ 56 | 57 | #save-record{style: "display: none"} 58 | %input{type: "submit", onclick: "javascript:save_replay()", value: "SAVE", id: 'save-record-button'}/ 59 | %input{type: "submit", onclick: "javascript:save_replay_locally()", value: "TO LOCAL"}/ 60 | 61 | 62 | #save-data{style: "display: none"} 63 | %textarea{type: "textarea"} 64 | %input{type: "submit", onclick: "javascript:$('#save-data').hide(300)", value: "OK"} 65 | 66 | 67 | .control-panel#change-map 68 | %input{type: "submit", onclick: "javascript:set_map($('select#maps').val())", value: "SET MAP", id: 'set-map-button'}/ 69 | %select#maps 70 | - for m in Map.all 71 | %option{value: m.id}= m.title 72 | 73 | -------------------------------------------------------------------------------- /rubyweb/app/views/rooms/_replays.haml: -------------------------------------------------------------------------------- 1 | #user-control.right-block 2 | .title_bar 3 | = @replay.title 4 | %span#record-by= "by #{@replay.user.name}" if @replay.user 5 | .right_body 6 | #record-panel 7 | %input{type: "submit", onclick: "javascript:toggle_replay()", value: "REPLAY", id: 'replay-button'}/ 8 | %span#replay-count 0 9 | = "/" 10 | %span#record-count 0 11 | 12 | :javascript 13 | load_replay(#{@replay.id}); 14 | 15 | -------------------------------------------------------------------------------- /rubyweb/app/views/rooms/_tips.haml: -------------------------------------------------------------------------------- 1 | #tips.right-block 2 | .title_bar TIPS 3 | .right_body 4 | #teams 5 | #pythons_team 6 | = image_tag("pythons_team_title.gif") 7 | .color.color_1 8 | .color.color_2 9 | #rubys_team 10 | = image_tag("rubys_team_title.gif") 11 | .color.color_1 12 | .color.color_2 13 | #team_food 14 | = image_tag("rubys_food.gif") 15 | = image_tag("pythons_food.gif") 16 | = image_tag("portal.gif") 17 | #team_category 18 | = image_tag("category_python.gif") 19 | = image_tag("category_ruby.gif") 20 | = image_tag("category_dead.gif") 21 | -------------------------------------------------------------------------------- /rubyweb/app/views/rooms/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :styles do 2 | = stylesheet_link_tag "room" 3 | = javascript_include_tag "simple_snake", "room" 4 | 5 | #left 6 | .title_bar 7 | #map_name 8 | #map_author 9 | #map_status 10 | #map_round 11 | %canvas#room-canvas 12 | #canvas_images{:style => "display:none;"} 13 | = image_tag("icons/egg.gif", :id => "icon_egg") 14 | = image_tag("icons/gem.gif", :id => "icon_gem") 15 | 16 | #right 17 | 18 | = render partial: "rooms/replays" if controller_name == 'replays' 19 | = render partial: "rooms/controls" if controller_name == 'rooms' 20 | .right-block#living_room 21 | .title_bar MEMBERS 22 | .right_body 23 | %ul#score_board 24 | = render partial: "rooms/tips" 25 | 26 | .right-block#chat 27 | .title_bar CHATS 28 | .right_body 29 | #send-msg 30 | %input{:type => "submit", :value => "SEND", onclick: "chat_send();"}/ 31 | %input#msg{:type => "text", }/ 32 | #msgs 33 | :javascript 34 | chat_init("ws://#{@chat_server}/chatroom", 35 | "#{current_user ? current_user.name : request.remote_ip}", 36 | "#{controller_name}-#{params[:id]}" 37 | ); 38 | $('#msg').keypress(function(e){ 39 | if (e.keyCode == 13) { 40 | chat_send(); 41 | e.preventDefault(); 42 | }; 43 | }); 44 | 45 | :javascript 46 | run_application("ws://#{@game_server}/info", #{@room_id}, #{controller_name == 'replays'}); 47 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/confirmations/new.html.haml: -------------------------------------------------------------------------------- 1 | %h2 Resend confirmation instructions 2 | = form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| 3 | = devise_error_messages! 4 | %p 5 | = f.email_field :email, placeholder: "email" 6 | %p= f.submit "Resend confirmation instructions" 7 | = render :partial => "devise/shared/links" 8 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/mailer/confirmation_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Welcome #{@resource.email}! 3 | %p You can confirm your account through the link below: 4 | %p= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) 5 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/mailer/reset_password_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Hello #{@resource.email}! 3 | %p Someone has requested a link to change your password, and you can do this through the link below. 4 | %p= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) 5 | %p If you didn't request this, please ignore this email. 6 | %p Your password won't change until you access the link above and create a new one. 7 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/mailer/unlock_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Hello #{@resource.email}! 3 | %p Your account has been locked due to an excessive amount of unsuccessful sign in attempts. 4 | %p Click the link below to unlock your account: 5 | %p= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) 6 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/passwords/edit.html.haml: -------------------------------------------------------------------------------- 1 | %h2 Change your password 2 | = form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| 3 | = devise_error_messages! 4 | = f.hidden_field :reset_password_token 5 | %p= f.password_field :password, placeholder: "New password" 6 | %p= f.password_field :password_confirmation, placeholder: "Confirm new password" 7 | %p= f.submit "Change my password" 8 | = render :partial => "devise/shared/links" 9 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/passwords/new.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | .left_content 3 | %h1 Forgot your password? 4 | = form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| 5 | = devise_error_messages! 6 | %p= f.email_field :email, placeholder: "email" 7 | %p= f.submit "Send me reset password instructions" 8 | = render :partial => "devise/shared/links" 9 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/registrations/edit.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | %h1 Edit #{resource_name.to_s.humanize} 3 | = form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| 4 | = devise_error_messages! 5 | %p= f.email_field :email, placeholder: "email" 6 | %p 7 | %i (leave blank if you don't want to change it) 8 | = f.password_field :password, placeholder: "password" 9 | %p= f.password_field :password_confirmation, placeholder: "Confirm Your Password" 10 | %p 11 | %i (we need your current password to confirm your changes) 12 | = f.password_field :current_password, placeholder: "Current Password" 13 | %p= f.submit "Update" 14 | %h3 Cancel my account 15 | %p 16 | Unhappy? #{link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete}. 17 | = link_to "Back", :back 18 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/registrations/new.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | .left_content 3 | %h1 Sign up 4 | = form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| 5 | = devise_error_messages! 6 | %p= f.email_field :email, placeholder: "Email" 7 | %p= f.text_field :name, placeholder: "Name" 8 | %p= f.password_field :password, placeholder: "Password" 9 | %p= f.password_field :password_confirmation, placeholder: "Password Confirmation" 10 | %p= f.submit "Sign up" 11 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/sessions/new.html.haml: -------------------------------------------------------------------------------- 1 | #place 2 | .left_content 3 | %h1 Sign in 4 | = form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| 5 | %p 6 | = f.email_field :email, placeholder: 'email' 7 | -# %p= link_to "Forgot your password?", "/users/password/new" 8 | %p= f.password_field :password, placeholder: 'password' 9 | - if devise_mapping.rememberable? 10 | %p 11 | = f.check_box :remember_me 12 | = f.label :remember_me 13 | %p= f.submit "Sign in" 14 | 15 | -------------------------------------------------------------------------------- /rubyweb/app/views/users/unlocks/new.html.haml: -------------------------------------------------------------------------------- 1 | %h2 Resend unlock instructions 2 | = form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| 3 | = devise_error_messages! 4 | %p 5 | = f.label :email 6 | %br/ 7 | = f.email_field :email 8 | %p= f.submit "Resend unlock instructions" 9 | = render :partial => "devise/shared/links" 10 | -------------------------------------------------------------------------------- /rubyweb/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rubyweb::Application 5 | -------------------------------------------------------------------------------- /rubyweb/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | if defined?(Bundler) 6 | # If you precompile assets before deploying to production, use this line 7 | Bundler.require *Rails.groups(:assets => %w(development test)) 8 | # If you want your assets lazily compiled in production, use this line 9 | # Bundler.require(:default, :assets, Rails.env) 10 | end 11 | 12 | module Rubyweb 13 | class Application < Rails::Application 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | # Custom directories with classes and modules you want to be autoloadable. 19 | # config.autoload_paths += %W(#{config.root}/extras) 20 | 21 | # Only load the plugins named here, in the order given (default is alphabetical). 22 | # :all can be used as a placeholder for all plugins not explicitly named. 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 24 | 25 | # Activate observers that should always be running. 26 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 27 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 30 | # config.time_zone = 'Central Time (US & Canada)' 31 | 32 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 33 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 34 | # config.i18n.default_locale = :de 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable the asset pipeline 43 | config.assets.enabled = true 44 | 45 | # Version of your assets, change this if you want to expire all your assets 46 | config.assets.version = '1.0' 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /rubyweb/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /rubyweb/config/compass.rb: -------------------------------------------------------------------------------- 1 | # This configuration file works with both the Compass command line tool and within Rails. 2 | # Require any additional compass plugins here. 3 | project_type = :rails 4 | 5 | # Set this to the root of your project when deployed: 6 | http_path = "/" 7 | css_dir = "public/assets/" 8 | sass_dir = "app/stylesheets" 9 | 10 | # You can select your preferred output style here (can be overridden via the command line): 11 | # output_style = :expanded or :nested or :compact or :compressed 12 | 13 | # To enable relative paths to assets via compass helper functions. Uncomment: 14 | # relative_assets = true 15 | 16 | # To disable debugging comments that display the original location of your selectors. Uncomment: 17 | # line_comments = false 18 | 19 | 20 | # If you prefer the indented syntax, you might want to regenerate this 21 | # project again passing --syntax sass, or you can uncomment this: 22 | # preferred_syntax = :sass 23 | # and then run: 24 | # sass-convert -R --from scss --to sass app/stylesheets scss && rm -rf sass && mv scss sass 25 | -------------------------------------------------------------------------------- /rubyweb/config/cucumber.yml: -------------------------------------------------------------------------------- 1 | <% 2 | rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" 3 | rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" 4 | std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" 5 | %> 6 | default: --drb <%= std_opts %> features 7 | wip: --drb --tags @wip:3 --wip features 8 | rerun: --drb <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip 9 | -------------------------------------------------------------------------------- /rubyweb/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3-ruby (not necessary on OS X Leopard) 3 | development: 4 | adapter: mysql2 5 | encoding: utf8 6 | reconnect: false 7 | database: 'snake_challenge_dev' 8 | pool: 5 9 | username: 'monster' 10 | password: '123123' 11 | host: "localhost" 12 | 13 | # Warning: The database defined as "test" will be erased and 14 | # re-generated from your development database when you run "rake". 15 | # Do not set this db to the same as development or production. 16 | test: 17 | adapter: mysql2 18 | encoding: utf8 19 | reconnect: false 20 | database: 'snake_challenge_test' 21 | pool: 5 22 | username: 'monster' 23 | password: '123123' 24 | host: "192.168.1.114" 25 | 26 | production: 27 | adapter: mysql2 28 | encoding: utf8 29 | reconnect: false 30 | database: 'personlab_production' 31 | pool: 5 32 | username: 'monster' 33 | password: '123123' 34 | socket: '/tmp/mysql.sock' 35 | -------------------------------------------------------------------------------- /rubyweb/config/database.yml.example: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3-ruby (not necessary on OS X Leopard) 3 | development: 4 | adapter: mysql2 5 | encoding: utf8 6 | reconnect: false 7 | database: 'snake_challenge_dev' 8 | pool: 5 9 | username: 'monster' 10 | password: '123123' 11 | host: "192.168.1.114" 12 | 13 | # Warning: The database defined as "test" will be erased and 14 | # re-generated from your development database when you run "rake". 15 | # Do not set this db to the same as development or production. 16 | test: &test 17 | adapter: mysql2 18 | encoding: utf8 19 | reconnect: false 20 | database: 'snake_challenge_test' 21 | pool: 5 22 | #username: 'monster' 23 | #password: '123123' 24 | #host: "192.168.1.219" 25 | 26 | production: 27 | adapter: mysql2 28 | encoding: utf8 29 | reconnect: false 30 | database: 'personlab_production' 31 | pool: 5 32 | username: 'monster' 33 | password: '123123' 34 | socket: '/tmp/mysql.sock' 35 | 36 | 37 | cucumber: 38 | <<: *test 39 | -------------------------------------------------------------------------------- /rubyweb/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Rubyweb::Application.initialize! 6 | 7 | -------------------------------------------------------------------------------- /rubyweb/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rubyweb::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Do not compress assets 26 | config.assets.compress = false 27 | 28 | # Expands the lines which load the assets 29 | config.assets.debug = true 30 | end 31 | -------------------------------------------------------------------------------- /rubyweb/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rubyweb::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to Rails.root.join("public/assets") 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Use a different logger for distributed setups 37 | # config.logger = SyslogLogger.new 38 | 39 | # Use a different cache store in production 40 | # config.cache_store = :mem_cache_store 41 | 42 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 43 | # config.action_controller.asset_host = "http://assets.example.com" 44 | 45 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 46 | # config.assets.precompile += %w( search.js ) 47 | 48 | # Disable delivery errors, bad email addresses will be ignored 49 | # config.action_mailer.raise_delivery_errors = false 50 | 51 | # Enable threaded mode 52 | # config.threadsafe! 53 | 54 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 55 | # the I18n.default_locale when a translation can not be found) 56 | config.i18n.fallbacks = true 57 | 58 | # Send deprecation notices to registered listeners 59 | config.active_support.deprecation = :notify 60 | end 61 | -------------------------------------------------------------------------------- /rubyweb/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rubyweb::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Use SQL instead of Active Record's schema dumper when creating the test database. 33 | # This is necessary if your schema can't be completely dumped by the schema dumper, 34 | # like if you have constraints or database-specific column types 35 | # config.active_record.schema_format = :sql 36 | 37 | # Print deprecation notices to the stderr 38 | config.active_support.deprecation = :stderr 39 | 40 | # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets 41 | config.assets.allow_debugging = true 42 | end 43 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/active_record_defaults.rb: -------------------------------------------------------------------------------- 1 | ActiveRecord::Base.include_root_in_json = false 2 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Rubyweb::Application.config.secret_token = '1ba4f2420c21c36203c40cd18cdfcc0c6b0cb56966cba29acadbc292b2d21f51fff8bc823abaa4e908728e8f355fe12f4efdfa02d0c12756dfcd1b4956d3ccbe' 8 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rubyweb::Application.config.session_store :cookie_store, key: '_rubyweb_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Rubyweb::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /rubyweb/config/initializers/zeromq.rb: -------------------------------------------------------------------------------- 1 | $zmq_context = ZMQ::Context.new 2 | 3 | $zmq_req = $zmq_context.socket(ZMQ::REQ) 4 | $zmq_req.connect('ipc:///tmp/game_oper.ipc') 5 | 6 | $zmq_sub = $zmq_context.socket(ZMQ::SUB) 7 | $zmq_sub.connect('ipc:///tmp/game_puber.ipc') 8 | -------------------------------------------------------------------------------- /rubyweb/config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at http://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | errors: 5 | messages: 6 | expired: "has expired, please request a new one" 7 | not_found: "not found" 8 | already_confirmed: "was already confirmed, please try signing in" 9 | not_locked: "was not locked" 10 | not_saved: 11 | one: "1 error prohibited this %{resource} from being saved:" 12 | other: "%{count} errors prohibited this %{resource} from being saved:" 13 | 14 | devise: 15 | failure: 16 | already_authenticated: 'You are already signed in.' 17 | unauthenticated: 'You need to sign in or sign up before continuing.' 18 | unconfirmed: 'You have to confirm your account before continuing.' 19 | locked: 'Your account is locked.' 20 | invalid: 'Invalid email or password.' 21 | invalid_token: 'Invalid authentication token.' 22 | timeout: 'Your session expired, please sign in again to continue.' 23 | inactive: 'Your account was not activated yet.' 24 | sessions: 25 | signed_in: 'Signed in successfully.' 26 | signed_out: 'Signed out successfully.' 27 | passwords: 28 | send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' 29 | updated: 'Your password was changed successfully. You are now signed in.' 30 | send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail" 31 | confirmations: 32 | send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' 33 | send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.' 34 | confirmed: 'Your account was successfully confirmed. You are now signed in.' 35 | registrations: 36 | signed_up: 'Welcome! You have signed up successfully.' 37 | inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.' 38 | updated: 'You updated your account successfully.' 39 | destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' 40 | unlocks: 41 | send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' 42 | unlocked: 'Your account was successfully unlocked. You are now signed in.' 43 | send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.' 44 | omniauth_callbacks: 45 | success: 'Successfully authorized from %{kind} account.' 46 | failure: 'Could not authorize you from %{kind} because "%{reason}".' 47 | mailer: 48 | confirmation_instructions: 49 | subject: 'Confirmation instructions' 50 | reset_password_instructions: 51 | subject: 'Reset password instructions' 52 | unlock_instructions: 53 | subject: 'Unlock Instructions' 54 | -------------------------------------------------------------------------------- /rubyweb/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /rubyweb/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rubyweb::Application.routes.draw do 2 | resources :replays 3 | 4 | root :to => "home#index" 5 | resources :room, :controller => :rooms do 6 | member do 7 | get :info 8 | get :map 9 | post :add 10 | post :turn 11 | end 12 | end 13 | 14 | resources :maps 15 | 16 | devise_for :users 17 | 18 | match ':controller(/:action(/:id(.:format)))' 19 | 20 | end 21 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110625045622_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 2 | def self.up 3 | create_table(:users) do |t| 4 | t.database_authenticatable :null => false 5 | t.recoverable 6 | t.rememberable 7 | t.trackable 8 | 9 | # t.encryptable 10 | # t.confirmable 11 | # t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both 12 | # t.token_authenticatable 13 | 14 | 15 | t.timestamps 16 | end 17 | 18 | add_index :users, :email, :unique => true 19 | add_index :users, :reset_password_token, :unique => true 20 | # add_index :users, :confirmation_token, :unique => true 21 | # add_index :users, :unlock_token, :unique => true 22 | # add_index :users, :authentication_token, :unique => true 23 | end 24 | 25 | def self.down 26 | drop_table :users 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110625052210_create_rooms.rb: -------------------------------------------------------------------------------- 1 | class CreateRooms < ActiveRecord::Migration 2 | def self.up 3 | create_table :rooms do |t| 4 | t.string :name, :null => false 5 | 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :rooms 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110625072033_create_replays.rb: -------------------------------------------------------------------------------- 1 | class CreateReplays < ActiveRecord::Migration 2 | def self.up 3 | create_table :replays do |t| 4 | t.string :title, :null => false 5 | t.text :json, :null => false 6 | t.integer :user_id 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :replays 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110626025151_add_map_to_replays.rb: -------------------------------------------------------------------------------- 1 | class AddMapToReplays < ActiveRecord::Migration 2 | def self.up 3 | add_column :replays, :map, :string 4 | end 5 | 6 | def self.down 7 | remove_column :replays, :map, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110626063853_add_field_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddFieldToUsers < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :name, :string 4 | add_column :users, :blog, :string 5 | add_column :users, :twitter, :string 6 | add_column :users, :bio, :string 7 | end 8 | 9 | def self.down 10 | remove_column :users, :name 11 | remove_column :users, :blog 12 | remove_column :users, :twitter 13 | remove_column :users, :bio 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110626064926_devise_create_admin_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateAdminUsers < ActiveRecord::Migration 2 | def self.up 3 | create_table(:admin_users) do |t| 4 | t.database_authenticatable :null => false 5 | t.recoverable 6 | t.rememberable 7 | t.trackable 8 | 9 | # t.encryptable 10 | # t.confirmable 11 | # t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both 12 | # t.token_authenticatable 13 | 14 | 15 | t.timestamps 16 | end 17 | 18 | # Create a default user 19 | AdminUser.create!(:email => 'admin@example.com', :password => 'password', :password_confirmation => 'password') 20 | 21 | add_index :admin_users, :email, :unique => true 22 | add_index :admin_users, :reset_password_token, :unique => true 23 | # add_index :admin_users, :confirmation_token, :unique => true 24 | # add_index :admin_users, :unlock_token, :unique => true 25 | # add_index :admin_users, :authentication_token, :unique => true 26 | end 27 | 28 | def self.down 29 | drop_table :admin_users 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110626144926_create_admin_notes.rb: -------------------------------------------------------------------------------- 1 | class CreateAdminNotes < ActiveRecord::Migration 2 | def self.up 3 | create_table :admin_notes do |t| 4 | t.references :resource, :polymorphic => true, :null => false 5 | t.references :admin_user, :polymorphic => true 6 | t.text :body 7 | t.timestamps 8 | end 9 | add_index :admin_notes, [:resource_type, :resource_id] 10 | add_index :admin_notes, [:admin_user_type, :admin_user_id] 11 | end 12 | 13 | def self.down 14 | drop_table :admin_notes 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20110626144927_move_admin_notes_to_comments.rb: -------------------------------------------------------------------------------- 1 | class MoveAdminNotesToComments < ActiveRecord::Migration 2 | def self.up 3 | remove_index :admin_notes, [:admin_user_type, :admin_user_id] 4 | rename_table :admin_notes, :active_admin_comments 5 | rename_column :active_admin_comments, :admin_user_type, :author_type 6 | rename_column :active_admin_comments, :admin_user_id, :author_id 7 | add_column :active_admin_comments, :namespace, :string 8 | add_index :active_admin_comments, [:namespace] 9 | add_index :active_admin_comments, [:author_type, :author_id] 10 | 11 | # Update all the existing comments to the default namespace 12 | say "Updating any existing comments to the #{ActiveAdmin.default_namespace} namespace." 13 | execute "UPDATE active_admin_comments SET namespace='#{ActiveAdmin.default_namespace}'" 14 | end 15 | 16 | def self.down 17 | remove_index :active_admin_comments, :column => [:author_type, :author_id] 18 | remove_index :active_admin_comments, :column => [:namespace] 19 | remove_column :active_admin_comments, :namespace 20 | rename_column :active_admin_comments, :author_id, :admin_user_id 21 | rename_column :active_admin_comments, :author_type, :admin_user_type 22 | rename_table :active_admin_comments, :admin_notes 23 | add_index :admin_notes, [:admin_user_type, :admin_user_id] 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /rubyweb/db/migrate/20111130040507_create_maps.rb: -------------------------------------------------------------------------------- 1 | class CreateMaps < ActiveRecord::Migration 2 | def change 3 | create_table :maps do |t| 4 | t.integer :user 5 | t.string :title 6 | t.text :data 7 | t.integer :height 8 | t.integer :width 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /rubyweb/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20111130040507) do 15 | 16 | create_table "active_admin_comments", :force => true do |t| 17 | t.integer "resource_id", :null => false 18 | t.string "resource_type", :null => false 19 | t.integer "author_id" 20 | t.string "author_type" 21 | t.text "body" 22 | t.datetime "created_at" 23 | t.datetime "updated_at" 24 | t.string "namespace" 25 | end 26 | 27 | add_index "active_admin_comments", ["author_type", "author_id"], :name => "index_active_admin_comments_on_author_type_and_author_id" 28 | add_index "active_admin_comments", ["namespace"], :name => "index_active_admin_comments_on_namespace" 29 | add_index "active_admin_comments", ["resource_type", "resource_id"], :name => "index_admin_notes_on_resource_type_and_resource_id" 30 | 31 | create_table "admin_users", :force => true do |t| 32 | t.string "email", :default => "", :null => false 33 | t.string "encrypted_password", :limit => 128, :default => "", :null => false 34 | t.string "reset_password_token" 35 | t.datetime "reset_password_sent_at" 36 | t.datetime "remember_created_at" 37 | t.integer "sign_in_count", :default => 0 38 | t.datetime "current_sign_in_at" 39 | t.datetime "last_sign_in_at" 40 | t.string "current_sign_in_ip" 41 | t.string "last_sign_in_ip" 42 | t.datetime "created_at" 43 | t.datetime "updated_at" 44 | end 45 | 46 | add_index "admin_users", ["email"], :name => "index_admin_users_on_email", :unique => true 47 | add_index "admin_users", ["reset_password_token"], :name => "index_admin_users_on_reset_password_token", :unique => true 48 | 49 | create_table "maps", :force => true do |t| 50 | t.integer "user" 51 | t.string "title" 52 | t.text "data" 53 | t.integer "height" 54 | t.integer "width" 55 | t.datetime "created_at" 56 | t.datetime "updated_at" 57 | end 58 | 59 | create_table "replays", :force => true do |t| 60 | t.string "title", :null => false 61 | t.text "json", :null => false 62 | t.integer "user_id" 63 | t.datetime "created_at" 64 | t.datetime "updated_at" 65 | t.string "map" 66 | end 67 | 68 | create_table "rooms", :force => true do |t| 69 | t.string "name", :null => false 70 | t.datetime "created_at" 71 | t.datetime "updated_at" 72 | end 73 | 74 | create_table "users", :force => true do |t| 75 | t.string "email", :default => "", :null => false 76 | t.string "encrypted_password", :limit => 128, :default => "", :null => false 77 | t.string "reset_password_token" 78 | t.datetime "reset_password_sent_at" 79 | t.datetime "remember_created_at" 80 | t.integer "sign_in_count", :default => 0 81 | t.datetime "current_sign_in_at" 82 | t.datetime "last_sign_in_at" 83 | t.string "current_sign_in_ip" 84 | t.string "last_sign_in_ip" 85 | t.datetime "created_at" 86 | t.datetime "updated_at" 87 | t.string "name" 88 | t.string "blog" 89 | t.string "twitter" 90 | t.string "bio" 91 | end 92 | 93 | add_index "users", ["email"], :name => "index_users_on_email", :unique => true 94 | add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true 95 | 96 | end 97 | -------------------------------------------------------------------------------- /rubyweb/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) 7 | # Mayor.create(:name => 'Daley', :city => cities.first) 8 | -------------------------------------------------------------------------------- /rubyweb/doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /rubyweb/features/map_editor_create.feature: -------------------------------------------------------------------------------- 1 | Feature: Can Create A New Map 2 | Background: 3 | Given I am on the new map page 4 | And I fill in "Title" with "A Brave New Map" 5 | Then I press "Create Map" 6 | Scenario: A new map 7 | Then I should see "A new map was created" 8 | Then I should see "Map Editor: A Brave New Map" 9 | And I should see "created by Anonymous" 10 | Scenario: Creating a map with duplicate title 11 | Then I am on the new map page 12 | And I fill in "Title" with "A Brave New Map" 13 | Then I press "Create Map" 14 | Then I should see "Error creating the map" 15 | Scenario: See it in the index page 16 | And I am on the maps page 17 | Then I should see "A Brave New Map" within "ul#maps" 18 | -------------------------------------------------------------------------------- /rubyweb/features/support/env.rb: -------------------------------------------------------------------------------- 1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. 2 | # It is recommended to regenerate this file in the future when you upgrade to a 3 | # newer version of cucumber-rails. Consider adding your own code to a new file 4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb 5 | # files. 6 | 7 | require 'rubygems' 8 | require 'spork' 9 | 10 | Spork.prefork do 11 | require 'cucumber/rails' 12 | 13 | 14 | # Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In 15 | # order to ease the transition to Capybara we set the default here. If you'd 16 | # prefer to use XPath just remove this line and adjust any selectors in your 17 | # steps to use the XPath syntax. 18 | Capybara.default_selector = :css 19 | 20 | end 21 | 22 | Spork.each_run do 23 | # By default, any exception happening in your Rails application will bubble up 24 | # to Cucumber so that your scenario will fail. This is a different from how 25 | # your application behaves in the production environment, where an error page will 26 | # be rendered instead. 27 | # 28 | # Sometimes we want to override this default behaviour and allow Rails to rescue 29 | # exceptions and display an error page (just like when the app is running in production). 30 | # Typical scenarios where you want to do this is when you test your error pages. 31 | # There are two ways to allow Rails to rescue exceptions: 32 | # 33 | # 1) Tag your scenario (or feature) with @allow-rescue 34 | # 35 | # 2) Set the value below to true. Beware that doing this globally is not 36 | # recommended as it will mask a lot of errors for you! 37 | # 38 | ActionController::Base.allow_rescue = false 39 | 40 | # Remove/comment out the lines below if your app doesn't have a database. 41 | # For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. 42 | begin 43 | DatabaseCleaner.strategy = :transaction 44 | rescue NameError 45 | raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." 46 | end 47 | 48 | # You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios. 49 | # See the DatabaseCleaner documentation for details. Example: 50 | # 51 | # Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do 52 | # DatabaseCleaner.strategy = :truncation, {:except => %w[widgets]} 53 | # end 54 | # 55 | # Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do 56 | # DatabaseCleaner.strategy = :transaction 57 | # end 58 | # 59 | end 60 | -------------------------------------------------------------------------------- /rubyweb/features/support/paths.rb: -------------------------------------------------------------------------------- 1 | module NavigationHelpers 2 | # Maps a name to a path. Used by the 3 | # 4 | # When /^I go to (.+)$/ do |page_name| 5 | # 6 | # step definition in web_steps.rb 7 | # 8 | def path_to(page_name) 9 | case page_name 10 | 11 | when /^the home\s?page$/ 12 | '/' 13 | 14 | # Add more mappings here. 15 | # Here is an example that pulls values out of the Regexp: 16 | # 17 | # when /^(.*)'s profile page$/i 18 | # user_profile_path(User.find_by_login($1)) 19 | 20 | else 21 | begin 22 | page_name =~ /^the (.*) page$/ 23 | path_components = $1.split(/\s+/) 24 | self.send(path_components.push('path').join('_').to_sym) 25 | rescue NoMethodError, ArgumentError 26 | raise "Can't find mapping from \"#{page_name}\" to a path.\n" + 27 | "Now, go and add a mapping in #{__FILE__}" 28 | end 29 | end 30 | end 31 | end 32 | 33 | World(NavigationHelpers) 34 | -------------------------------------------------------------------------------- /rubyweb/features/support/selectors.rb: -------------------------------------------------------------------------------- 1 | module HtmlSelectorsHelpers 2 | # Maps a name to a selector. Used primarily by the 3 | # 4 | # When /^(.+) within (.+)$/ do |step, scope| 5 | # 6 | # step definitions in web_steps.rb 7 | # 8 | def selector_for(locator) 9 | case locator 10 | 11 | when "the page" 12 | "html > body" 13 | 14 | # Add more mappings here. 15 | # Here is an example that pulls values out of the Regexp: 16 | # 17 | # when /^the (notice|error|info) flash$/ 18 | # ".flash.#{$1}" 19 | 20 | # You can also return an array to use a different selector 21 | # type, like: 22 | # 23 | # when /the header/ 24 | # [:xpath, "//header"] 25 | 26 | # This allows you to provide a quoted selector as the scope 27 | # for "within" steps as was previously the default for the 28 | # web steps: 29 | when /^"(.+)"$/ 30 | $1 31 | 32 | else 33 | raise "Can't find mapping from \"#{locator}\" to a selector.\n" + 34 | "Now, go and add a mapping in #{__FILE__}" 35 | end 36 | end 37 | end 38 | 39 | World(HtmlSelectorsHelpers) 40 | -------------------------------------------------------------------------------- /rubyweb/lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /rubyweb/lib/tasks/cucumber.rake: -------------------------------------------------------------------------------- 1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. 2 | # It is recommended to regenerate this file in the future when you upgrade to a 3 | # newer version of cucumber-rails. Consider adding your own code to a new file 4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb 5 | # files. 6 | 7 | 8 | unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks 9 | 10 | vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first 11 | $LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? 12 | 13 | begin 14 | require 'cucumber/rake/task' 15 | 16 | namespace :cucumber do 17 | Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| 18 | t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. 19 | t.fork = true # You may get faster startup if you set this to false 20 | t.profile = 'default' 21 | end 22 | 23 | Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t| 24 | t.binary = vendored_cucumber_bin 25 | t.fork = true # You may get faster startup if you set this to false 26 | t.profile = 'wip' 27 | end 28 | 29 | Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t| 30 | t.binary = vendored_cucumber_bin 31 | t.fork = true # You may get faster startup if you set this to false 32 | t.profile = 'rerun' 33 | end 34 | 35 | desc 'Run all features' 36 | task :all => [:ok, :wip] 37 | 38 | task :statsetup do 39 | require 'rails/code_statistics' 40 | ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') 41 | ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') 42 | end 43 | end 44 | desc 'Alias for cucumber:ok' 45 | task :cucumber => 'cucumber:ok' 46 | 47 | task :default => :cucumber 48 | 49 | task :features => :cucumber do 50 | STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" 51 | end 52 | 53 | # In case we don't have ActiveRecord, append a no-op task that we can depend upon. 54 | task 'db:test:prepare' do 55 | end 56 | 57 | task :stats => 'cucumber:statsetup' 58 | rescue LoadError 59 | desc 'cucumber rake task not available (cucumber not installed)' 60 | task :cucumber do 61 | abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' 62 | end 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /rubyweb/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /rubyweb/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /rubyweb/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /rubyweb/public/assets/04B.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/04B.ttf -------------------------------------------------------------------------------- /rubyweb/public/assets/Planet_Conquer_Big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/Planet_Conquer_Big.jpg -------------------------------------------------------------------------------- /rubyweb/public/assets/Planet_Conquer_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/Planet_Conquer_thumbnail.jpg -------------------------------------------------------------------------------- /rubyweb/public/assets/Snake_Challenge_Big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/Snake_Challenge_Big.jpg -------------------------------------------------------------------------------- /rubyweb/public/assets/Snake_Challenge_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/Snake_Challenge_thumbnail.jpg -------------------------------------------------------------------------------- /rubyweb/public/assets/active_admin.js: -------------------------------------------------------------------------------- 1 | /* Active Admin JS */ 2 | 3 | $(function(){ 4 | $(".datepicker").datepicker({dateFormat: 'yy-mm-dd'}); 5 | 6 | $(".clear_filters_btn").click(function(){ 7 | window.location.search = ""; 8 | return false; 9 | }); 10 | 11 | // AJAX Comments 12 | $('form#admin_note_new').submit(function() { 13 | 14 | if ($(this).find('#admin_note_body').val() != "") { 15 | $(this).fadeOut('slow', function() { 16 | $('.loading_indicator').fadeIn(); 17 | $.ajax({ 18 | url: $(this).attr('action'), 19 | type: 'POST', 20 | dataType: 'json', 21 | data: $(this).serialize(), 22 | success: function(data, textStatus, xhr) { 23 | $('.loading_indicator').fadeOut('slow', function(){ 24 | 25 | // Hide the empty message 26 | $('.admin_notes_list li.empty').fadeOut().remove(); 27 | 28 | // Add the note 29 | $('.admin_notes_list').append(data['note']); 30 | 31 | // Update the number of notes 32 | $('.admin_notes h3 span.admin_notes_count').html("(" + data['number_of_notes'] + ")"); 33 | 34 | // Reset the form 35 | $('form#new_active_admin_admin_note').find('#active_admin_admin_note_body').val(""); 36 | 37 | // Show the form 38 | $('form#new_active_admin_admin_note').fadeIn('slow'); 39 | }) 40 | }, 41 | error: function(xhr, textStatus, errorThrown) { 42 | //called when there is an error 43 | } 44 | }); 45 | }); 46 | 47 | }; 48 | 49 | return false; 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /rubyweb/public/assets/active_admin/admin_notes_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/active_admin/admin_notes_icon.png -------------------------------------------------------------------------------- /rubyweb/public/assets/active_admin/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/active_admin/loading.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/active_admin/nested_menu_arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/active_admin/nested_menu_arrow.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/active_admin/nested_menu_arrow_dark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/active_admin/nested_menu_arrow_dark.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/active_admin/orderable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/active_admin/orderable.png -------------------------------------------------------------------------------- /rubyweb/public/assets/bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/bg.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/bg.jpg -------------------------------------------------------------------------------- /rubyweb/public/assets/brainstorming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/brainstorming.png -------------------------------------------------------------------------------- /rubyweb/public/assets/category_dead.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/category_dead.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/category_python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/category_python.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/category_ruby.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/category_ruby.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/choose_room.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/choose_room.png -------------------------------------------------------------------------------- /rubyweb/public/assets/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/close.png -------------------------------------------------------------------------------- /rubyweb/public/assets/douban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/douban.png -------------------------------------------------------------------------------- /rubyweb/public/assets/ekohe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/ekohe.png -------------------------------------------------------------------------------- /rubyweb/public/assets/electronica_nine.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/electronica_nine.ttf -------------------------------------------------------------------------------- /rubyweb/public/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/favicon.ico -------------------------------------------------------------------------------- /rubyweb/public/assets/follow_us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/follow_us.png -------------------------------------------------------------------------------- /rubyweb/public/assets/footer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/footer.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/footer.png -------------------------------------------------------------------------------- /rubyweb/public/assets/gurudigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/gurudigger.png -------------------------------------------------------------------------------- /rubyweb/public/assets/header_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/header_bg.png -------------------------------------------------------------------------------- /rubyweb/public/assets/icons/egg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/icons/egg.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/icons/gem.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/icons/gem.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/intridea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/intridea.png -------------------------------------------------------------------------------- /rubyweb/public/assets/jiantou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/jiantou.png -------------------------------------------------------------------------------- /rubyweb/public/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/logo.png -------------------------------------------------------------------------------- /rubyweb/public/assets/main_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/main_bg.png -------------------------------------------------------------------------------- /rubyweb/public/assets/memeber_icon_dorian.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/memeber_icon_dorian.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/memeber_icon_linjunhalida.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/memeber_icon_linjunhalida.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/memeber_icon_quake.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/memeber_icon_quake.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/p.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/p.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/portal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/portal.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/python_vs_ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/python_vs_ruby.png -------------------------------------------------------------------------------- /rubyweb/public/assets/pythons_food.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/pythons_food.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/pythons_team_title.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/pythons_team_title.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/r.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/r.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/rubys_food.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/rubys_food.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/rubys_team_title.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/rubys_team_title.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/rubyvspythonlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/rubyvspythonlogo.png -------------------------------------------------------------------------------- /rubyweb/public/assets/skeleton.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/skeleton.gif -------------------------------------------------------------------------------- /rubyweb/public/assets/snda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/snda.png -------------------------------------------------------------------------------- /rubyweb/public/assets/sohu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/sohu.png -------------------------------------------------------------------------------- /rubyweb/public/assets/sponsor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/sponsor.png -------------------------------------------------------------------------------- /rubyweb/public/assets/taobao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/taobao.png -------------------------------------------------------------------------------- /rubyweb/public/assets/time_adr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/time_adr.png -------------------------------------------------------------------------------- /rubyweb/public/assets/time_gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/time_gh.png -------------------------------------------------------------------------------- /rubyweb/public/assets/title_bar_bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/assets/title_bar_bg.gif -------------------------------------------------------------------------------- /rubyweb/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/public/favicon.ico -------------------------------------------------------------------------------- /rubyweb/script/cucumber: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first 4 | if vendored_cucumber_bin 5 | load File.expand_path(vendored_cucumber_bin) 6 | else 7 | require 'rubygems' unless ENV['NO_RUBYGEMS'] 8 | require 'cucumber' 9 | load Cucumber::BINARY 10 | end 11 | -------------------------------------------------------------------------------- /rubyweb/script/loadmap.rb: -------------------------------------------------------------------------------- 1 | files = `find ../srcs/map |grep yml`.split 2 | Map.delete_all 3 | for file in files 4 | data = YAML.load File.open(file).read() 5 | puts data['name'] 6 | Map.create! title: data['name'], width: data['width'], height: data['height'], data: JSON.dump(data) 7 | end 8 | 9 | -------------------------------------------------------------------------------- /rubyweb/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /rubyweb/spec/models/admin_user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AdminUser do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /rubyweb/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require File.expand_path("../../config/environment", __FILE__) 4 | require 'rspec/rails' 5 | 6 | # Requires supporting ruby files with custom matchers and macros, etc, 7 | # in spec/support/ and its subdirectories. 8 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 9 | 10 | RSpec.configure do |config| 11 | # == Mock Framework 12 | # 13 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 14 | # 15 | # config.mock_with :mocha 16 | # config.mock_with :flexmock 17 | # config.mock_with :rr 18 | config.mock_with :rspec 19 | 20 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 21 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 22 | 23 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 24 | # examples within a transaction, remove the following line or assign false 25 | # instead of true. 26 | config.use_transactional_fixtures = true 27 | end 28 | -------------------------------------------------------------------------------- /rubyweb/test/fixtures/replays.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | one: 4 | title: MyString 5 | round: 1 6 | json: MyText 7 | 8 | two: 9 | title: MyString 10 | round: 1 11 | json: MyText 12 | -------------------------------------------------------------------------------- /rubyweb/test/fixtures/rooms.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | one: 4 | name: MyString 5 | 6 | two: 7 | name: MyString 8 | -------------------------------------------------------------------------------- /rubyweb/test/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /rubyweb/test/functional/chat_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ChatControllerTest < ActionController::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /rubyweb/test/functional/replays_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ReplaysControllerTest < ActionController::TestCase 4 | setup do 5 | @replay = replays(:one) 6 | end 7 | 8 | test "should get index" do 9 | get :index 10 | assert_response :success 11 | assert_not_nil assigns(:replays) 12 | end 13 | 14 | test "should get new" do 15 | get :new 16 | assert_response :success 17 | end 18 | 19 | test "should create replay" do 20 | assert_difference('Replay.count') do 21 | post :create, :replay => @replay.attributes 22 | end 23 | 24 | assert_redirected_to replay_path(assigns(:replay)) 25 | end 26 | 27 | test "should show replay" do 28 | get :show, :id => @replay.to_param 29 | assert_response :success 30 | end 31 | 32 | test "should get edit" do 33 | get :edit, :id => @replay.to_param 34 | assert_response :success 35 | end 36 | 37 | test "should update replay" do 38 | put :update, :id => @replay.to_param, :replay => @replay.attributes 39 | assert_redirected_to replay_path(assigns(:replay)) 40 | end 41 | 42 | test "should destroy replay" do 43 | assert_difference('Replay.count', -1) do 44 | delete :destroy, :id => @replay.to_param 45 | end 46 | 47 | assert_redirected_to replays_path 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /rubyweb/test/functional/rooms_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class RoomsControllerTest < ActionController::TestCase 4 | setup do 5 | @room = rooms(:one) 6 | end 7 | 8 | test "should get index" do 9 | get :index 10 | assert_response :success 11 | assert_not_nil assigns(:rooms) 12 | end 13 | 14 | test "should get new" do 15 | get :new 16 | assert_response :success 17 | end 18 | 19 | test "should create room" do 20 | assert_difference('Room.count') do 21 | post :create, :room => @room.attributes 22 | end 23 | 24 | assert_redirected_to room_path(assigns(:room)) 25 | end 26 | 27 | test "should show room" do 28 | get :show, :id => @room.to_param 29 | assert_response :success 30 | end 31 | 32 | test "should get edit" do 33 | get :edit, :id => @room.to_param 34 | assert_response :success 35 | end 36 | 37 | test "should update room" do 38 | put :update, :id => @room.to_param, :room => @room.attributes 39 | assert_redirected_to room_path(assigns(:room)) 40 | end 41 | 42 | test "should destroy room" do 43 | assert_difference('Room.count', -1) do 44 | delete :destroy, :id => @room.to_param 45 | end 46 | 47 | assert_redirected_to rooms_path 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /rubyweb/test/performance/browsing_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'rails/performance_test_help' 3 | 4 | # Profiling results for each test method are written to tmp/performance. 5 | class BrowsingTest < ActionDispatch::PerformanceTest 6 | def test_homepage 7 | get '/' 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /rubyweb/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] = "test" 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. 7 | # 8 | # Note: You'll currently still have to declare fixtures explicitly in integration tests 9 | # -- they do not yet inherit this setting 10 | fixtures :all 11 | 12 | # Add more helper methods to be used by all tests here... 13 | end 14 | -------------------------------------------------------------------------------- /rubyweb/test/unit/helpers/chat_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ChatHelperTest < ActionView::TestCase 4 | end 5 | -------------------------------------------------------------------------------- /rubyweb/test/unit/helpers/replays_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ReplaysHelperTest < ActionView::TestCase 4 | end 5 | -------------------------------------------------------------------------------- /rubyweb/test/unit/helpers/room_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class RoomHelperTest < ActionView::TestCase 4 | end 5 | -------------------------------------------------------------------------------- /rubyweb/test/unit/helpers/rooms_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class RoomsHelperTest < ActionView::TestCase 4 | end 5 | -------------------------------------------------------------------------------- /rubyweb/test/unit/replay_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ReplayTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /rubyweb/test/unit/room_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class RoomTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /rubyweb/test/unit/user_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class UserTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /rubyweb/vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/rubyweb/vendor/plugins/.gitkeep -------------------------------------------------------------------------------- /srcs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/srcs/__init__.py -------------------------------------------------------------------------------- /srcs/db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: db 5 | """ 6 | import sqlite3 7 | db = sqlite3.connect('tmp/game.db') 8 | cursor = db.cursor() 9 | try: 10 | cursor.execute('create table scores (time, name)') 11 | cursor.execute('create index scores_time_index on scores(time)') 12 | except: 13 | pass 14 | 15 | 16 | -------------------------------------------------------------------------------- /srcs/dynamic_wall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: dynamic wall samples 5 | """ 6 | 7 | from snakec.game import * 8 | 9 | class FanWallGen(WallGen): 10 | freq = 2 # fan frequence 11 | flen = 4 # fan length 12 | 13 | # fan movement offest 14 | offset = [[(-1,0), (1,0), (0,-1), (0,1)], \ 15 | [(-1, -1), (-1,1), (1,-1), (1,1)]] 16 | 17 | def can(self, ctx): 18 | return ctx.round % self.freq == 0 19 | 20 | def gen(self, ctx): 21 | ct = [ctx.size[0]/2, ctx.size[1]/2] 22 | walls = [ct] 23 | ang = (ctx.round / self.freq) % 2 24 | 25 | def move(pt, of): 26 | return [pt[0]+of[0], pt[1]+of[1]] 27 | 28 | for of in self.offset[ang]: 29 | pt = ct[:] 30 | for i in range(self.flen): 31 | pt = move(pt, of) 32 | walls.append(pt[:]) 33 | 34 | return walls 35 | -------------------------------------------------------------------------------- /srcs/game.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: game core 5 | """ 6 | 7 | class BeanGen: 8 | def can(self, ctx): 9 | pass 10 | def gen(self, ctx): 11 | pass 12 | 13 | class WallGen: 14 | def can(self, ctx): 15 | pass 16 | def gen(self, ctx): 17 | pass 18 | -------------------------------------------------------------------------------- /srcs/game_controller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: game_controller 5 | 游戏控制器.. 提供api级别的接口, 方便服务器调用game 6 | 7 | """ 8 | from snake_game import * 9 | 10 | class RoomController(): 11 | def __init__(self, games): 12 | self.games = games 13 | self.controllers = [Controller(g) 14 | for g in self.games] 15 | def op(self, data): 16 | """ 17 | 分配room 18 | """ 19 | # 检查room 20 | if not data.has_key('room'): 21 | return dict(status = "data has no room param.") 22 | 23 | try: 24 | room = int(data['room']) 25 | except Exception as e: 26 | return dict(status="room data (%s) error: %s" % (data['room'], str(e))) 27 | 28 | if not 0 <= room < len(self.games): 29 | return dict(status='room number error: %d'%room) 30 | # 分配处理 31 | return self.controllers[room].op(data) 32 | 33 | class Controller(): 34 | def __init__(self, game): 35 | self.game = game 36 | 37 | def op(self, data): 38 | """ 39 | 统一的op接口 40 | """ 41 | op = data['op'] 42 | if op == 'add': 43 | return self.game.add_snake(type=data['type'], name=data['name']) 44 | 45 | elif op in ('turn', 'sprint'): 46 | if not data.has_key(round): data['round'] = -1 47 | return dict(status=self.game.set_snake_op(data['id'], int(data['round']), data)) 48 | 49 | elif op == 'map': 50 | return self.game.get_map() 51 | 52 | elif op == 'setmap': 53 | return dict(status=self.game.user_set_map(data['data'])) 54 | 55 | elif op == 'info': 56 | return self.game.get_info() 57 | 58 | elif op == 'history': 59 | return self.history() 60 | 61 | elif op == 'scores': 62 | return self.game.scores() 63 | 64 | else: 65 | return dict(status='op error: %s' % op) 66 | 67 | def test(): 68 | """ 69 | # 初始化 70 | >>> game = Game() 71 | >>> c = Controller(game) 72 | 73 | # 添加新的蛇 74 | >>> result = c.add(name='foo',type='python') 75 | >>> result = c.add(name='bar',type='python') 76 | >>> id = result['id'] 77 | >>> result['seq'] 78 | 1 79 | 80 | # 控制蛇的方向 81 | >>> result = c.turn(id=id, d=0, round=-1) 82 | 83 | # 获取地图信息 84 | >>> m = c.map() 85 | 86 | # 获取实时信息 87 | >>> info = c.info() 88 | """ 89 | import doctest 90 | doctest.testmod() 91 | 92 | if __name__=="__main__": 93 | test() 94 | -------------------------------------------------------------------------------- /srcs/lib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: lib 5 | """ 6 | import sys, os 7 | import time, logging, json, random, uuid, datetime 8 | from datetime import date 9 | 10 | logging.basicConfig(level=logging.DEBUG, 11 | format="%(asctime)s - %(levelname)s - %(message)s") 12 | 13 | 14 | class Clock(): 15 | """一个分时器,限制刷新率 16 | >>> c = Clock(20) # fps 17 | >>> c.tick(block=False) 18 | """ 19 | def __init__(self, fps): 20 | self.set_fps(fps) 21 | 22 | def set_fps(self, fps): 23 | self.fps = fps 24 | self.interval = 1.0/float(fps) 25 | self.pre = time.time() 26 | 27 | def tick(self, block=True): 28 | """ 29 | 检查是否到了时间 30 | """ 31 | mid = time.time() - self.pre 32 | if mid < self.interval: 33 | if block: 34 | time.sleep(self.interval - mid) 35 | else: 36 | return 37 | self.pre = time.time() 38 | return True 39 | -------------------------------------------------------------------------------- /srcs/map/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halida/snake-challenge/0368ca5f1db043979bd8b58165745c121f6117b3/srcs/map/__init__.py -------------------------------------------------------------------------------- /srcs/map/campain.yml: -------------------------------------------------------------------------------- 1 | name: campain 2 | author: halida 3 | version: 1.0 4 | 5 | width: 50 6 | height: 25 7 | 8 | snake_init: 2 9 | snake_max: 15 10 | 11 | food_max: 1 12 | 13 | map: | 14 | .................................................. 15 | .................................................. 16 | .................................................. 17 | .................................................. 18 | .................................................. 19 | .....WAWWWWWWWWWCWWWWWWWWWWWWWWWWCWWWWWWWWWAW..... 20 | .....W......................................W..... 21 | .....W......................................W..... 22 | .....W......................................W..... 23 | .....W......................................W..... 24 | .....W......................................W..... 25 | .....W......................................W..... 26 | .....W......................................W..... 27 | .....W......................................W..... 28 | .....W......................................W..... 29 | .....W......................................W..... 30 | .....W......................................W..... 31 | .....W......................................W..... 32 | .....W......................................W..... 33 | .....WBWWWWWWWWWDWWWWWWWWWWWWWWWWDWWWWWWWWWBW..... 34 | .................................................. 35 | .................................................. 36 | .................................................. 37 | .................................................. 38 | .................................................. 39 | -------------------------------------------------------------------------------- /srcs/map/castle.yml: -------------------------------------------------------------------------------- 1 | name: castle # map name 2 | author: Ray Ling # map author 3 | version: 1.0 # map version 4 | 5 | width: 50 6 | height: 25 7 | 8 | snake_init: 2 # initial snake length 9 | snake_max: 5 10 | 11 | food_max: 1 12 | 13 | map: | 14 | .................................................. 15 | ........................C.......................S. 16 | ..WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.. 17 | ..W............................................W.. 18 | ..W.......A............................B.......W.. 19 | ..W............................................W.. 20 | ..W...WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW...W.. 21 | ..W...W....................................W...W.. 22 | ..W...W....................................W...W.. 23 | ..W...W....................................W...W.. 24 | ..W...W....W...WWWWW...WWWWW...WWWWW.......W...W.. 25 | ..W...W....W...W...W...W...W...W...W.......W...W.. 26 | ......W....W...W...W...W.C.W...W...W...........W.. 27 | ..W...W....W...W...W...W...W...W...W.......W...W.. 28 | ..W...W....WWWWW...WWWWW...WWWWW...WWWW....W...W.. 29 | ..W...W....................................W...W.. 30 | ..W...W...B............................A...W...W.. 31 | ..W...W....................................W...W.. 32 | ..W...WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW...W.. 33 | ..W............................................W.. 34 | ..W............................................W.. 35 | ..W............................................W.. 36 | ..WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.. 37 | ................................................S. 38 | .................................................. 39 | -------------------------------------------------------------------------------- /srcs/map/empty.yml: -------------------------------------------------------------------------------- 1 | name: empty 2 | author: halida 3 | version: 1.0 4 | 5 | width: 50 6 | height: 25 7 | 8 | snake_init: 5 9 | food_max: 1 10 | 11 | map: | 12 | .................................................. 13 | .................................................. 14 | .................................................. 15 | .................................................. 16 | .................................................. 17 | .................................................. 18 | .................................................. 19 | .................................................. 20 | .................................................. 21 | .................................................. 22 | .................................................. 23 | .................................................. 24 | .................................................. 25 | .................................................. 26 | .................................................. 27 | .................................................. 28 | .................................................. 29 | .................................................. 30 | .................................................. 31 | .................................................. 32 | .................................................. 33 | .................................................. 34 | .................................................. 35 | .................................................. 36 | .................................................. 37 | -------------------------------------------------------------------------------- /srcs/map/flat.yml: -------------------------------------------------------------------------------- 1 | name: flat 2 | author: linjunhalida 3 | version: 1.0 4 | height: 60 5 | width: 100 6 | round: 10 7 | 8 | snake_init: 10 9 | snake_max: 30 10 | 11 | food_max: 3 12 | map: | 13 | .................................................................................................... 14 | .................................................................................................... 15 | .................................................................................................... 16 | .................................................................................................... 17 | .................................................................................................... 18 | .................................................................................................... 19 | .................................................................................................... 20 | .................................................................................................... 21 | .................................................................................................... 22 | ......................B............................C................................................ 23 | .................................................................................................... 24 | .................................................................................................... 25 | .................................................................................................... 26 | .................................................................................................... 27 | .................................................................................................... 28 | .................................................................................................... 29 | .................................................................................................... 30 | .................................................................................................... 31 | .................................................................................................... 32 | .................................................................................................... 33 | .................................................................................................... 34 | .................................................................................................... 35 | .................................................................................................... 36 | .....................................................................D.............................. 37 | .................................................................................................... 38 | .........A.......................................................................................... 39 | .................................................................................................... 40 | ..F.....................................E..F........................................................ 41 | .................................................................................................... 42 | .................................................................................................... 43 | .................................................................................................... 44 | .................................................................................................... 45 | .................................................................................................... 46 | .................................................................................................... 47 | .................................................................................................... 48 | .................................................................................................... 49 | .................................................................................................... 50 | .................D.................................................................................. 51 | .................................................................................................... 52 | ......................................................................A............................. 53 | .................................................................................................... 54 | .................................................................................................... 55 | .................................................................................................... 56 | .................................................................................................... 57 | .................................................................................................... 58 | .................................................................................................... 59 | .................................................................................................... 60 | ............................C.........................B............................................. 61 | .................................................................................................... 62 | .................................................................................................... 63 | .................................................................................................... 64 | .................................................................................................... 65 | .................................................................................................... 66 | .................................................................................................... 67 | .................................................................................................... 68 | .................................................................................................... 69 | ........................................E........................................................... 70 | .................................................................................................... 71 | .................................................................................................... 72 | .................................................................................................... 73 | -------------------------------------------------------------------------------- /srcs/map/image2map.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: convert image to snake challenge map, require PIL 5 | """ 6 | 7 | import sys 8 | import Image 9 | 10 | def color2map(color): 11 | if color[0] < 128 and color[1] < 128 and color[2] < 128: 12 | return 'W' 13 | elif color[0] > 128 and color[1] < 128 and color[2] < 128: 14 | return 'X' 15 | elif color[0] < 128 and color[1] < 128 and color[2] > 128: 16 | return 'S' 17 | else: 18 | return '.' 19 | 20 | def image2map(file, size=None): 21 | map = [] 22 | img = Image.open(file, 'r').convert("RGB") 23 | 24 | if size is not None: 25 | img = img.resize(size) 26 | 27 | data = img.load() 28 | for i in range(img.size[1]): 29 | mapscan = [] 30 | for j in range(img.size[0]): 31 | color = data[j,i] 32 | mapscan.append(color2map(color)) 33 | map.append(mapscan) 34 | return map 35 | 36 | def mapconfigs(): 37 | cfgs = ['author','version','name','snakelength','size','food','maxfoodvalue'] 38 | meta = {} 39 | for cfg in cfgs: 40 | sys.stdout.write(cfg + ": ") 41 | input = sys.stdin.readline() 42 | meta[cfg] = input 43 | return meta 44 | 45 | def writetofile(meta, map, file): 46 | with open(file, 'w') as f: 47 | for mk,mv in meta.items(): 48 | f.write(mk+": "+mv) 49 | f.write("map:\n") 50 | for y in map: 51 | for x in y: 52 | f.write(x) 53 | f.write("\n") 54 | 55 | def tosize(value): 56 | d = value.strip().split('x') 57 | return (int(d[0]), int(d[1])) 58 | 59 | if __name__ == '__main__': 60 | meta = mapconfigs() 61 | try: 62 | size = tosize(meta['size']) 63 | except Exception: 64 | size = None 65 | print size 66 | map = image2map(sys.argv[1], size) 67 | 68 | writetofile(meta, map, sys.argv[2]) -------------------------------------------------------------------------------- /srcs/map/lost_temple.yml: -------------------------------------------------------------------------------- 1 | author: Ray Ling 2 | version: 1.0 3 | name: Lost Temple 4 | width: 50 5 | height: 25 6 | snake_max: 4 7 | map: | 8 | .WWW.WW...........WWWW...WW..........X...WWWWWW..W 9 | ..X....W..W......W......XX...WW................... 10 | W........WW.......W............W.............WWW.. 11 | .W......W........WW......S................WWW...WW 12 | .W.......WW.......WW.....................W.......W 13 | ........W........W...........W..........W.......X. 14 | ..WWW.WW..........WWWW.......W........WW......S..X 15 | .W.......WW.......WWW.W.....W........W............ 16 | W......................WW.WWWW..........W........W 17 | ....W...................WWW............W.......... 18 | .....WW................................WW.....WWW. 19 | .W.....W..................W...................W..W 20 | ........W................W.W...............WW..... 21 | W.......WW................W....................... 22 | ..........W.........W...............WW............ 23 | .X.......WWW.......W.WW...............W.WW........ 24 | W.S.........W.....WW...WW.W...............W...X... 25 | .X.......WW......W.......W.WW............WW...WWW. 26 | ........W.......WW..........W.............WWWW...W 27 | W......WW........WW.........WW..........WW........ 28 | .WW.WWW.........W.WW..........WWW.......W....X.... 29 | ...W...............W..S.......W..........W........ 30 | .................WW....................WW.....WW.. 31 | ..................WW....X...............W....W..W. 32 | ..................WWWW..x.WWWW.W.........W........ 33 | -------------------------------------------------------------------------------- /srcs/map/map.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: map 5 | """ 6 | import random, yaml, json 7 | from game import * 8 | 9 | class Map: 10 | walltoken = ['.','W','S'] 11 | # portal tokens 12 | portal_token = ['A','B','C','D','E','F','G','H','I','J'] 13 | 14 | def __init__(self): 15 | self.beangen = MapBeanGen(self) 16 | self.wallgen = MapWallGen(self) 17 | # default meta 18 | self.meta = dict( 19 | name = 'unknown', 20 | author = 'none', 21 | version = 1.0, 22 | round = 3000, 23 | 24 | snake_init = 5, 25 | snake_max = 30, 26 | food_max = 3, 27 | ) 28 | 29 | @staticmethod 30 | def loadfile(filename): 31 | data = yaml.load(open(filename).read()) 32 | return Map.loaddata(data) 33 | 34 | @staticmethod 35 | def loaddata(data): 36 | map = Map() 37 | map.load(data) 38 | return map 39 | 40 | def __getattr__(self, name): 41 | return self.meta[name] 42 | 43 | def load(self, data): 44 | for key in data: 45 | self.meta[key] = data[key] 46 | 47 | self.beangen.maxbean = self.meta['food_max'] 48 | 49 | self.walls = [] 50 | self.snakes = [] 51 | self.portals = [] 52 | 53 | # extract map data 54 | data = self.meta['map'].strip().split('\n') 55 | 56 | for y in range(self.meta['height']): 57 | for x in range(self.meta['width']): 58 | v = data[y][x] 59 | if v == 'W': 60 | self.walls.append([x,y]) 61 | elif v == 'S': 62 | self.snakes.append([x,y]) 63 | 64 | elif v in self.portal_token: 65 | idx = self.portal_token.index(v) 66 | shortage = (idx+1)*2 - len(self.portals) 67 | if shortage > 0: 68 | self.portals.extend([None] * shortage) 69 | if self.portals[2*idx]: 70 | self.portals[2*idx+1] = [x,y] 71 | else: 72 | self.portals[2*idx] = [x,y] 73 | 74 | class MapWallGen: 75 | def __init__(self, map): 76 | self.map = map 77 | 78 | def can(self, ctx): 79 | return ctx.round == 0 and ctx.status == 'initial' 80 | def gen(self, ctx): 81 | return self.map.walls 82 | 83 | class MapBeanGen(BeanGen): 84 | def __init__(self, map): 85 | self.map = map 86 | self.maxbean = 1 87 | 88 | def can(self, ctx): 89 | return ctx.status == 'running' and (self.canEgg(ctx) or self.canGem(ctx)) 90 | #return ctx.round % 4 == 0 and ctx.status == 'running' 91 | 92 | def gen(self, ctx): 93 | gems,eggs = [],[] 94 | needgem, needegg = self.maxbean - len(ctx.gems), self.maxbean - len(ctx.eggs) 95 | 96 | while needgem>0: 97 | gem = self.randomGen(ctx, gems) 98 | gems.append(gem) 99 | needgem -= 1 100 | 101 | while needegg>0: 102 | egg = self.randomGen(ctx, gems + eggs) 103 | eggs.append(egg) 104 | needegg -= 1 105 | 106 | return [eggs,gems] 107 | 108 | def canEgg(self, ctx): 109 | return len(ctx.eggs)=0 and pt[0]=0 and pt[1] self.straight: 47 | random.shuffle(self.idxes) 48 | for i in self.idxes: 49 | dt = self.offset[i] 50 | dp = [pt[0]+dt[0], pt[1]+dt[1]] 51 | if bound(dp): 52 | for wp in walls: 53 | if dp == wp: dp = None; break 54 | if dp is not None: 55 | return dp 56 | return None 57 | 58 | # generate num points to construct the walls 59 | while num>0: 60 | # start point of a wall 61 | pt = [random.randint(0, ctx.w-1), random.randint(0, ctx.h-1)] 62 | if pt in walls: continue 63 | walls += [pt] 64 | num -= 1 65 | 66 | # continue grow the wall 67 | while random.random()>self.discrete and num>0: 68 | np = next(pt) 69 | if np == None: break 70 | walls += [np] 71 | pt = np 72 | num -= 1 73 | 74 | return walls 75 | 76 | def breakWall(self, ctx, walls): 77 | """ 78 | break the closed area: 79 | 1. calculate union set of the area 80 | 2. break the wall between different area 81 | """ 82 | set = [ [j*ctx.h+i for i in range(ctx.h)] for j in range(ctx.w)] 83 | 84 | for pt in walls: 85 | set[pt[0]][pt[1]] = -1 86 | 87 | move = lambda pt,dt=(0,0): [(pt[0]+dt[0]+ctx.w)%ctx.w, (pt[1]+dt[1]+ctx.h)%ctx.h] 88 | inset = lambda pt: set[pt[0]][pt[1]] 89 | setv = lambda pt,v: set[pt[0]].__setitem__(pt[1], v) 90 | setvp = lambda pt,vp: set[pt[0]].__setitem__(pt[1], set[vp[0]][vp[1]]) 91 | idxtopt = lambda idx: [idx/ctx.h, idx%ctx.h] 92 | parent = lambda pt: idxtopt(inset(pt)) 93 | 94 | def root(pt): 95 | if inset(pt) < 0: return -1 96 | t = pt 97 | while parent(t) != t: 98 | t = parent(t) 99 | tp = pt 100 | while parent(tp) != t: 101 | pt, tp = tp, parent(tp) 102 | setvp(pt, t) 103 | return inset(t) 104 | 105 | def union(pt1, pt2): 106 | rt1, rt2 = root(pt1), root(pt2) 107 | if rt1 < rt2: 108 | setv(idxtopt(rt2), rt1) 109 | elif rt2 < rt1: 110 | setv(idxtopt(rt1), rt2) 111 | 112 | # union the connected points 113 | def connect(pt): 114 | if root(pt) < 0 : return 115 | 116 | pt1 = move(pt, (-1,0)) 117 | pt2 = move(pt, (0,-1)) 118 | if root(pt1)>=0: 119 | union(pt, pt1) 120 | if root(pt2)>=0: 121 | union(pt, pt2) 122 | 123 | # build connection relationship 124 | for y in range(ctx.h): 125 | for x in range(ctx.w): 126 | connect((x,y)) 127 | 128 | rtcnt = {} 129 | for y in range(ctx.h): 130 | for x in range(ctx.w): 131 | rt = root((x,y)) 132 | if rt < 0 : continue 133 | if rt in rtcnt.keys(): 134 | rtcnt[rt] += 1 135 | else: 136 | rtcnt[rt] = 1 137 | 138 | maxrt, maxrtcnt = 0, 0 139 | for k,v in rtcnt.items(): 140 | if v > maxrtcnt: maxrt, maxrtcnt = k, v 141 | 142 | # break the closed area by removing blocking wall 143 | while len(rtcnt)>1: 144 | for pt in walls: 145 | for dt in self.offset: 146 | tp = move(pt, dt) 147 | rt = root(tp) 148 | if rt>=0 and rt!=maxrt: 149 | walls.remove(pt) 150 | setv(pt, rt) 151 | break 152 | if root(pt)>=0: 153 | for dt in self.offset: 154 | tp = move(pt, dt) 155 | root1, root2 = root(pt), root(tp) 156 | if root1>=0 and root2>=0 and root1!=root2: 157 | union(tp, pt) 158 | del rtcnt[max(root1,root2)] 159 | return walls 160 | 161 | if __name__ == '__main__': 162 | import doctest 163 | doctest.testmod() 164 | -------------------------------------------------------------------------------- /srcs/simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: simple strategy for game 5 | """ 6 | 7 | from lib import * 8 | from game import * 9 | 10 | BEAN_TIME = 6 11 | 12 | def simpleBeanGen(ctx): 13 | """ 14 | 随机获取一个空的位置 15 | 可能是性能陷阱? 16 | """ 17 | while True: 18 | p = [random.randint(0, ctx.w-1), 19 | random.randint(0, ctx.h-1)] 20 | # 不要和其他东西碰撞 21 | if ctx.check_hit(p): 22 | continue 23 | return p 24 | 25 | class SimpleBeanGen(BeanGen): 26 | def can(self, ctx): 27 | return ctx.enable_bean and ctx.round % BEAN_TIME == 0 28 | def gen(self, ctx): 29 | ret = [[],[]] 30 | if self.canEgg(ctx): 31 | ret[0].append(simpleBeanGen(ctx)) 32 | if self.canGem(ctx): 33 | ret[1].append(simpleBeanGen(ctx)) 34 | if ret[0] == ret[1]: 35 | ret[random.randint(0,1)] = [] 36 | return ret 37 | 38 | def canEgg(self, ctx): 39 | return len(ctx.eggs)<10 40 | def canGem(self, ctx): 41 | return len(ctx.gems)<10 42 | 43 | class SimpleWallGen(WallGen): 44 | def can(self, ctx): 45 | # in simple mode, only generate wall before game start 46 | return ctx.round == 0 47 | def gen(self, ctx): 48 | # 因为js没有(), 只好用[] 49 | return [[10, i] for i in range(5, 35)] 50 | 51 | -------------------------------------------------------------------------------- /srcs/snake_profile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: snake_profile 5 | 用来测试profile功能 6 | 7 | profile前数据: 8 | ncalls tottime percall cumtime percall filename:lineno(function) 9 | 1000000 9.065 0.000 9.065 0.000 snake_game.py:290(check_hit) 10 | 500000 2.525 0.000 15.162 0.000 snake_game.py:225(step) 11 | 1000000 1.897 0.000 12.293 0.000 snake_game.py:66(move) 12 | 1000000 0.834 0.000 0.834 0.000 snake_game.py:58(get_next) 13 | """ 14 | from snake_game import * 15 | 16 | def main(): 17 | game = Game((40,20), 18 | enable_bean=False, 19 | enable_wall=False, 20 | enable_no_resp_die=False) 21 | status, seq, id = game.add_snake(PYTHON, DOWN, (3, 4), 2) 22 | status, seq, id = game.add_snake(PYTHON, DOWN, (2, 2), 4) 23 | game.walls = [[i, j] for i in range(5, 19) for j in range(12)] 24 | for i in range(500): 25 | game.step() 26 | 27 | 28 | if __name__=="__main__": 29 | for i in range(1000): 30 | main() 31 | -------------------------------------------------------------------------------- /srcs/web_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: server 5 | """ 6 | from lib import * 7 | 8 | import zmq 9 | from zmq.eventloop import ioloop, zmqstream 10 | # hack 11 | ioloop.install() 12 | 13 | import tornado 14 | import tornado.web, tornado.websocket 15 | 16 | 17 | context = zmq.Context() 18 | 19 | # 用来接受info更新 20 | suber = context.socket(zmq.SUB) 21 | suber.connect('ipc:///tmp/game_puber.ipc') 22 | # self.suber.setsockopt(zmq.SUBSCRIBE, 'room:%d '%room) 23 | suber.setsockopt(zmq.SUBSCRIBE, '') 24 | 25 | 26 | # 用来与服务器交互 27 | oper = context.socket(zmq.REQ) 28 | oper.connect('ipc:///tmp/game_oper.ipc') 29 | 30 | 31 | class ChatRoomWebSocket(tornado.websocket.WebSocketHandler): 32 | connects = [] 33 | chats = {} 34 | SAVED_CHATS = 30 35 | def open(self): 36 | self.name = '???' 37 | self.room = "root" 38 | # 显示现在已经在的人 39 | if len(self.connects) > 0: 40 | current_ins = ', '.join([u"%s in : %s" % (c.name, c.room) 41 | for c in self.connects]) 42 | else: 43 | current_ins = 'none' 44 | self.write_message('current in: \n' + current_ins) 45 | 46 | self.connects.append(self) 47 | 48 | def on_message(self, message): 49 | data = json.loads(message) 50 | if data.has_key('name'): 51 | self.name = data['name'] 52 | self.room = data['room'] 53 | self.broadcast(self.room, '%s enters the room: %s' % (self.name, self.room)) 54 | # write some history chats 55 | for chat in self.chats.get(self.room, []): 56 | self.write_message(chat) 57 | return 58 | else: 59 | self.broadcast(self.room, '%s says: %s' % (self.name, data['msg']) ) 60 | 61 | def broadcast(self, room, msg): 62 | # save chat 63 | if not self.chats.has_key(room): 64 | self.chats[room] = [] 65 | room_chats = self.chats[room] 66 | room_chats.append(msg) 67 | if len(room_chats) > self.SAVED_CHATS: 68 | self.chats[room] = room_chats[-self.SAVED_CHATS:] 69 | 70 | for c in self.connects: 71 | if c.room != room: 72 | continue 73 | try: 74 | c.write_message(msg) 75 | except Exception as e: 76 | logging.debug(str(e)) 77 | try: 78 | self.connects.remove(c) 79 | except: 80 | pass 81 | 82 | def on_close(self): 83 | self.connects.remove(self) 84 | self.broadcast(self.room, self.name + ' leaves.') 85 | 86 | class Cmd(tornado.web.RequestHandler): 87 | def post(self): 88 | data = self.request.arguments 89 | # warp list 90 | for key in data: 91 | data[key] = data[key][0] 92 | data = json.dumps(data) 93 | oper.send_unicode(data) 94 | result = oper.recv() 95 | self.set_header("Content-Type", "application/json") 96 | self.write(result) 97 | 98 | class InfoWebSocket(tornado.websocket.WebSocketHandler): 99 | 100 | connects = [] 101 | room = -1 102 | 103 | @classmethod 104 | def check_info(cls, data): 105 | # 拆分掉room头信息 106 | data = data[0] 107 | i = data.index(' ') 108 | room = int(data[:i].split(':')[1]) 109 | # 发送给所有注册到这个room的连接 110 | cls.send_info(room, data[i:]) 111 | 112 | @classmethod 113 | def send_info(cls, room, info): 114 | for c in cls.connects[:]: 115 | if c.room == room: 116 | try: 117 | c.write_message(info) 118 | except: 119 | try: 120 | cls.remove(c) 121 | except: 122 | pass 123 | 124 | def open(self): 125 | self.connects.append(self) 126 | 127 | def on_message(self, message): 128 | data = json.loads(message) 129 | if data.get('op') == 'setroom': 130 | self.room = int(data['room']) 131 | else: 132 | self.process_cmd(message) 133 | 134 | def process_cmd(self, message): 135 | # logging.debug(message) 136 | oper.send_unicode(message) 137 | result = oper.recv() 138 | self.write_message(result) 139 | 140 | def on_close(self): 141 | try: 142 | self.connects.remove(self) 143 | except: 144 | pass 145 | 146 | stream = zmqstream.ZMQStream(suber) 147 | stream.on_recv(InfoWebSocket.check_info) 148 | 149 | settings = { 150 | "static_path": os.path.join(os.path.dirname(__file__), "static"), 151 | "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=", 152 | # "login_url": "/login", 153 | # "xsrf_cookies": True, 154 | 'debug' : True, 155 | # 'gzip' : True, 156 | } 157 | 158 | application = tornado.web.Application([ 159 | (r"/info", InfoWebSocket), 160 | (r"/chatroom", ChatRoomWebSocket), 161 | (r"/cmd", Cmd), 162 | ], **settings) 163 | 164 | def main(): 165 | application.listen(9999) 166 | try: 167 | ioloop.IOLoop.instance().start() 168 | except KeyboardInterrupt: 169 | print "bye!" 170 | 171 | if __name__ == "__main__": 172 | main() 173 | -------------------------------------------------------------------------------- /srcs/zmq_game_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: server 5 | """ 6 | from lib import * 7 | import zmq, json, random 8 | 9 | import game_controller 10 | from snake_game import * 11 | 12 | context = zmq.Context() 13 | 14 | ROOMS = 10 15 | 16 | class Server(): 17 | """ 18 | 游戏的服务器逻辑 19 | 服务器提供2个队列: 20 | - game_puber队列(PUB), 当地图更新的时候, 发送info信息 21 | - game_oper队列(REP), 可以进行add/turn/map命令 22 | """ 23 | def on_logic(self, g, ok): 24 | """判断定期更新的时间是否到了""" 25 | min_waits = 0.2 26 | max_waits = self.max_waits 27 | if not hasattr(g, 'pre'): 28 | g.pre = time.time() 29 | 30 | # 时间段不能小于min_waits, 不能大于max_waits 31 | now = time.time() 32 | if (now > g.pre + max_waits 33 | or (ok and now > g.pre + min_waits) 34 | ): 35 | g.pre = now 36 | return True 37 | 38 | def pub_info(self, i): 39 | info = self.controller.op(dict(room=i, op='info')) 40 | info['op'] = 'info' 41 | self.puber.send("room:%d "%i + json.dumps(info)) 42 | 43 | 44 | def run(self, max_waits=10.0, enable_no_resp_die=True): 45 | self.max_waits = max_waits 46 | self.games = [Game(enable_no_resp_die=enable_no_resp_die) 47 | for i in range(ROOMS)] 48 | self.controller = game_controller.RoomController(self.games) 49 | 50 | # 用来发布信息更新 51 | puber = context.socket(zmq.PUB) 52 | puber.bind('ipc:///tmp/game_puber.ipc') 53 | self.puber = puber 54 | 55 | # 用来处理 56 | oper = context.socket(zmq.REP) 57 | oper.bind('ipc:///tmp/game_oper.ipc') 58 | 59 | while True: 60 | time.sleep(0.001) 61 | 62 | # 处理op 63 | while True: 64 | try: 65 | rc = oper.recv(zmq.NOBLOCK) 66 | # 处理完所有命令就跳出命令处理逻辑 67 | except zmq.ZMQError: 68 | break 69 | 70 | try: 71 | rc = json.loads(rc) 72 | result = self.controller.op(rc) 73 | result['op'] = rc['op'] 74 | #如果有新的蛇加进来, 也pub一下 75 | if rc['op'] == 'add' and result.has_key('seq'): 76 | self.pub_info(int(rc['room'])) 77 | #如果地图变动也pub 78 | if rc['op'] == 'setmap' and result['status'] == 'ok': 79 | self.pub_info(int(rc['room'])) 80 | # logging.debug('process op %s ', rc) 81 | 82 | # 为了防止错误命令搞挂服务器, 加上错误处理 83 | except Exception as e: 84 | error_msg = str(e) 85 | result = dict(status=error_msg, data=rc) 86 | logging.debug(error_msg) 87 | 88 | oper.send(json.dumps(result)) 89 | 90 | # 处理所有room的游戏id 91 | for i, g in enumerate(self.games): 92 | 93 | if g.status == RUNNING: 94 | # 当游戏进行时, 需要等待所有活着的玩家操作完毕 95 | ok = g.alloped() 96 | else: 97 | # 其他状态的话, 最小时间的方式定时更新 98 | ok = True 99 | 100 | if not self.on_logic(g, ok): 101 | continue 102 | 103 | # 游戏处理 104 | updated = g.step() 105 | 106 | # 发送更新信息 107 | if updated: 108 | logging.debug("room %d updated: %s" % (i, g.status)) 109 | self.pub_info(i) 110 | 111 | usage = """\ 112 | $ zmq_game_server.py [type] 113 | type == web: 114 | server for snakechallenge.org, when game over, server start new round. 115 | because it is slow on internet, set wait time to 5.0 seconds 116 | type == local: 117 | local max_waits set to 1.0s 118 | """ 119 | 120 | def main(): 121 | import sys 122 | if len(sys.argv) < 2: print usage 123 | cmd = sys.argv[1] 124 | if cmd == 'web': 125 | s = Server() 126 | s.run(max_waits=5.0, enable_no_resp_die=True) 127 | elif cmd == 'local': 128 | s = Server() 129 | s.run(max_waits=1.0, enable_no_resp_die=True) 130 | else: 131 | print usage 132 | 133 | if __name__=="__main__": 134 | main() 135 | -------------------------------------------------------------------------------- /srcs/zmq_logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: log_server 5 | 记录以及回放服务器 6 | """ 7 | from ailib import * 8 | 9 | 10 | def logger(controller, filename="game.log", quit_on_finish=True): 11 | """ 12 | 用来记录log 13 | """ 14 | c = controller 15 | # log file 16 | f = open(filename, 'w+') 17 | 18 | def save_map(): 19 | m = c.map() 20 | logging.debug(m) 21 | f.write('map: ') 22 | f.write(json.dumps(m)) 23 | f.write('\n') 24 | return m 25 | 26 | def save_info(): 27 | info = c.info() 28 | logging.debug(info) 29 | f.write('info: ') 30 | f.write(json.dumps(info)) 31 | f.write('\n') 32 | return info 33 | 34 | clock = Clock(30) 35 | info = None 36 | status = None 37 | round = -1 38 | 39 | while True: 40 | try: 41 | clock.tick() 42 | # get map on init 43 | if not status: 44 | save_map() 45 | 46 | # loop get info.. 47 | info = c.info() 48 | if info['round'] == round: 49 | time.sleep(0.3) 50 | continue 51 | round = info['round'] 52 | logging.debug(info) 53 | 54 | # get map again when start new game 55 | if status == 'finished' and info['status'] == 'waitforplayer': 56 | save_map() 57 | 58 | # save info 59 | f.write('info: ') 60 | f.write(json.dumps(info)) 61 | f.write('\n') 62 | 63 | # quit on game finished 64 | if quit_on_finish and info['status'] == 'finished': 65 | f.close() 66 | return 67 | status = info['status'] 68 | except KeyboardInterrupt: 69 | f.close() 70 | return 71 | 72 | usage = """\ 73 | $zmq_logger.py [connect type] [room number] [filename] 74 | connect type is in [web, zero] 75 | """ 76 | 77 | def main(): 78 | if len(sys.argv) < 3: print usage 79 | controller = sys.argv[1] 80 | try: 81 | room = int(sys.argv[2]) 82 | except: 83 | print usage 84 | 85 | if controller == 'web': 86 | Controller = WebController 87 | elif controller == 'zero': 88 | Controller = ZeroController 89 | else: 90 | print usage 91 | 92 | filename=sys.argv[3] 93 | 94 | logger(Controller(room), 95 | filename=filename, 96 | quit_on_finish=False) 97 | 98 | if __name__=="__main__": 99 | main() 100 | -------------------------------------------------------------------------------- /srcs/zmq_pygame_show.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: zmq_pygame_show 5 | """ 6 | from lib import * 7 | from pygame_show import Shower 8 | 9 | import zmq 10 | context = zmq.Context() 11 | 12 | usage = """ 13 | python zmq_pygame_show.py [room number] 14 | """ 15 | 16 | def show(room): 17 | """ 18 | 用来显示现在游戏状况的client 19 | """ 20 | # 用来接受info更新 21 | suber = context.socket(zmq.SUB) 22 | suber.connect('ipc:///tmp/game_puber.ipc') 23 | suber.setsockopt(zmq.SUBSCRIBE, "room:%d " % room) 24 | # 用来与服务器交互 25 | oper = context.socket(zmq.REQ) 26 | oper.connect('ipc:///tmp/game_oper.ipc') 27 | # 获取map 28 | def get_map(): 29 | req = dict(op='map', room=room) 30 | oper.send(json.dumps(req)) 31 | return json.loads(oper.recv()) 32 | m = get_map() 33 | 34 | clock = Clock(30) 35 | shower = Shower(m) 36 | info = None 37 | 38 | while True: 39 | clock.tick() 40 | # 等待地图更新... 41 | try: 42 | info = suber.recv(zmq.NOBLOCK) 43 | info = info[info.index(' ') : ] 44 | info = json.loads(info) 45 | # 如果游戏结束了, 获取map 46 | if info['status'] == 'waitforplayer': 47 | shower.set_map(get_map()) 48 | 49 | except zmq.ZMQError as e: 50 | pass 51 | 52 | if info: 53 | shower.flip(info) 54 | 55 | 56 | if __name__=="__main__": 57 | try: 58 | room = int(sys.argv[1]) 59 | except: 60 | print usage 61 | show(room) 62 | -------------------------------------------------------------------------------- /srcs/zmq_replayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | """ 4 | module: zmq_replayer 5 | """ 6 | from lib import * 7 | 8 | import zmq 9 | context = zmq.Context() 10 | 11 | 12 | def replayer(filename="game.log", loop=False): 13 | """ 14 | 用来回放log, 默认room0 15 | """ 16 | if loop: loop_count=0 17 | # 读取file 18 | datas = [] 19 | with open(filename) as f: 20 | for line in f.readlines(): 21 | p = line.find(': ') 22 | type = line[:p] 23 | data = line[p+len(': '):] 24 | data = json.loads(data) 25 | datas.append((type, data)) 26 | 27 | # 用来发布信息更新 28 | puber = context.socket(zmq.PUB) 29 | puber.bind('ipc:///tmp/game_puber.ipc') 30 | 31 | # 用来处理 32 | oper = context.socket(zmq.REP) 33 | oper.bind('ipc:///tmp/game_oper.ipc') 34 | 35 | clock = Clock(2) 36 | i = 0 37 | map = None 38 | info = None 39 | 40 | while True: 41 | # 处理op 42 | while True: 43 | try: 44 | rc = json.loads(oper.recv(zmq.NOBLOCK)) 45 | if rc['op'] not in ('map', 'info'): 46 | result = 'this is replay server, only accept map and info' 47 | if rc['op'] == 'map': 48 | result = map 49 | else: 50 | result = info 51 | oper.send(json.dumps(result)) 52 | logging.debug('process op %s ', rc['op']) 53 | except zmq.ZMQError: 54 | break 55 | 56 | #定时更新 57 | if not clock.tick(block=False): 58 | continue 59 | 60 | # get data 61 | type, data = datas[i] 62 | i += 1 63 | if i == len(datas): break 64 | 65 | if type == 'map': 66 | map = data 67 | continue 68 | else: 69 | info = data 70 | 71 | logging.debug("stepping:" + info['status']) 72 | # 发送更新信息 73 | puber.send("room:0 " + json.dumps(info)) 74 | 75 | time.sleep(0.001) 76 | 77 | usage = """\ 78 | zmq_replayer.py [filename] 79 | """ 80 | 81 | if __name__=="__main__": 82 | if len(sys.argv) <1: print usage 83 | replayer(filename) 84 | -------------------------------------------------------------------------------- /tmp/readme.txt: -------------------------------------------------------------------------------- 1 | this dir is for temp files 2 | --------------------------------------------------------------------------------