├── guitar.png ├── screenshot.png ├── scores.txt ├── requirements.txt ├── LICENSE ├── README.md └── game.py /guitar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlitzKraft/vimDDR/HEAD/guitar.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlitzKraft/vimDDR/HEAD/screenshot.png -------------------------------------------------------------------------------- /scores.txt: -------------------------------------------------------------------------------- 1 | User Score Accu Streak Duration Achieved on 2 | ------------------------------------------------------------------- 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | astroid==1.6.3 2 | colorama==0.3.9 3 | getch==1.0 4 | isort==4.3.4 5 | lazy-object-proxy==1.3.1 6 | mccabe==0.6.1 7 | pylint==1.8.4 8 | six==1.11.0 9 | wrapt==1.10.11 10 | # For windows use msvcrt 11 | # msvcrt 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 BlitzKraft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![saythanks](https://img.shields.io/badge/say-thanks-ff69b4.svg)](https://saythanks.io/to/BlitzKraft) 2 | ## NEW!! Guitar-hero like option `gtro` and `gtr` 3 | ![Default mode](./guitar.png?raw=true "No options given") 4 | * `gtr` shows the strings and HJKL keys. 5 | * `gtro` shows the strings with "O" for buttons 6 | * Colors!! 7 | 8 | ### Just a little fun exercise for vim practice 9 | * Runs within the terminal. Keeps score along the way. 10 | * No install required! 11 | * Test your reflexes! 12 | * ... and accuracy 13 | * Keeps log of scores and accuracy. 14 | * Now with windows support (testing required, \*nixers needn't panic, it's all the same for you) 15 | * Default is unicode arrows. If your terminal doesn't support that, there are two other options you can try 16 | * Try the other options anyway. They are fun too. 17 | 18 | #### Dependencies 19 | * getch - pypi package 20 | * python3 21 | * msvcrt (windows only) 22 | 23 | #### Features 24 | * Keeps score 25 | * Logs score and accuracy 26 | * Gets longest streak and logs it too! 27 | 28 | ### Screenshot 29 | ![Default mode](./screenshot.png?raw=true "No options given") 30 | 31 | #### Usage 32 | * Clone the repo 33 | * `cd` to the directory 34 | * `./game.py [ fallback | giant ] [ inf ]` optional args 35 | * `./game.py help` to see the above line again 36 | * Enjoy 37 | 38 | #### Game modes 39 | * `fallback` 40 | For terminals/emulators that don't support unicode but still one line per move 41 | * `giant` 42 | Each arrow is four lines in height. Composed of slashes and backslashes. 43 | * `inf` 44 | infinite game. 'q' to quit. Keeps track of score and accuracy ( percentage ) 45 | 46 | #### Todo 47 | - [x] Use figlet/toilet for larger display (~~has known bug #1~~ fixed) 48 | - [x] Fall back mode when unicode is not supported 49 | - [x] Also track time along with score 50 | - [x] Calculate speed 51 | - [x] Accept command line options for fallback and giant mode 52 | - [x] More forgiving, and show hearts to keep track of mistakes 53 | - [x] Log score 54 | - [x] Get longest streak 55 | - [ ] Make it installable via pip. 56 | 57 | #### Feel free to fork and give a star if you enjoy it! Thanks!! 58 | -------------------------------------------------------------------------------- /game.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | """ 3 | # For best results use source code pro 4 | # Arrows 5 | # "←..↑..↓..→" 6 | """ 7 | 8 | import datetime 9 | import random 10 | import getpass 11 | #Stupid windows # <- I agree... 12 | try: 13 | import msvcrt 14 | except ImportError: 15 | import getch 16 | msvcrt = getch 17 | import time 18 | import sys 19 | 20 | 21 | try: 22 | MODE = sys.argv 23 | except IndexError: 24 | MODE = 'default' 25 | 26 | class GameEnv(): # pylint: disable=too-many-instance-attributes, too-few-public-methods 27 | """ 28 | Start up variables 29 | """ 30 | score = 0 31 | accu = 0 32 | hearts = 3 33 | streak = 0 34 | long_streak = 0 35 | fallback = False 36 | giant = False 37 | g = False 38 | gtr = False 39 | gtro = False 40 | 41 | GAME_SETTINGS = GameEnv() 42 | 43 | def game(): 44 | """ 45 | Game logic 46 | """ 47 | if 'help' in MODE: 48 | print("Usage: ./game.py [ fallback | giant ] [ g ] ") 49 | print("See README for more details.") 50 | sys.exit() 51 | 52 | total = 0 53 | if 'g' in MODE: 54 | GAME_SETTINGS.g = True # pylint: disable=invalid-name 55 | GAME_SETTINGS.hearts = 0 56 | if 'fallback' in MODE: 57 | GAME_SETTINGS.fallback = True 58 | elif 'giant' in MODE: 59 | GAME_SETTINGS.giant = True 60 | elif 'gtr' in MODE: 61 | GAME_SETTINGS.gtr = True 62 | elif 'gtro' in MODE: 63 | GAME_SETTINGS.gtro = True 64 | 65 | heart = " ❤" 66 | start = time.time() 67 | while True: 68 | direction = random.choice(['h', 'j', 'k', 'l']) 69 | ddr(direction, GAME_SETTINGS.hearts, heart) 70 | char = msvcrt.getch().lower() 71 | total = total + 1 72 | if char == 'q': 73 | break 74 | elif char != direction: 75 | GAME_SETTINGS.long_streak = max(GAME_SETTINGS.streak, GAME_SETTINGS.long_streak) 76 | GAME_SETTINGS.streak = 0 77 | GAME_SETTINGS.hearts = GAME_SETTINGS.hearts - 1 78 | if GAME_SETTINGS.hearts == 0: 79 | break 80 | else: 81 | GAME_SETTINGS.streak = GAME_SETTINGS.streak + 1 82 | GAME_SETTINGS.score = GAME_SETTINGS.score + 1 83 | 84 | end = time.time() 85 | time_completion = round(end - start, 2) 86 | date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 87 | user = getpass.getuser() 88 | GAME_SETTINGS.accu = str(round(GAME_SETTINGS.score * 100/total, 2))+ '%' 89 | record_scores(user, date, GAME_SETTINGS.accu, GAME_SETTINGS.score, GAME_SETTINGS.long_streak) 90 | print("Time : ", str(time_completion)+"s") 91 | print("Accu : ", GAME_SETTINGS.accu, "(", GAME_SETTINGS.score, "of", total, ")") 92 | print("Speed: ", round(GAME_SETTINGS.score/time_completion, 2), "strokes/sec") 93 | print("Longest streak: ", GAME_SETTINGS.long_streak) 94 | 95 | def record_scores(user, date, accu, score, long_streak): 96 | """ 97 | Score is recorded to scores.txt 98 | """ 99 | outstr = "\t".join([user, str(score), accu, str(long_streak), str(time) + "s\t", date]) 100 | with open("scores.txt", "a") as score_file: 101 | score_file.write(outstr + "\n") 102 | 103 | def gethearts(num, heart): 104 | """ 105 | Hearts are managed here 106 | """ 107 | heart_count = "" 108 | while num > 0: 109 | heart_count = heart_count + heart 110 | num = num - 1 111 | return heart_count 112 | 113 | def ddr(dirn, hearts, heart): 114 | """ 115 | DDR is printed here 116 | """ 117 | left = "← " 118 | down = " ↓ " 119 | up_up = " ↑ " 120 | right = " →" 121 | heart = " ❤" 122 | 123 | if GAME_SETTINGS.fallback: 124 | left = "< " 125 | down = " v " 126 | up_up = " ^ " 127 | right = " > " 128 | heart = " <3" 129 | 130 | if GAME_SETTINGS.giant: 131 | left = " /\n /\n \\\n \\ " 132 | down = " \\ /\n \\ /\n \\ /\n \\/ " 133 | up_up = " /\\\n / \\\n / \\\n / \\ " 134 | right = " \\\n \\\n /\n / " 135 | heart = "<3 " 136 | 137 | if GAME_SETTINGS.gtr: 138 | left = "\033[1;31;49mH\033[1;30m | | | " 139 | down = "| \033[1;32;49mJ\033[1;30m | | " 140 | up_up = "| | \033[1;33;49mK\033[1;30m | " 141 | right = "| | | \033[1;34;49mL\033[1;30m " 142 | heart = " <3" 143 | 144 | 145 | if GAME_SETTINGS.gtro: 146 | left = "\033[1;31;49mO\033[1;30m | | | " 147 | down = "| \033[1;32;49mO\033[1;30m | | " 148 | up_up = "| | \033[1;33;49mO\033[1;30m | " 149 | right = "| | | \033[1;34;49mO\033[1;30m " 150 | heart = " <3" 151 | 152 | 153 | if dirn == 'h': 154 | print(left+ gethearts(hearts, heart)) 155 | elif dirn == 'j': 156 | print(down+ gethearts(hearts, heart)) 157 | elif dirn == 'k': 158 | print(up_up + gethearts(hearts, heart)) 159 | elif dirn == 'l': 160 | print(right + gethearts(hearts, heart)) 161 | 162 | 163 | 164 | if __name__ == "__main__": 165 | game() 166 | --------------------------------------------------------------------------------