Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails turn based game manager

I am writing a turn based card game (line an online poker). I have experience using rails so i would like to use it for the majority of the logic like managing the users with coins and statistics, manage rooms and games. I am planning to use node js + socket.io + redis to provide realtime messaging server -> client (basically use redis from rails to publish messages, listen to them on node.js side and publish through socket.io to the clients) and using REST API to communicate from the client -> server.

The part i am stuck on is trying to manage the actual game logic inside rails. I would need a Game Manager for each game in progress which would evaluate everything that happens in a game (dealing cards, accepting bets, going through player turns, evaluating results etc..). Two things in particular seems kinda impossible to me and that is this situation from my experience building webapps with rails so far:

  • Having the game manager as a single shared object in memory: I was thinking this could be a redis cached object and will be reloaded on each state change and saved again with the new state which seems like a big overhead. Another thing i was considering was holding a hash of game manager objects, one for each ongoing game as a static object accessible from anywhere in the rails app. Anything i am missing here? Can this be somehow improved or any other approach to doing this sort of a functionality?

  • Having a timer that ticks while waiting for a player to make a move Like any turn based game i would need to wait a specific number of seconds until a player reacts, if the player doesn't take action in lets say 20 seconds then the server should automatically move to the next player. I really don't know how to do this in rails. One approach i was considering was a delayed task which will run after 20 seconds and expire the players turn or be canceled if the user acts before it. (using sidekiq for example for these tasks).

EDIT

I am stuck on designing how to implement the actual game logic, thats why i need a game manager, there needs to be a timer ticking every 1 second for every active game (game that has at least 2 players), there needs to be a callback after x seconds if a player doesn't take their turn to move to the next player. I don't see how i can do that in rails due to the stateless nature of each request and i need to store game state in memory and run a timer somehow. I do believe i can solve this specific issue around game logic in node.js, but i would rather use node.js just to manage the socket connections and receive events through redis pub/sub.

like image 542
DArkO Avatar asked Jan 31 '26 02:01

DArkO


1 Answers

This is going to be quite abstract, I hope you don't mind.


Game Manager

What will the game manager actually do?

You say you want it to run in memory - why? An application runs based on input/output. Unless you want to use it in some sort of timed response format (sending notification messages etc), the game manager idea really is useless.

What you need is a way to handle the individual games on the system. This may require heavy javascript implementation, BUT from a Rails perspective it's not necessary to go overboard in the backend.

Remember, you're just looking for real time logic. This does not mean you have to have real-time applications running on the server. On the contrary, you could handle it with Rails' models and business logic in the backend.

This is just a basic example:

#app/models/game.rb
class Game < ActiveRecord::Base
   #columns id | name | active (bool) | created_at | updated_at
   has_many :players
end

#app/models/player.rb
class Player < ActiveRecord::Base
   #columns id | game_id | user_id | created_at | updated_at
   belongs_to :game
   belongs_to :user

   alias_attribute :joined, :created_at
end

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :players
   has_many :games, through: :players
end

This is a very basic example, but what it should give you is the following:

#config/routes.rb
resources :games, only: [:index, :show] do
    resources :sessions, path: "", path_names: { new: "join", destroy: "leave" show: "" }, only: [:new, :destroy] #-> url.com/games/:game_id/join
end

#app/controllers/games_controller.rb
class SessionsController < ApplicationController
   def new
      @game = Game.find params[:game_id]
      @session = @game.players.new player_params
      if @session.save
         redirect_to @game #-> takes you to url.com/game/23
      else
         redirect_to root_url, notice: "Sorry, you cannot join this game"
      end
   end

   private

   def player_params
      params.require(:user).permit(:x, :y, :z)
   end
end

I know it's not strictly CRUD, but I hope you appreciate how it works.

You could then make your logic inside your models:

#app/models/player.rb
class Player < ActiveRecord::Base
    belongs_to :game
    belongs_to :user

    alias_attribute :joined, :created_at

    validates :user, uniqueness: { scope: :game, message: "You're already in this game!" } 
end

The real-time aspect of this will come from how fast your server responds to the requests. If you have a JS front-end (to make it look pretty), you'll be able to ping the backend with JSON (like an API), taking responses and utilizing them in the front-end.

--

Messages

Use Pusher with Redis.

The real time notification stuff would be a little more involved thing to implement, not programmatically, but resourcefully.

Sending push notifications to connected clients is relatively simple - just queue the messages in Redis and send them out with Pusher.

However, if you wanted to invoke messages without an input (IE if there's a time update or whatever), you'll need have some sort of CRON script running every xseconds on the server.

This is where you may need some separate functionality, although I think Rails could handle it with some rake commands. The resource load of having this type of functionality is what has to be comprehended.

like image 59
Richard Peck Avatar answered Feb 01 '26 15:02

Richard Peck