Compare commits

...

4 Commits

9 changed files with 302 additions and 122 deletions

View File

@ -1,2 +1,4 @@
generate-elm :
cd external/GoUI && elm make Go.elm --output ../../public/js/Go.js
generate-css :
scss public/scss/main.scss > public/css/main.css

2
external/GoUI vendored

@ -1 +1 @@
Subproject commit 0d31433b96e1f7e656243a44eaed97b01f8f7d80
Subproject commit 54d1229c9f12ee0edf65774a3335bff70ff78a84

55
public/css/main.css Normal file
View File

@ -0,0 +1,55 @@
h1, h2, h3, h4, h5, h6 {
font-family: "Indie Flower", serif; }
h1 {
font-size: 5em;
margin: 0px;
text-align: center; }
body {
font-family: "Raleway", sans-serif;
margin: 0px;
background-color: #f4f4f4; }
.content-wrapper {
max-width: 750px;
margin: auto; }
.board {
background-color: tomato;
padding: 20px;
max-width: 500px;
margin: auto;
border-radius: 10px; }
.black-player .overlay:hover {
background-color: black; }
.white-player .overlay:hover {
background-color: white; }
.board-cell {
display: inline-block;
position: relative;
padding: 5.55556%; }
.board-cell .overlay {
position: absolute;
box-sizing: border-box;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
border-radius: 50%;
transition: background-color .25s; }
.board-cell.small {
padding: 5.55556%; }
.board-cell.medium {
padding: 3.84615%; }
.board-cell.large {
padding: 2.63158%; }
.black-cell .overlay {
background-color: black; }
.white-cell .overlay {
background-color: white; }

View File

@ -9504,7 +9504,18 @@ var _user$project$Go_View$renderIndex = function (_p0) {
_1: {ctor: '[]'}
}
},
{ctor: '[]'});
{
ctor: '::',
_0: A2(
_elm_lang$html$Html$div,
{
ctor: '::',
_0: _elm_lang$html$Html_Attributes$class('overlay'),
_1: {ctor: '[]'}
},
{ctor: '[]'}),
_1: {ctor: '[]'}
});
};
var _user$project$Go_View$renderBoard = F2(
function (size, board) {
@ -9550,10 +9561,7 @@ var _user$project$Go_Ws$wsUrl = function (m) {
return A2(
_elm_lang$core$Basics_ops['++'],
m.sessionUrl,
A2(
_elm_lang$core$Basics_ops['++'],
'/game/',
_elm_lang$core$Basics$toString(m.sessionId)));
A2(_elm_lang$core$Basics_ops['++'], '/game/', m.sessionId));
};
var _user$project$Go_Ws$sendMove = F2(
function (m, c) {
@ -9655,7 +9663,7 @@ var _user$project$Main$initDummy = {
_user$project$Go_Types$Model,
_user$project$Go_Types$Black,
'ws://localhost:3000',
1,
'debug',
9,
_elm_lang$core$Maybe$Nothing,
_elm_lang$core$Maybe$Nothing,
@ -9698,7 +9706,7 @@ var _user$project$Main$main = _elm_lang$html$Html$programWithFlags(
},
A2(_elm_lang$core$Json_Decode$field, 'size', _elm_lang$core$Json_Decode$int));
},
A2(_elm_lang$core$Json_Decode$field, 'id', _elm_lang$core$Json_Decode$int));
A2(_elm_lang$core$Json_Decode$field, 'id', _elm_lang$core$Json_Decode$string));
},
A2(_elm_lang$core$Json_Decode$field, 'black', _elm_lang$core$Json_Decode$bool)));

87
public/scss/main.scss Normal file
View File

@ -0,0 +1,87 @@
$background-grey: #f4f4f4;
@mixin board-cell($size) {
padding: 100%/$size/2;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Indie Flower", serif;
}
h1 {
font-size: 5em;
margin: 0px;
text-align: center;
}
body {
font-family: "Raleway", sans-serif;
margin: 0px;
background-color: $background-grey;
}
.content-wrapper {
max-width: 750px;
margin: auto;
}
.board {
background-color: tomato;
padding: 20px;
max-width: 500px;
margin: auto;
border-radius: 10px;
}
.black-player .overlay {
&:hover {
background-color: black;
}
}
.white-player .overlay {
&:hover {
background-color: white;
}
}
.board-cell {
display: inline-block;
position: relative;
@include board-cell(9);
.overlay {
position: absolute;
box-sizing: border-box;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
border-radius: 50%;
transition: background-color .25s;
}
&.small {
@include board-cell(9);
}
&.medium {
@include board-cell(13);
}
&.large {
@include board-cell(19);
}
}
.black-cell {
.overlay {
background-color: black;
}
}
.white-cell {
.overlay {
background-color: white;
}
}

119
src/Go.cr
View File

