Compare commits
4 Commits
6287968404
...
9d60519f5c
Author | SHA1 | Date |
---|---|---|
Danila Fedorin | 9d60519f5c | |
Danila Fedorin | e7b1144301 | |
Danila Fedorin | 75a386539e | |
Danila Fedorin | f01c891cec |
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0d31433b96e1f7e656243a44eaed97b01f8f7d80
|
||||
Subproject commit 54d1229c9f12ee0edf65774a3335bff70ff78a84
|
|
@ -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; }
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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
119
src/Go.cr
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue