{"action":"created","comment":{"url":"https://api.github.com/repos/java-course-au/assignments/pulls/comments/45107338","id":45107338,"diff_hunk":"@@ -3,21 +3,185 @@\n import java.io.BufferedReader;\n import java.io.FileReader;\n import java.io.IOException;\n-import java.util.*;\n+import java.util.ArrayList;\n+import java.util.concurrent.locks.Lock;\n+import java.util.concurrent.locks.ReentrantLock;\n+\n+import static java.lang.String.format;\n \n \n public class QuizGame implements Game {\n+\n+    public static final String FORMAT_NEW_ROUND = \"New round started: %s (%d letters)\";\n+    public static final String FORMAT_CURRENT_PREFIX = \"Current prefix is %s\";\n+    public static final String FORMAT_WINNER = \"The winner is %s\";\n+    public static final String FORMAT_WRONG = \"Wrong try\";\n+    public static final String FORMAT_STOP = \"Game has been stopped by %s\";\n+    public static final String FORMAT_NOBODY = \"Nobody guessed, the word was %s\";\n+\n+    public void setDictionaryFilename(String dictionaryFilename) {\n+        this.dictionaryFilename = dictionaryFilename;\n+    }\n+\n+    public void setMaxLettersToOpen(int maxLettersToOpen) {\n+        this.maxLettersToOpen = maxLettersToOpen;\n+    }\n+\n+    public void setDelayUntilNextLetter(int delayUntilNextLetter) {\n+        this.delayUntilNextLetter = delayUntilNextLetter;\n+    }\n+\n+    // Params:\n+    protected String dictionaryFilename;\n+    protected int maxLettersToOpen;\n+    protected int delayUntilNextLetter;\n+\n+    protected static class Question {\n+        private String question;\n+        private String answer;\n+\n+        private Question(String question, String answer) {\n+            this.question = question;\n+            this.answer = answer;\n+        }\n+    }\n+\n+    protected GameServer gameServer;\n+    protected Lock lockMessages = new ReentrantLock();\n+    protected ArrayList<Question> questions = new ArrayList<>();\n+    protected int currentQuestion = -1;\n+    protected int currentProgress;\n+    protected boolean isRunning = false;\n+\n+    protected int tickerTaskId = 0;\n+\n     public QuizGame(GameServer server) {\n-        throw new UnsupportedOperationException(\"TODO: implement\");\n+        gameServer = server;\n     }\n \n     @Override\n     public void onPlayerConnected(String id) {\n-        throw new UnsupportedOperationException(\"TODO: implement\");\n+        if (!isRunning) {\n+            return;\n+        }\n+\n+        lockMessages.lock();\n+        try {\n+            gameServer.sendTo(id, format(FORMAT_NEW_ROUND, questions.get(currentQuestion).question, questions.get(currentQuestion).answer.length()));\n+            for (int i = 1; i <= currentProgress; ++i) {\n+                gameServer.sendTo(id, format(FORMAT_CURRENT_PREFIX, questions.get(currentQuestion).answer.substring(0, i)));\n+            }\n+        } finally {\n+            lockMessages.unlock();\n+        }\n     }\n \n     @Override\n     public void onPlayerSentMsg(String id, String msg) {\n-        throw new UnsupportedOperationException(\"TODO: implement\");\n+        lockMessages.lock();\n+        try {\n+            if (msg.length() != 0 && msg.charAt(0) == '!') {\n+                //Commands\n+                switch (msg) {\n+                    case \"!start\":\n+                        if (!isRunning) {\n+                            startGame(id);\n+                        }\n+                        break;\n+\n+                    case \"!stop\":\n+                        if (isRunning) {\n+                            stopGame(id);\n+                        }\n+                        break;\n+                }\n+                return;\n+            }\n+\n+            boolean answered = false;\n+            if (msg.equals(questions.get(currentQuestion).answer)) {\n+                answered = true;\n+                stopTicker();\n+                gameServer.broadcast(format(FORMAT_WINNER, id));\n+            } else {\n+                gameServer.sendTo(id, FORMAT_WRONG);\n+            }\n+            if (answered)\n+                startRound();\n+        } finally {\n+            lockMessages.unlock();\n+        }\n+    }\n+\n+    protected void startGame(String id) {\n+        try {\n+            BufferedReader reader = new BufferedReader(new FileReader(dictionaryFilename));\n+            String line;\n+            questions.clear();\n+            while ((line = reader.readLine()) != null) {\n+                int sep = line.indexOf(';');\n+                questions.add(new Question(line.substring(0, sep), line.substring(sep + 1)));\n+            }\n+        } catch (IOException e) {\n+            throw new RuntimeException(\"Can't read questions\", e);\n+        }\n+//        currentQuestion = -1;\n+        isRunning = true;\n+        startRound();\n+    }\n+\n+    protected void stopGame(String id) {\n+        stopTicker();\n+        gameServer.broadcast(format(FORMAT_STOP, id));\n+        isRunning = false;\n+    }\n+\n+    protected void startRound() {\n+        ++currentQuestion;\n+        if (currentQuestion == questions.size()) {\n+            currentQuestion = 0;\n+        }\n+        currentProgress = 0;\n+        gameServer.broadcast(format(FORMAT_NEW_ROUND, questions.get(currentQuestion).question, questions.get(currentQuestion).answer.length()));\n+        runTicker();\n+    }\n+\n+    protected void runTicker() {\n+        new Thread(new Runnable() {\n+            final int task = tickerTaskId;\n+\n+            @Override\n+            public void run() {\n+                try {\n+                    Thread.sleep(delayUntilNextLetter);\n+                } catch (InterruptedException e) {\n+                    return;\n+                }\n+                lockMessages.lock();\n+                try {\n+                    if (tickerTaskId == task) {","path":"src/main/java/ru/spbau/mit/QuizGame.java","position":164,"original_position":164,"commit_id":"bc0a81ac57f1eb2d75fbde69cfdae5aa1c2b0f1f","original_commit_id":"bc0a81ac57f1eb2d75fbde69cfdae5aa1c2b0f1f","user":{"login":"dzharkov","id":863207,"avatar_url":"https://avatars.githubusercontent.com/u/863207?v=3","gravatar_id":"","url":"https://api.github.com/users/dzharkov","html_url":"https://github.com/dzharkov","followers_url":"https://api.github.com/users/dzharkov/followers","following_url":"https://api.github.com/users/dzharkov/following{/other_user}","gists_url":"https://api.github.com/users/dzharkov/gists{/gist_id}","starred_url":"https://api.github.com/users/dzharkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dzharkov/subscriptions","organizations_url":"https://api.github.com/users/dzharkov/orgs","repos_url":"https://api.github.com/users/dzharkov/repos","events_url":"https://api.github.com/users/dzharkov/events{/privacy}","received_events_url":"https://api.github.com/users/dzharkov/received_events","type":"User","site_admin":false},"body":"Какая-то сложная логика вышла с этими tickerTaskId\r\nОтчего это должно нас спасти?","created_at":"2015-11-17T19:28:24Z","updated_at":"2015-11-17T19:28:24Z","html_url":"https://github.com/java-course-au/assignments/pull/74#discussion_r45107338","pull_request_url":"https://api.github.com/repos/java-course-au/assignments/pulls/74","_links":{"self":{"href":"https://api.github.com/repos/java-course-au/assignments/pulls/comments/45107338"},"html":{"href":"https://github.com/java-course-au/assignments/pull/74#discussion_r45107338"},"pull_request":{"href":"https://api.github.com/repos/java-course-au/assignments/pulls/74"}}},"pull_request":{"url":"https://api.github.com/repos/java-course-au/assignments/pulls/74","id":50751588,"html_url":"https://github.com/java-course-au/assignments/pull/74","diff_url":"https://github.com/java-course-au/assignments/pull/74.diff","patch_url":"https://github.com/java-course-au/assignments/pull/74.patch","issue_url":"https://api.github.com/repos/java-course-au/assignments/issues/74","number":74,"state":"open","locked":false,"title":"ДЗ 3, Лапшин Дмитрий, подгруппа 1","user":{"login":"LDVSOFT","id":5804255,"avatar_url":"https://avatars.githubusercontent.com/u/5804255?v=3","gravatar_id":"","url":"https://api.github.com/users/LDVSOFT","html_url":"https://github.com/LDVSOFT","followers_url":"https://api.github.com/users/LDVSOFT/followers","following_url":"https://api.github.com/users/LDVSOFT/following{/other_user}","gists_url":"https://api.github.com/users/LDVSOFT/gists{/gist_id}","starred_url":"https://api.github.com/users/LDVSOFT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LDVSOFT/subscriptions","organizations_url":"https://api.github.com/users/LDVSOFT/orgs","repos_url":"https://api.github.com/users/LDVSOFT/repos","events_url":"https://api.github.com/users/LDVSOFT/events{/privacy}","received_events_url":"https://api.github.com/users/LDVSOFT/received_events","type":"User","site_admin":false},"body":"@dzharkov тут такое дело -- тесты на `QuizGame` иногда не падают, иногда падают, но всё упирается в `assertFalse` в `checkNotDone` -- оно иногда падает, иногда не падает. Это понятно почему -- моя игра не знает о том, что `connection` надо закрыть, и ждёт сообщения от бота, а он ругается, типа не его это забота сейчас писать, всё что хотел он послал. Я руками перепроверял тесты -- при запуске каждого из них поодиночке они OK.","created_at":"2015-11-15T17:44:14Z","updated_at":"2015-11-17T19:28:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"17fb81edc8aee2d19b352ee4659a5fa93330dcdd","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/java-course-au/assignments/pulls/74/commits","review_comments_url":"https://api.github.com/repos/java-course-au/assignments/pulls/74/comments","review_comment_url":"https://api.github.com/repos/java-course-au/assignments/pulls/comments{/number}","comments_url":"https://api.github.com/repos/java-course-au/assignments/issues/74/comments","statuses_url":"https://api.github.com/repos/java-course-au/assignments/statuses/bc0a81ac57f1eb2d75fbde69cfdae5aa1c2b0f1f","head":{"label":"LDVSOFT:03-game-server","ref":"03-game-server","sha":"bc0a81ac57f1eb2d75fbde69cfdae5aa1c2b0f1f","user":{"login":"LDVSOFT","id":5804255,"avatar_url":"https://avatars.githubusercontent.com/u/5804255?v=3","gravatar_id":"","url":"https://api.github.com/users/LDVSOFT","html_url":"https://github.com/LDVSOFT","followers_url":"https://api.github.com/users/LDVSOFT/followers","following_url":"https://api.github.com/users/LDVSOFT/following{/other_user}","gists_url":"https://api.github.com/users/LDVSOFT/gists{/gist_id}","starred_url":"https://api.github.com/users/LDVSOFT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LDVSOFT/subscriptions","organizations_url":"https://api.github.com/users/LDVSOFT/orgs","repos_url":"https://api.github.com/users/LDVSOFT/repos","events_url":"https://api.github.com/users/LDVSOFT/events{/privacy}","received_events_url":"https://api.github.com/users/LDVSOFT/received_events","type":"User","site_admin":false},"repo":{"id":42593849,"name":"assignments","full_name":"LDVSOFT/assignments","owner":{"login":"LDVSOFT","id":5804255,"avatar_url":"https://avatars.githubusercontent.com/u/5804255?v=3","gravatar_id":"","url":"https://api.github.com/users/LDVSOFT","html_url":"https://github.com/LDVSOFT","followers_url":"https://api.github.com/users/LDVSOFT/followers","following_url":"https://api.github.com/users/LDVSOFT/following{/other_user}","gists_url":"https://api.github.com/users/LDVSOFT/gists{/gist_id}","starred_url":"https://api.github.com/users/LDVSOFT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LDVSOFT/subscriptions","organizations_url":"https://api.github.com/users/LDVSOFT/orgs","repos_url":"https://api.github.com/users/LDVSOFT/repos","events_url":"https://api.github.com/users/LDVSOFT/events{/privacy}","received_events_url":"https://api.github.com/users/LDVSOFT/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/LDVSOFT/assignments","description":"Домашние задания по Java","fork":true,"url":"https://api.github.com/repos/LDVSOFT/assignments","forks_url":"https://api.github.com/repos/LDVSOFT/assignments/forks","keys_url":"https://api.github.com/repos/LDVSOFT/assignments/keys{/key_id}","collaborators_url":"https://api.github.com/repos/LDVSOFT/assignments/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/LDVSOFT/assignments/teams","hooks_url":"https://api.github.com/repos/LDVSOFT/assignments/hooks","issue_events_url":"https://api.github.com/repos/LDVSOFT/assignments/issues/events{/number}","events_url":"https://api.github.com/repos/LDVSOFT/assignments/events","assignees_url":"https://api.github.com/repos/LDVSOFT/assignments/assignees{/user}","branches_url":"https://api.github.com/repos/LDVSOFT/assignments/branches{/branch}","tags_url":"https://api.github.com/repos/LDVSOFT/assignments/tags","blobs_url":"https://api.github.com/repos/LDVSOFT/assignments/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/LDVSOFT/assignments/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/LDVSOFT/assignments/git/refs{/sha}","trees_url":"https://api.github.com/repos/LDVSOFT/assignments/git/trees{/sha}","statuses_url":"https://api.github.com/repos/LDVSOFT/assignments/statuses/{sha}","languages_url":"https://api.github.com/repos/LDVSOFT/assignments/languages","stargazers_url":"https://api.github.com/repos/LDVSOFT/assignments/stargazers","contributors_url":"https://api.github.com/repos/LDVSOFT/assignments/contributors","subscribers_url":"https://api.github.com/repos/LDVSOFT/assignments/subscribers","subscription_url":"https://api.github.com/repos/LDVSOFT/assignments/subscription","commits_url":"https://api.github.com/repos/LDVSOFT/assignments/commits{/sha}","git_commits_url":"https://api.github.com/repos/LDVSOFT/assignments/git/commits{/sha}","comments_url":"https://api.github.com/repos/LDVSOFT/assignments/comments{/number}","issue_comment_url":"https://api.github.com/repos/LDVSOFT/assignments/issues/comments{/number}","contents_url":"https://api.github.com/repos/LDVSOFT/assignments/contents/{+path}","compare_url":"https://api.github.com/repos/LDVSOFT/assignments/compare/{base}...{head}","merges_url":"https://api.github.com/repos/LDVSOFT/assignments/merges","archive_url":"https://api.github.com/repos/LDVSOFT/assignments/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/LDVSOFT/assignments/downloads","issues_url":"https://api.github.com/repos/LDVSOFT/assignments/issues{/number}","pulls_url":"https://api.github.com/repos/LDVSOFT/assignments/pulls{/number}","milestones_url":"https://api.github.com/repos/LDVSOFT/assignments/milestones{/number}","notifications_url":"https://api.github.com/repos/LDVSOFT/assignments/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/LDVSOFT/assignments/labels{/name}","releases_url":"https://api.github.com/repos/LDVSOFT/assignments/releases{/id}","created_at":"2015-09-16T14:53:21Z","updated_at":"2015-09-15T08:01:56Z","pushed_at":"2015-11-16T22:20:26Z","git_url":"git://github.com/LDVSOFT/assignments.git","ssh_url":"git@github.com:LDVSOFT/assignments.git","clone_url":"https://github.com/LDVSOFT/assignments.git","svn_url":"https://github.com/LDVSOFT/assignments","homepage":"http://mit.spbau.ru/sewiki/index.php/Java_2_2015","size":102,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"java-course-au:03-game-server","ref":"03-game-server","sha":"1a409528799d45902314f8945b255a72b9a7b427","user":{"login":"java-course-au","id":14248092,"avatar_url":"https://avatars.githubusercontent.com/u/14248092?v=3","gravatar_id":"","url":"https://api.github.com/users/java-course-au","html_url":"https://github.com/java-course-au","followers_url":"https://api.github.com/users/java-course-au/followers","following_url":"https://api.github.com/users/java-course-au/following{/other_user}","gists_url":"https://api.github.com/users/java-course-au/gists{/gist_id}","starred_url":"https://api.github.com/users/java-course-au/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/java-course-au/subscriptions","organizations_url":"https://api.github.com/users/java-course-au/orgs","repos_url":"https://api.github.com/users/java-course-au/repos","events_url":"https://api.github.com/users/java-course-au/events{/privacy}","received_events_url":"https://api.github.com/users/java-course-au/received_events","type":"Organization","site_admin":false},"repo":{"id":42502722,"name":"assignments","full_name":"java-course-au/assignments","owner":{"login":"java-course-au","id":14248092,"avatar_url":"https://avatars.githubusercontent.com/u/14248092?v=3","gravatar_id":"","url":"https://api.github.com/users/java-course-au","html_url":"https://github.com/java-course-au","followers_url":"https://api.github.com/users/java-course-au/followers","following_url":"https://api.github.com/users/java-course-au/following{/other_user}","gists_url":"https://api.github.com/users/java-course-au/gists{/gist_id}","starred_url":"https://api.github.com/users/java-course-au/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/java-course-au/subscriptions","organizations_url":"https://api.github.com/users/java-course-au/orgs","repos_url":"https://api.github.com/users/java-course-au/repos","events_url":"https://api.github.com/users/java-course-au/events{/privacy}","received_events_url":"https://api.github.com/users/java-course-au/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/java-course-au/assignments","description":"Домашние задания по Java","fork":false,"url":"https://api.github.com/repos/java-course-au/assignments","forks_url":"https://api.github.com/repos/java-course-au/assignments/forks","keys_url":"https://api.github.com/repos/java-course-au/assignments/keys{/key_id}","collaborators_url":"https://api.github.com/repos/java-course-au/assignments/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/java-course-au/assignments/teams","hooks_url":"https://api.github.com/repos/java-course-au/assignments/hooks","issue_events_url":"https://api.github.com/repos/java-course-au/assignments/issues/events{/number}","events_url":"https://api.github.com/repos/java-course-au/assignments/events","assignees_url":"https://api.github.com/repos/java-course-au/assignments/assignees{/user}","branches_url":"https://api.github.com/repos/java-course-au/assignments/branches{/branch}","tags_url":"https://api.github.com/repos/java-course-au/assignments/tags","blobs_url":"https://api.github.com/repos/java-course-au/assignments/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/java-course-au/assignments/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/java-course-au/assignments/git/refs{/sha}","trees_url":"https://api.github.com/repos/java-course-au/assignments/git/trees{/sha}","statuses_url":"https://api.github.com/repos/java-course-au/assignments/statuses/{sha}","languages_url":"https://api.github.com/repos/java-course-au/assignments/languages","stargazers_url":"https://api.github.com/repos/java-course-au/assignments/stargazers","contributors_url":"https://api.github.com/repos/java-course-au/assignments/contributors","subscribers_url":"https://api.github.com/repos/java-course-au/assignments/subscribers","subscription_url":"https://api.github.com/repos/java-course-au/assignments/subscription","commits_url":"https://api.github.com/repos/java-course-au/assignments/commits{/sha}","git_commits_url":"https://api.github.com/repos/java-course-au/assignments/git/commits{/sha}","comments_url":"https://api.github.com/repos/java-course-au/assignments/comments{/number}","issue_comment_url":"https://api.github.com/repos/java-course-au/assignments/issues/comments{/number}","contents_url":"https://api.github.com/repos/java-course-au/assignments/contents/{+path}","compare_url":"https://api.github.com/repos/java-course-au/assignments/compare/{base}...{head}","merges_url":"https://api.github.com/repos/java-course-au/assignments/merges","archive_url":"https://api.github.com/repos/java-course-au/assignments/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/java-course-au/assignments/downloads","issues_url":"https://api.github.com/repos/java-course-au/assignments/issues{/number}","pulls_url":"https://api.github.com/repos/java-course-au/assignments/pulls{/number}","milestones_url":"https://api.github.com/repos/java-course-au/assignments/milestones{/number}","notifications_url":"https://api.github.com/repos/java-course-au/assignments/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/java-course-au/assignments/labels{/name}","releases_url":"https://api.github.com/repos/java-course-au/assignments/releases{/id}","created_at":"2015-09-15T07:36:54Z","updated_at":"2015-10-04T08:47:09Z","pushed_at":"2015-11-17T19:24:29Z","git_url":"git://github.com/java-course-au/assignments.git","ssh_url":"git@github.com:java-course-au/assignments.git","clone_url":"https://github.com/java-course-au/assignments.git","svn_url":"https://github.com/java-course-au/assignments","homepage":"http://mit.spbau.ru/sewiki/index.php/Java_2_2015","size":1239,"stargazers_count":2,"watchers_count":2,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":26,"mirror_url":null,"open_issues_count":10,"forks":26,"open_issues":10,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/java-course-au/assignments/pulls/74"},"html":{"href":"https://github.com/java-course-au/assignments/pull/74"},"issue":{"href":"https://api.github.com/repos/java-course-au/assignments/issues/74"},"comments":{"href":"https://api.github.com/repos/java-course-au/assignments/issues/74/comments"},"review_comments":{"href":"https://api.github.com/repos/java-course-au/assignments/pulls/74/comments"},"review_comment":{"href":"https://api.github.com/repos/java-course-au/assignments/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/java-course-au/assignments/pulls/74/commits"},"statuses":{"href":"https://api.github.com/repos/java-course-au/assignments/statuses/bc0a81ac57f1eb2d75fbde69cfdae5aa1c2b0f1f"}}}}