@ -2,81 +2,30 @@ require "./Go/*"
require "kemal"
require "json"
enum Color
Black
White
end
enum Size
Small = 9,
Medium = 13,
Large = 19
end
alias Board = Hash(Tuple(Int8, Int8), Color)
def cell_json(index, color, json)
json.object do
json.field "index" do
json.object do
json.field "x", index[0]
json.field "y", index[1]
end
end
json.field "color", color.to_s
end
end
def board_json(board, json)
json.array do
board.each do |key, value|
cell_json(key, value, json)
end
end
end
class Game
property size : Size
property board : Board
property turn : Color
property sockets : Array(HTTP::WebSocket)
def initialize(size : Size)
@size = size
@board = Board.new
@turn = Color::Black
@sockets = [] of HTTP::WebSocket
end
def to_string
JSON.build do |json|
json.object do
json.field "turn", @turn.to_s
json.field "board" { board_json(@board, json) }
end
end
end
def update(x, y, color)
@board[{x, y}] = color
end
end
URL = "localhost"
GAME_CACHE = {} of Int64 => Game
GAME_CACHE = {} of String => Go::Game
def lookup_game(cache, id) : Game?
def query_game(db, id) : Go::Game?
return nil
end
def lookup_game(db, cache, id) : Go::Game?
if game = cache[id]?
return game
else
loaded_game = query_game(db, id)
cache[id] = loaded_game if loaded_game
return loaded_game
end
end
def handle_message(id, game, socket, message)
split_command = message.split(" ")
command = split_command[0]
if command == "place"
x = split_command[1].to_i8
y = split_command[2].to_i8
color = split_command[3] == "Black" ? Color::Black : Color::White
color = split_command[3] == "Black" ? Go::Color::Black : Go::Color::White
game.update(x, y, color)
game.sockets.each { |socket| socket.send game.to_string }
@ -88,41 +37,43 @@ get "/" do |env|
end
get "/game/:id" do |env|
if game_id = env.params.url["id"].to_i64?
if game = (GAME_CACHE[game_id]? || lookup_game(GAME_CACHE, game_id))
game_id = env.params.url["id"]
game_password = env.params.query["password"]?
if game = lookup_game(nil, GAME_CACHE, game_id)
id = game_id
size = game.size.value
black = nil
if game_password == game.blackPass
black = true
id = game_id
size = game.size.value
render "src/Go/views/game.ecr"
else
render_404
elsif game_password == game.whitePass
black = false
end
black.try { |black| render "src/Go/views/game.ecr", "src/Go/views/base.ecr"} || render_404
else
render_404
end
end
ws "/game/:id" do |socket, env|
if game_id = env.params.url["id"].to_i64?
if game = (GAME_CACHE[game_id]? || lookup_game(GAME_CACHE, game_id))
socket.send game.to_string
game.sockets << socket
game_id = env.params.url["id"]
if game = lookup_game(nil, GAME_CACHE, game_id)
socket.send game.to_string
game.sockets << socket
socket.on_message do |message|
game.try { |game| handle_message(game_id, game, socket, message) }
end
socket.on_message do |message|
game.try { |game| handle_message(game_id, game, socket, message) }
end
socket.on_close do
game.try { |game| game.sockets.delete socket }
end
else
render_404
socket.on_close do
game.try { |game| game.sockets.delete socket }
end
else
render_404
end
end
GAME_CACHE[1_i64] = Game.new(Size::Small)
GAME_CACHE["debug"] = Go::Game.new(Go::Size::Small, "black", "white")
Kemal.run

84
src/Go/Game.cr Normal file
View File

@ -0,0 +1,84 @@
module Go
enum Color
Black
White
end
enum Size
Small = 9,
Medium = 13,
Large = 19
end
alias Board = Hash(Tuple(Int8, Int8), Color)
class Game
property size : Size
property blackPass : String
property whitePass : String
property board : Board
property turn : Color
property sockets : Array(HTTP::WebSocket)
def initialize(size : Size, @blackPass, @whitePass)
@size = size
@board = Board.new
@turn = Color::Black
@sockets = [] of HTTP::WebSocket
end
private def cell_json(index, color, json)
json.object do
json.field "index" do
json.object do
json.field "x", index[0]
json.field "y", index[1]
end
end
json.field "color", color.to_s
end
end
private def board_json(board, json)
json.array do
board.each do |key, value|
cell_json(key, value, json)
end
end
end
def to_string
JSON.build do |json|
json.object do
json.field "turn", @turn.to_s
json.field "board" { board_json(@board, json) }
end
end
end
def update(x, y, color)
@board[{x, y}] = color
@turn = @turn == Color::Black ? Color::White : Color::Black
end
private def color_char(color)
color == Color::Black ? 'B' : 'W'
end
private def board_string(board)
String.build do |str|
(0...@size.value).each do |x|
(0...@size.value).each do |y|
color = @board[{x.to_i8, y.to_i8}]?
char = color ? color_char(color) : 'E'
str << char
end
end
end
end
def encode
{ @turn.to_s, @size.value, board_string(@board) }
end
end
end

12
src/Go/views/base.ecr Normal file
View File

@ -0,0 +1,12 @@
<html>
<head>
<link rel="stylesheet" href="/css/main.css">
<link href="https://fonts.googleapis.com/css?family=Indie+Flower|Raleway" rel="stylesheet">
</head>
<body>
<div class="content-wrapper">
<h1>Go</h1>
<%= content %>
</div>
</body>
</html>

View File

@ -1,30 +1,11 @@
<html>
<head>
<style>
.board-cell {
display: inline-block;
background-color: #eaeaea;
padding: 20px;
}
.black-cell {
background-color: black;
}
.board {
max-width: 360px;
}
</style>
</head>
<body>
<div id="elm-root"></div>
<script src="/js/Go.js"></script>
<script>
var node = document.getElementById('elm-root')
var app = Elm.Main.embed(node, {
'black' : <%= black %>,
'url' : "<%= "ws://" + URL + ":" + Kemal.config.port.to_s %>",
'id' : <%= id %>,
'size' : <%= size %>
})
</script>
</body>
</html>
<div id="elm-root" class="<%= black ? "black" : "white" %>-player"></div>
<script src="/js/Go.js"></script>
<script>
var node = document.getElementById('elm-root')
var app = Elm.Main.embed(node, {
'black' : <%= black %>,
'url' : "<%= "ws://" + URL + ":" + Kemal.config.port.to_s %>",
'id' : "<%= id %>",
'size' : <%= size %>
})
</script>