Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Achievements new #496

Merged
merged 4 commits into from Jun 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions services/app/assets/css/app.scss
Expand Up @@ -82,3 +82,15 @@ a {
background: rgba(0, 0, 0, 0);
padding: 0;
}
.polyglot {
width: 50px;
height: 50px;
background: url('/assets/images/achievements/polyglot.png');
background-size: cover;
padding: 5px;
}
.profile .polyglot{
width: 200px;
height: 200px;
padding: 12px;
}
30 changes: 30 additions & 0 deletions services/app/assets/js/widgets/components/UserAchievements.jsx
@@ -0,0 +1,30 @@
import React from 'react';
import _ from 'lodash';

const renderPolyglotAchievement = (languages) => {
return (
<div key="polyglot" className="polyglot">
<div className="d-flex h-75 flex-wrap align-items-center justify-content-around">
{languages.map(el => <img key={el} width="10" height="10" src={`/assets/images/achievements/${el}.png`} />)}
</div>
</div>
);
};

const UserAchievements = (achievements) => {
if (!_.isEmpty(achievements)) {
return (
<div className="d-flex justify-content-start">
{achievements.map((el) => {
const [name, languages] = el.split('?');
if (name === 'win_games_with') {
return renderPolyglotAchievement(languages.split('_'));
}
return <img src={`/assets/images/achievements/${el}.png`} className="mr-1" alt={el} height="50" width="50" />})
}
</div>
);
}
return '';
};
export default UserAchievements;
11 changes: 2 additions & 9 deletions services/app/assets/js/widgets/components/UserStats.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import _ from 'lodash';
import Loading from './Loading';
import UserAchievements from './UserAchievements';

const UserStats = ({ data }) => {
if (data) {
Expand All @@ -23,15 +24,7 @@ const UserStats = ({ data }) => {
</li>
</ul>
{achivementsTitle}
{!_.isEmpty(achievements) && (
<ul className="list-inline">
{achievements.map(el => (
<li key={el} className="list-inline-item">
<img src={`/assets/images/achievements/${el}.png`} alt={el} height="50" width="50" />
</li>
))}
</ul>
)}
{UserAchievements(achievements)}
</div>
);
}
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions services/app/lib/codebattle/game_process/engine/base.ex
Expand Up @@ -54,7 +54,7 @@ defmodule Codebattle.GameProcess.Engine.Base do
creator: winner.creator,
rating: new_winner_rating,
rating_diff: winner_rating_diff,
lang: Map.get(winner, :lang, nil)
lang: Map.get(winner, :editor_lang)
})

create_user_game!(%{
Expand All @@ -64,7 +64,7 @@ defmodule Codebattle.GameProcess.Engine.Base do
creator: loser.creator,
rating: new_loser_rating,
rating_diff: loser_rating_diff,
lang: Map.get(loser, :lang, nil)
lang: Map.get(loser, :editor_lang)
})

winner_achievements = Achievements.recalculate_achievements(winner)
Expand Down
Expand Up @@ -103,7 +103,6 @@ defmodule Codebattle.GameProcess.Engine.Standard do

def handle_give_up(game_id, loser, fsm) do
winner = FsmHelpers.get_opponent(fsm, loser.id)

store_game_result_async!(fsm, {winner, "won"}, {loser, "gave_up"})
ActiveGames.terminate_game(game_id)
end
Expand Down
30 changes: 30 additions & 0 deletions services/app/lib/codebattle/user/achievements.ex
Expand Up @@ -10,6 +10,7 @@ defmodule Codebattle.User.Achievements do
def recalculate_achievements(user) do
{user.achievements, user}
|> count_played_games
|> count_wins
|> elem(0)
end

Expand Down Expand Up @@ -62,4 +63,33 @@ defmodule Codebattle.User.Achievements do
{achievements, user}
end
end

def count_wins({achievements, user}) do
query =
from(ug in UserGame,
select: {
ug.lang,
count(ug.id)
},
where: ug.user_id == ^user.id and ug.result == "won" and not is_nil(ug.lang),
group_by: ug.lang
)

