Note: The default ITS GitLab runner is a shared resource and is subject to slowdowns during heavy usage.
You can run your own GitLab runner that is dedicated just to your group if you need to avoid processing delays.

Commit d96e3816 authored by Keanu's avatar Keanu
Browse files

[ADD] Typing Game

parent 3b2ea7cd
elm-stuff
node_modules
.idea
dist
.DS_Store
MIT License
Copyright (c) 2017 Paulo Costa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# fastType
You need 80/wpm to win this game
You can play it here [http://paulombcosta.github.io/typing-speed-test/](http://paulombcosta.github.io/typing-speed-test/)
Here's an image of it in action:
![Project Image](/img/app.png)
/* This file is for your main application css. */
/*.root {*/
/*position: relative;*/
/*}*/
* {
box-sizing: border-box;
}
html, body, .app-container, #elm-container, #main {
height: 100%;
margin: 0;
padding: 0;
}
.root {
height: 100%;
margin: 0;
padding: 0;
display: flex;
align-items: center;
flex-direction: column;
}
.words-box {
margin-top: 0;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
}
p {
margin: 0;
padding: 0;
}
.stats-container {
width: 100%;
margin-top: 30px;
align-self: flex-start;
align-items: center;
justify-content: center;
display: flex;
flex-direction: column;
}
.metrics {
display: flex;
flex-direction: row;
}
.status-text {
font-size: 30px;
}
.metrics-text {
font-size: 30px;
margin-top: 10px;
}
.cpm {
margin-top: 20px;
margin-left: 50px;
font-size: 20px;
}
.wpm {
margin-top: 20px;
margin-right: 50px;
font-size: 20px;
}
.typing {
height: 285px;
max-width: 75%;
overflow: hidden;
background-color: white;
margin-top: 50px;
border: 2px solid #6A8BE3;
}
.countdown {
align-self: center;
}
.current-typed-chars {
margin-top: 10px;
font-size: 30px;
}
.word {
font-size: 40px;
float: left;
margin: 0px 8px 0px 8px;
}
.currentWord {
font-size: 40px;
float: left;
margin: 0px 8px -2px 8px;
border-bottom: 2px solid #6A8BE3;
}
.header-text {
align-self: flex-start;
padding-top: 15px;
padding-left: 10px;
color: #FFFFFF;
font-weight: 300;
word-spacing: 3px;
letter-spacing: 5px;
}
.restart {
background: none;
cursor: pointer;
border: none;
font-size: 18px;
padding-bottom: 18px;
padding-right: 10px;
align-self: flex-end;
margin-left: auto;
}
.restart:hover {
color: darkblue;
}
.restart:active {
color: white;
}
.header {
display: flex;
flex-direction: row;
height: 50px;
margin: 0;
width: 100%;
background-color: #6A8BE3;
}
/* This file is for your main application css. */
/*.root {*/
/*position: relative;*/
/*}*/
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html, body, .app-container, #elm-container, #main {
height: 100%;
margin: 0;
padding: 0;
}
.root {
height: 100%;
margin: 0;
padding: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.words-box {
margin-top: 0;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
}
p {
margin: 0;
padding: 0;
}
.stats-container {
width: 100%;
margin-top: 30px;
-ms-flex-item-align: start;
align-self: flex-start;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.metrics {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.status-text {
font-size: 30px;
}
.metrics-text {
font-size: 30px;
margin-top: 10px;
}
.cpm {
margin-top: 20px;
margin-left: 50px;
font-size: 20px;
}
.wpm {
margin-top: 20px;
margin-right: 50px;
font-size: 20px;
}
.typing {
height: 285px;
max-width: 75%;
overflow: hidden;
background-color: white;
margin-top: 50px;
border: 2px solid #6A8BE3;
}
.countdown {
-ms-flex-item-align: center;
align-self: center;
}
.current-typed-chars {
margin-top: 10px;
font-size: 30px;
}
.word {
font-size: 40px;
float: left;
margin: 0px 8px 0px 8px;
}
.currentWord {
font-size: 40px;
float: left;
margin: 0px 8px -2px 8px;
border-bottom: 2px solid #6A8BE3;
}
.header-text {
-ms-flex-item-align: start;
align-self: flex-start;
padding-top: 15px;
padding-left: 10px;
color: #FFFFFF;
font-weight: 300;
word-spacing: 3px;
letter-spacing: 5px;
}
.restart {
background: none;
cursor: pointer;
border: none;
font-size: 18px;
padding-bottom: 18px;
padding-right: 10px;
-ms-flex-item-align: end;
align-self: flex-end;
margin-left: auto;
}
.restart:hover {
color: darkblue;
}
.restart:active {
color: white;
}
.header {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
height: 50px;
margin: 0;
width: 100%;
background-color: #6A8BE3;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="app.css">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Elm Typing Test</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
This diff is collapsed.
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"src"
],
"exposed-modules": [],
"native-modules": true,
"dependencies": {
"elm-lang/core": "5.1.1 <= v < 6.0.0",
"elm-lang/dom": "1.1.1 <= v < 2.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"elm-lang/keyboard": "1.0.1 <= v < 2.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}
{
"name": "typing-test",
"version": "1.0.0",
"description": "Test your typing speed!",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch",
"dev": "webpack-dev-server --port 3000 --hot"
},
"author": "Paulo Costa",
"license": "MIT",
"devDependencies": {
"autoprefixer": "^7.1.1",
"css-loader": "^0.28.4",
"elm-hot-loader": "^0.5.4",
"elm-webpack-loader": "^4.3.1",
"extract-text-webpack-plugin": "^2.1.2",
"file-loader": "^0.11.2",
"loader-utils": "^1.1.0",
"postcss-import": "^10.0.0",
"postcss-loader": "^2.0.6",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"webpack-dev-server": "^2.5.0"
}
}
module.exports = {
plugins: [
require('autoprefixer')
]
}
\ No newline at end of file
module App exposing (..)
import State
import View
import Html
main =
Html.program
{ init = State.initialState
, view = View.view
, update = State.update
, subscriptions = State.subscriptions
}
module Bounds exposing (get, ClientRect, origin)
import Native.Bounds
import String
import Maybe
import Task exposing (Task)
type alias ClientRect =
{ bottom : Float
, height : Float
, left : Float
, right : Float
, top : Float
, width : Float
}
origin : ClientRect
origin =
{ bottom = 0, height = 0, left = 0, right = 0, top = 0, width = 0 }
get : String -> Task String (Maybe ClientRect)
get =
Native.Bounds.get
// import Maybe, Native.Scheduler //
var _user$project$Native_Bounds = function() {
function get(id) {
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) {
var elem = document.getElementById(id);
return callback(_elm_lang$core$Native_Scheduler.succeed(
(elem == null) ? _elm_lang$core$Maybe$Nothing : _elm_lang$core$Maybe$Just(elem.getBoundingClientRect())
));
});
}
return {
get: get
};
}();
module State exposing (..)
import Types exposing (..)
import List exposing (..)
import Keyboard
import Random exposing (Seed, initialSeed, step, int, list)
import Debug exposing (log, crash)
import Array exposing (Array, length, get, fromList, toList, push, set, indexedMap)
import Time exposing (now, inMilliseconds, Time, every, second)
import Task exposing (perform)
import Char exposing (fromCode)
import String exposing (fromChar)
import Types exposing (..)
import Bounds exposing (get, ClientRect, origin)
import Dom.Scroll exposing (toY)
import Words exposing (words)
spaceKey =
32
upperCaseA =
65
lowerCaseZ =
122
initialWordNumber =
100
lineHeight =
46
hardcodedWordRepository : Array String
hardcodedWordRepository =
fromList words
initialState : ( Model, Cmd Msg )
initialState =
( { evaluatedWords = []
, currentTypedChars = fromList []
, currentWords = fromList []
, applicationStatus = NotStarted
, currentPosition = 0
, currentSeed = initialSeed 0
, currentBound = Bounds.origin
, currentYScroll = 0
, lineScrollThreshold = 2
, lineScrollAcc = 0
, firstLineTyped = False
, timeLimitSeconds = 60
, timePassedSeconds = 0
, currentWPM = 0
, currentCPM = 0
}
, Cmd.batch [ timeForInitialSeed, scrollY 0 ]
)
timeForInitialSeed : Cmd Msg
timeForInitialSeed =
Task.perform TimeForInitialSeed Time.now
getBoundsTask : String -> Cmd Msg
getBoundsTask id =
Bounds.get id |> Task.attempt processBounds
processBounds : Result String (Maybe ClientRect) -> Msg
processBounds result =
case result of
Ok result ->
BoundsForElement result
Err _ ->
NoOp
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NoOp ->
( model, Cmd.none )
TimeForInitialSeed time ->
let
randomWordsAndSeed =
randomWords initialWordNumber (initialSeedFromTime time) []
wordList =
Tuple.first randomWordsAndSeed
resultingSeed =
Tuple.second randomWordsAndSeed
in
( { model | currentWords = fromList wordList, currentSeed = resultingSeed }, Cmd.none )
KeyTyped key ->
let
newModel =
{ model | applicationStatus = Started }
in
if (key >= upperCaseA && key <= lowerCaseZ) then
updateCurrentTypedWords key newModel
else if (key == spaceKey) then
updateWordStatus newModel
|> verifyNewWordsNeeded
|> wrapModelInCmd
else
( model, Cmd.none )
BoundsForElement maybeBounds ->
case maybeBounds of
Nothing ->
( model, Cmd.none )
Just bound ->
let
lineChanged =
checkLineChanged model.currentBound bound