Skip to content

Commit

Permalink
many changes
Browse files Browse the repository at this point in the history
  • Loading branch information
chouzar committed Feb 3, 2024
1 parent d306627 commit 83b0f09
Show file tree
Hide file tree
Showing 12 changed files with 657 additions and 370 deletions.
8 changes: 3 additions & 5 deletions priv/assets/script.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
const session = document.querySelector("meta[name='session']").content;
const body = document.querySelector("body");

const socket = new WebSocket("wss://localhost:4444/events");
const socket = new WebSocket("wss://localhost:4444/events/" + session);

socket.onopen = (_event) => {
socket.send("session:" + session)
};

socket.onmessage = (event) => {
Expand All @@ -13,9 +12,8 @@ socket.onmessage = (event) => {
};

window.addEventListener('click', (event) => {
console.log(event.target.dataset.event)
if (event.target.dataset.event) {
const action = event.target.dataset.event
const data = JSON.stringify(event.target.dataset);
socket.send(new Blob([action, "\n\n", data]));
socket.send(new Blob([event.target.dataset.event]));
}
});
51 changes: 44 additions & 7 deletions src/luster.gleam
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import chip
import envoy
import gleam/erlang/process
import gleam/http/request
import gleam/http/response
import luster/store
import luster/systems/store
import luster/web
import luster/web/tea_game
import mist
import chip

// TODO: Create a web, games and luster/runtime contexts
// TODO: Add a proper supervision tree
//assert Ok(subject) =
// supervisor.start(fn(children) {
// children
// |> supervisor.add(supervisor.worker(session.start))
// })

// TODO: Rename chip to be:
// register -> For adding an already created subject
// spawn -> For adding the subject in callback

// TODO: Eventually Chip needs to have a way of registering
// custom types and addressing the register, de-register through callbacks.
// OR accept Selectors

// TODO: Chip could handle id generation through continuations
// OR use ETS underneath

// TODO: Create a compartment in Chip for unique subjects

pub fn main() -> Nil {
let assert Ok(store) = store.start()
let assert Ok(registry) = chip.start()
let assert Ok(session_registry) = chip.start()
let assert Ok(socket_registry) = chip.start()

let request_pipeline = fn(request: request.Request(mist.Connection)) -> response.Response(
mist.ResponseData,
) {
web.router(request, registry, store)
web.router(request, store, session_registry, socket_registry)
}

let assert Ok(_server) =
Expand All @@ -34,7 +46,6 @@ pub fn main() -> Nil {
keyfile: env("LUSTER_KEY"),
)

store.create(store, tea_game.init())
process.sleep_forever()
}

Expand All @@ -44,3 +55,29 @@ fn env(key: String) -> String {
Error(Nil) -> panic as "unable to find ENV"
}
}
// --- Helpers --- //

//const adjectives = [
// "salty", "brief", "noble", "glorious", "respectful", "tainted", "measurable",
// "constant", "fake", "lighting", "cool", "sparkling", "painful", "superperfect",
//]
//
//const subjects = [
// "poker", "party", "battle", "danceoff", "bakeoff", "marathon", "club", "game",
// "match", "rounds",
//]
//
//fn generate_name() -> String {
// let assert Ok(adjective) =
// adjectives
// |> list.shuffle()
// |> list.first()
//
// let assert Ok(subject) =
// subjects
// |> list.shuffle()
// |> list.first()
//
// adjective <> " " <> subject
//}
//
37 changes: 15 additions & 22 deletions src/luster/game.gleam → src/luster/games/three_line_poker.gleam
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import gleam/dict.{type Dict}
import gleam/int
import gleam/list
import gleam/dict.{type Dict}
import gleam/option.{type Option, None, Some}
import gleam/order.{type Order}
import gleam/result.{try}

const max_hand_size = 8
pub const max_hand_size = 8

const plays_per_turn = 4

Expand All @@ -27,6 +27,11 @@ const ranks = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

const suits = [Spade, Heart, Diamond, Club]

pub type Message {
DrawCard(player: Player)
PlayCard(player: Player, slot: Slot, card: Card)
}