languages = Repo.all(query) |> Enum.into(%{}) |> Map.keys()
exist_achievement = Enum.filter(achievements, fn x -> String.contains?(x, "win_games_with") end) |> Enum.at(0)
new_achievement = "win_games_with?#{Enum.join(languages, "_")}"
cond do
Enum.count(languages) >= 3 ->
if (new_achievement !== exist_achievement) do
new_list = List.delete(achievements, exist_achievement)
{new_list ++ [new_achievement], user}
else
{achievements, user}
end
true ->
{achievements, user}
end


end
end
16 changes: 12 additions & 4 deletions services/app/lib/codebattle_web/templates/user/show.html.slim
Expand Up @@ -35,8 +35,16 @@
.col-12.text-center.mt-4
h2.mt-1.mb-0
| Achievements:
ul.list-inline
= for achievement <- @user.achievements do
li.list-inline-item
img.img-fluid.rounded[alt="#{achievement}" title="#{achievement}" src="/assets/images/achievements/#{achievement}.png" width="200" height="200"]
div.d-flex.justify-content-center.profile
= Enum.map @user.achievements, fn achievement ->
- condition = String.contains?(achievement, "win_games_with")
= if condition do
div.polyglot[title="#{achievement}"]
div.d-flex.h-75.flex-wrap.align-items-center.justify-content-around
- langs = String.split(achievement, "?") |> Enum.at(1) |> String.split("_")
= Enum.map langs, fn lang ->
img.[alt="#{lang}" title="#{lang}" src="/assets/images/achievements/#{lang}.png" width="38" height="38"]
- else
img.mr-1[alt="#{achievement}" title="#{achievement}" src="/assets/images/achievements/#{achievement}.png" width="200" height="200"]


Expand Up @@ -56,7 +56,7 @@ defmodule RecalculateAchivementsTest do
conn =
conn1
|> get(page_path(conn1, :index))
|> post(game_path(conn1, :create, level: "easy"))
|> post(game_path(conn1, :create, level: "easy", lang: "js"))

game_id = game_id_from_conn(conn)

Expand All @@ -66,15 +66,56 @@ defmodule RecalculateAchivementsTest do
# Second player join game
post(conn2, game_path(conn2, :join, game_id))
{:ok, _response, socket2} = subscribe_and_join(socket2, GameChannel, game_topic)
# First player won
editor_text1 = "Hello world1!"
Phoenix.ChannelTest.push(socket1, "check_result", %{editor_text: editor_text1, lang: "js"})
:timer.sleep(100)
fsm = Server.fsm(game_id)

user = Repo.get(User, user1.id)
assert user.achievements == ["played_ten_games", "win_games_with?js_php_ruby"]
end
end

test "calculate polyglot achievement", %{
conn1: conn1,
conn2: conn2,
socket1: socket1,
socket2: socket2,
user1: user1,
user2: user2
} do
with_mocks [
{Codebattle.CodeCheck.Checker, [], [check: fn _a, _b, _c -> {:ok, "asdf", "asdf"} end]}
] do

["js", "php", "ruby"]
|> Enum.each(fn x ->
insert_list(3, :user_game, %{user: user1, lang: x, result: "won"})
end)

# Create game
conn =
conn1
|> get(page_path(conn1, :index))
|> post(game_path(conn1, :create, level: "easy", lang: "js"))

game_id = game_id_from_conn(conn)

game_topic = "game:" <> to_string(game_id)
{:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic)

# Second player join game
post(conn2, game_path(conn2, :join, game_id))
{:ok, _response, socket2} = subscribe_and_join(socket2, GameChannel, game_topic)
# First player won
editor_text1 = "Hello world1!"
Phoenix.ChannelTest.push(socket1, "check_result", %{editor_text: editor_text1, lang: "js"})
:timer.sleep(100)
fsm = Server.fsm(game_id)

user = Repo.get(User, user1.id)
assert user.achievements == ["played_ten_games"]
assert user.achievements == ["played_ten_games", "win_games_with?js_php_ruby"]
end
end
end
Expand Up @@ -51,7 +51,7 @@ defmodule Codebattle.RandomTaskSelectorTest do
conn =
conn1
|> get(page_path(conn1, :index))
|> post(game_path(conn1, :create, level: "easy"))
|> post(game_path(conn1, :create, level: "easy", lang: "js"))

game_id = game_id_from_conn(conn)

Expand Down