pub opaque type GameState {
GameState(
turn: Int,
Expand Down Expand Up @@ -115,7 +120,7 @@ pub type Score {
}

pub type Errors {
InvalidAction(Action)
InvalidAction(Message)
NotCurrentPhase
NotCurrentPlayer
EmptyDeck
Expand All @@ -138,28 +143,11 @@ pub fn new() -> GameState {
)
}

pub type Action {
DrawCard(player: Player)
PlayCard(player: Player, slot: Slot, card: Card)
}

/// Modifies the game state by applying an action.
pub fn next(state: GameState, action: Action) -> Result(GameState, Errors) {
let check_current_player = fn(state: GameState, player) {
let current = first(state.sequence)

case state.turn, player {
0, _player -> Ok(state)
_, player if player == current -> Ok(state)
_, _ -> Error(NotCurrentPlayer)
}
}

// TODO: Draw should not stop from playng the other player
pub fn next(state: GameState, action: Message) -> Result(GameState, Errors) {
case state.phase, action {
Draw, DrawCard(player) -> {
Ok(state)
|> result.then(check_current_player(_, player))
|> result.then(fn(state) {
draw_card(state.board, player)
|> result.map(fn(board) { GameState(..state, board: board) })
Expand All @@ -182,7 +170,12 @@ pub fn next(state: GameState, action: Action) -> Result(GameState, Errors) {

Play, PlayCard(player, slot, card) -> {
Ok(state)
|> result.then(check_current_player(_, player))
|> result.then(fn(state) {
case first(state.sequence) {
current if player == current -> Ok(state)
_current -> Error(NotCurrentPlayer)
}
})
|> result.then(fn(state) {
play_card(state.board, player, slot, card)
|> result.map(fn(board) { GameState(..state, board: board) })
Expand Down
Empty file removed src/luster/player.gleam
Empty file.
153 changes: 153 additions & 0 deletions src/luster/systems/comp.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import gleam/erlang/process
import gleam/float
import gleam/function.{identity}
import gleam/int
import gleam/list
import gleam/otp/actor
import gleam/result.{try}
import luster/games/three_line_poker as tlp
import luster/systems/session
import luster/web/socket

pub type Message {
AssessMove
Stop
}

type State {
State(
self: process.Subject(Message),
session_id: String,
player: tlp.Player,
session: process.Subject(session.Message),
pubsub: socket.PubSub,
)
}

pub fn start(
player: tlp.Player,
session: process.Subject(session.Message),
pubsub: socket.PubSub,
) -> Result(process.Subject(Message), actor.StartError) {
actor.start_spec(actor.Spec(
init: fn() { handle_init(player, session, pubsub) },
init_timeout: 10,
loop: handle_message,
))
}

fn handle_init(
player: tlp.Player,
session: process.Subject(session.Message),
pubsub: socket.PubSub,
) -> actor.InitResult(State, Message) {
let self = process.new_subject()

let session_id = session.id(session)

process.send_after(self, 5000, AssessMove)

actor.Ready(
State(self, session_id, player, session, pubsub),
process.new_selector()
|> process.selecting(self, identity),
)
}

fn handle_message(message: Message, state: State) -> actor.Next(Message, State) {
case message {
AssessMove -> {
let _ = {
use gamestate <- try(session.get(state.session))
use message <- try(assess_move(state.player, gamestate))
use gamestate <- try(make_move(gamestate, message))
let Nil = session.set(state.session, gamestate)
let Nil =
socket.broadcast(
state.pubsub,
state.session_id,
socket.UpdateGameState,
)

Ok(Nil)
}

let _timer =
process.send_after(state.self, between(1000, 2500), AssessMove)

actor.continue(state)
}

Stop -> {
actor.Stop(process.Normal)
}
}
}

fn assess_move(
player: tlp.Player,
gamestate: tlp.GameState,
) -> Result(tlp.Message, Nil) {
let hand = tlp.player_hand(gamestate, player)
let slots = tlp.available_plays(gamestate, player)

case list.length(hand), tlp.current_player(gamestate) {
size, current if size == tlp.max_hand_size && current == player -> {
Ok(play_card(player, slots, hand))
}

size, current if size == tlp.max_hand_size && current != player -> {
Error(Nil)
}

_size, current if current != player -> {
Ok(draw_card(player))
}

0, _player -> {
Ok(draw_card(player))
}

_size, player -> {
let assert Ok(move) =
[play_card(player, slots, hand), draw_card(player)]
|> list.shuffle()
|> list.first()

Ok(move)
}
}
}

fn play_card(player, slots, hand) -> tlp.Message {
let assert Ok(slot) =
slots
|> list.shuffle()
|> list.first()
let assert Ok(card) =
hand
|> list.shuffle()
|> list.first()
tlp.PlayCard(player, slot, card)
}

fn draw_card(player) -> tlp.Message {
tlp.DrawCard(player)
}

fn make_move(gamestate, message) {
case tlp.next(gamestate, message) {
Ok(gamestate) -> Ok(gamestate)
Error(_) -> Error(Nil)
}
}

fn between(start: Int, end: Int) -> Int {
let period = int.to_float(end - start)
let random =
period
|> float.multiply(float.random())
|> float.round()

random + start
}
Loading

0 comments on commit 83b0f09

Please sign in to comment.