Full Code of UpGado/ascii_racer for AI

master 36ab0185399d cached
17 files
20.6 KB
6.6k tokens
36 symbols
1 requests
Download .txt
Repository: UpGado/ascii_racer
Branch: master
Commit: 36ab0185399d
Files: 17
Total size: 20.6 KB

Directory structure:
gitextract_36pgqf48/

├── .gitignore
├── .replit
├── .travis.yml
├── LICENSE
├── README.md
├── asciiracer/
│   ├── __init__.py
│   ├── __main__.py
│   ├── ascii_factory.py
│   ├── config.py
│   ├── environment.py
│   ├── game.py
│   ├── hud.py
│   ├── mechanics.py
│   ├── misc.py
│   └── tests/
│       └── test_general.py
├── requirements.txt
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/


================================================
FILE: .replit
================================================
language = "python3"
run = "python -m asciiracer"


================================================
FILE: .travis.yml
================================================
language: python
python:
  - "3.6"
  - "3.7"
  - "nightly"
install:
  - pip install -r requirements.txt
  - pip install flake8
before_script:
  - flake8 .
script:
  - pytest
deploy:
  provider: pypi
  user: "UpGado"
  password:
    secure: bDLod+Mf1eV5e1uE39qtrjR3OCp5NlsnXa+GdhtbRi6tgkgb63foVAB/z0F2kKxzTHWgT6Zl+IIH9m4bZPvpblITKeLke16gG6s1qoXPkEIYInBTOYhJxe9noHvox6mD9dcffX3MZv5O0UOYnujOm0Mb7iIASJzInL8o54ALF0jar8/MLcJPVE+xGYIIgperUhgZPHcAEvpYUZTGsJ4EAHiTnPaq4cFw7FGf7KJJXKZ1aiuI0nu1xJFSvVwrCKd0S96y3+2+xe/DocHap7ZX8fau5CwtQ4CSbXew7dv+U2mYv3hdxxxZh0if10IgIn2iNrw6Tomps98XLuzm5aPDX7eKBeSJdwrZ6rDh/SUODOr34yGSZoXE3eUThqRaSsy+JGwUYleG4HlxiR/KhdD+H1avrnOMQavP9FY3g93BGmnvtBPfcHg6gn46gxV1Z9zOvSRjlDn0erQ/UEZtCiy6to8OoRdXudxYffhfNcv9MlWyR+jPB9wqmJbGdM3Ao0WHwLFYFUNo1Z1/38rnGQwtdErwTU41GsnEYhgKD1Z38NRKnXnseYtGDvy66dugI2ukkxc5LK1V8Hu6r6WHeObQdUlMBAGZ4GOli0YAh5zi8RXcW9FR8xVeeYOD8/p5T4RQh5QMBMsdmkalnPzYf783oPS0YE/Pp0yY1tG9UxjsND0=
  on:
    tags: true
    python: "3.7"
  distributions: "sdist bdist_wheel"


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Ahmed Gado

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.


================================================
FILE: README.md
================================================
```
                    _ _                           
     /\            (_(_)                          
    /  \   ___  ___ _ _   _ __ __ _  ___ ___ _ __ 
   / /\ \ / __|/ __| | | | '__/ _` |/ __/ _ | '__|
  / ____ \\__ | (__| | | | | | (_| | (_|  __| |   
 /_/    \_|___/\___|_|_| |_|  \__,_|\___\___|_|   
```                                              
                                                  



![PyPI](https://img.shields.io/pypi/v/asciiracer?color=success&label=pypi%20package)
[![Build Status](https://travis-ci.com/UpGado/ascii_racer.svg?branch=master)](https://travis-ci.com/UpGado/ascii_racer)
![GitHub last commit](https://img.shields.io/github/last-commit/UpGado/ascii_racer)
[![Downloads](https://pepy.tech/badge/asciiracer)](https://pepy.tech/project/asciiracer)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

An endless racing game that runs in the terminal. 100% Python.

<p align="center"><img src="https://raw.githubusercontent.com/UpGado/ascii_racer/master/docs/gameplay.gif" alt="ascii-racer"/></p>

## Instructions

Collect as many alcoholic drinks as possible, while avoiding the `Beer` drinks. The game is only key-based.

| Keys | Role        |
|------|-------------|
| a    | Move Left   |
| d    | Move Right  |
| w    | Accelerate  |
| s    |  Decelerate |
| q    |  Quit game  |

### Installation

> ```diff
> + Please report issues if you try to install and run into problems!
> ```

Make sure you are running at least Python 3.6.0

Install using pip:
```bash
pip3 install asciiracer
```
or clone the repository and install manually:

```bash
$ git clone https://github.com/UpGado/ascii_racer.git
$ cd ascii_racer && python3 setup.py install
```

### Start Game
To start the game, run either:
```bash
$ asciiracer
$ python -m asciiracer
```

### Scoring
There are four different types of drinks that you can collect on the racetrack. 
* Vodka - 10 Points
* Gin - 5 Points
* $ - 1 Point
* Beer - Negative 20 points

### Contributions

> ```diff
> + If you think this is cool, fork it and make it cooler!
> ```

This might be great practice if you want to learn Python, and you can personally reach out to me if you have any questions about the *simple but elegant* code base.

#### Possible Improvements

- Color support.
- Curvy roads and more interesting tracks.
- Multiplayer/Competitive racing.
- *Your* creative idea.

If you encounter any problem or have any suggestions, please [open an issue](https://github.com/UpGado/ascii_racer/issues/new) or [send a PR](https://github.com/UpGado/ascii_racer/pulls).


================================================
FILE: asciiracer/__init__.py
================================================


================================================
FILE: asciiracer/__main__.py
================================================
from . import game


def main():
    game.run()


main()


================================================
FILE: asciiracer/ascii_factory.py
================================================
# All digits are 6 characters wide and 4 high
nums = {
    0:     ['██████',
            '█    █',
            '█    █',
            '██████'],

    1:     ['   █  ',
            '   █  ',
            '   █  ',
            '   ▉  '],

    2:     ['██████',
            '     █',
            '██████',
            '█▄▄▄▄▄'],

    3:     ['██████',
            '     █',
            '▀▀▀▀▀█',
            '▄▄▄▄▄█'],

    4:     ['█    █',
            '█    █',
            '█▄▄▄▄█',
            '     █'],

    5:     ['██████',
            '█     ',
            '▀▀▀▀▀█',
            '▄▄▄▄▄█'],

    6:     ['█▀▀▀▀█',
            '█     ',
            '█▀▀▀▀█',
            '█▄▄▄▄█'],

    7:     ['██████',
            '   ▗█▛',
            '  ▟█▛ ',
            '▄██▛  '],

    8:     ['█▀▀▀▀█',
            '█    █',
            '█▀▀▀▀█',
            '█▄▄▄▄█'],

    9:     ['█▀▀▀▀█',
            '█▄▄▄▄█',
            '     █',
            '     █'],
}


def num2str(num):
    assert(0 <= num and num <= 99)
    r_digit = num % 10
    l_digit = (num - r_digit)/10
    l_digit, r_digit = [nums[_] for _ in [l_digit, r_digit]]
    string = []
    for l_line, r_line in zip(l_digit, r_digit):
        string.append(' '.join([l_line, r_line]))
    return string


================================================
FILE: asciiracer/config.py
================================================
from .misc import get_terminal_size

#
# Definitions:
# - [X]_STICKY_TIME: amount of time a key press of action [X]
#                    sticks in the game
GAME_SIZE = get_terminal_size()
FPS = 60

# Car movement
SPEED_INCREMENT = 1
SPEED_DECREMENT = -1
BASE_SPEED = 5
MAX_SPEED = 99
SPEED_STICKY_TIME = 0.2
STEERING_STICKY_TIME = 0.5
STEERING_STEP = 0.06

# Environment
HORIZON = 0.5  # how far from top?
TRACK_SLOPE = 0.7  # x = x0 - slope*y
DEBRIS_SPEED_MULTIPLIER = 1.0
MAX_NUM_DEBRIS = 20

# Cars
MAX_NUM_CARS = 4


================================================
FILE: asciiracer/environment.py
================================================
import random
from collections import namedtuple
from .config import HORIZON, TRACK_SLOPE, DEBRIS_SPEED_MULTIPLIER, \
                   MAX_NUM_DEBRIS
from .misc import linear_interpolate

Sprite = namedtuple('Sprite', ['attrs', 'current_coords'])


def init(screen):
    global width, height, horizon_y, left_track, right_track
    height, width = screen.getmaxyx()
    horizon_y = int(HORIZON*height)
    left_track = (int(3*width/16), '▞', TRACK_SLOPE)
    right_track = (int(13*width/16), '▚', -TRACK_SLOPE)


def in_range(y, x):
    return 0 <= y and y <= height - 1 and \
           0 <= x and x <= width - 1


def draw_background(screen, state):
    global width, height
    background = ' '
    for y in range(height):
        for x in range(width-1):
            screen.addstr(y, x, background)


def draw_statusbar(screen, state):
    status = '|'.join([f"Time: {state['time']:.2f} seconds",
                      f"Score: {state['score']}"])
    screen.addstr(0, 0, status)


def draw_tracks(screen, state):
    global left_track, right_track, height, horizon_y
    for (x0, character, slope) in [left_track, right_track]:
        for y in range(horizon_y, height):
            x = x0+int(slope*(height-1-y))
            if y <= horizon_y + 5:
                c = character
                character = '$'
            screen.addstr(y, x, character)
            if y <= horizon_y + 5:
                character = c


def spawn_debris(state, x_ranges):
    debris_list = [[u'/\\',
                    u'\\/'],
                   ['*'],
                   ['#']]
    return spawn_sprite(state, x_ranges, debris_list, DEBRIS_SPEED_MULTIPLIER)


def spawn_money(state, x_ranges):
    def martini_glass(ch):
        return [r'╲___╱',
                f" ╲{ch}╱ ",
                r'  ╿   ',
                r'  ┴  ']

    def beer_can():
        return [r'┌-/-┐',
                r'|   |',
                r'|BUD|',
                r'|   |',
                r'└---┘']

    def dollar_bill():
        return [r'     ',
                r'┌---┐',
                r'|$1$|',
                r'└---┘',
                r'     ']
    money_list = [(martini_glass('V'), 10),
                  (dollar_bill(), 1),
                  (martini_glass('G'), 5),
                  (beer_can(), -20),
                  (beer_can(), -20),
                  (beer_can(), -20)]
    return spawn_sprite(state, x_ranges, money_list, 1)


def spawn_sprite(state, x_ranges, sprites, speed_multiplier):
    sprite_design = random.choice(sprites)

    y0 = horizon_y
    x_range = random.choice(x_ranges)
    x0 = random.randint(*x_range)
    t0 = state['time']
    new_sprite = Sprite((sprite_design, y0, x0, t0, speed_multiplier),
                        None)
    return new_sprite


def draw_debris(screen, state):
    top_track_offset = int(horizon_y*TRACK_SLOPE) - 2
    x_ranges = [(0, left_track[0]+top_track_offset),
                (right_track[0]-top_track_offset, width-1)]
    draw_sprite(screen, state, 'debris', MAX_NUM_DEBRIS,
                x_ranges, spawn_debris)


def draw_money(screen, state):
    top_track_offset = int(horizon_y*TRACK_SLOPE) + 2
    x_ranges = [(left_track[0]+top_track_offset,
                right_track[0]-top_track_offset)]
    draw_sprite(screen, state, 'money', 1, x_ranges, spawn_money)


def draw_sprite(screen, state, key, max_num, x_ranges, spawn_func):
    num_missing_sprites = max_num - len(state[key])
    if num_missing_sprites > 0:
        for _ in range(num_missing_sprites):
            state[key].append(spawn_func(state, x_ranges))
    draw_parallax(state[key], screen, state)


def draw_parallax(sprites, screen, state):
    for s, sprite_tuple in enumerate(sprites):
        sprite, y0, x0, t0, speed_multiplier = sprite_tuple.attrs
        if type(sprite) is tuple:
            sprite_design = sprite[0]
        else:
            sprite_design = sprite
        speed = state['speed']*speed_multiplier
        step = parallax_slope(x0)
        y = y0 + int(speed*(state['time']-t0))
        x = x0 + int((y0-y)*step)
        if in_range(y+len(sprite_design), x):
            for i, line in enumerate(sprite_design):
                screen.addstr(y+i, x, line)
            sprites[s] = Sprite((sprite, y0, x0, t0, speed_multiplier),
                                ((y, y+i), (x, x+len(line))))
        else:
            sprites.remove(sprite_tuple)


def draw_horizon(screen, state):
    for x in range(width):
        screen.addstr(horizon_y, x, '-')


def draw_car(screen, state):
    car = [r'      ____________     ',
           r'     /            \    ',
           r'  ▉▉|      RrrrR   |▉▉  ',
           r'  ▉▉|  CA  R     R |▉▉  ',
           r'  ▉▉ \____________/ ▉▉   ']

    car_width = len(car[0])
    offset = 2  # offset from track
    x0 = left_track[0]+car_width/2+offset
    x1 = right_track[0]-car_width/2-offset
    car_center_x = linear_interpolate(-1, x0, 1, x1, state['car_x'])
    start_x = int(car_center_x - car_width / 2)
    for offset, line in enumerate(reversed(car)):
        y = height-1-offset
        x = start_x + len(line)
        screen.addstr(y, start_x, line)
    y_coords = (height-1-offset, height-1)
    x_coords = (start_x, x)
    state['car'] = Sprite(None, (y_coords, x_coords))


def parallax_slope(x0):
    # using top end of tracks as reference
    top_track_offset = int(horizon_y*TRACK_SLOPE)
    x_range = (left_track[0]+top_track_offset, right_track[0]-top_track_offset)
    return linear_interpolate(x_range[0], TRACK_SLOPE,
                              x_range[1], -TRACK_SLOPE, x0)


================================================
FILE: asciiracer/game.py
================================================
import curses
from . import environment
from .environment import draw_background, draw_tracks, draw_statusbar, \
                    draw_debris, draw_horizon, draw_car, draw_money
from . import hud
from .hud import draw_hud
from .mechanics import update_state
from .config import GAME_SIZE, FPS, BASE_SPEED
from .misc import limit_fps


SCENE = [draw_statusbar, draw_hud, draw_horizon, draw_tracks,
         draw_debris, draw_car, draw_money, draw_background]
state = {'frames': 0,
         'time': 0.0,  # seconds
         'speed': BASE_SPEED,  # coord per frame
         'car': None,
         'car_x': 0,  # range -1:1
         'car_steer_tuple': None,
         'car_speed_tuple': None,
         'debris': [],  # debris objects drawn in scene
         'money': [],  # money objects drawn in scene
         'score': 0,
         'pdb': False}  # for testing


@limit_fps(fps=FPS)
def draw_scene(screen):
    for draw_element in reversed(SCENE):
        draw_element(screen, state)
    screen.refresh()


def main(screen):
    screen.resize(*GAME_SIZE)
    screen.nodelay(True)
    environment.init(screen)
    hud.init(screen)
    while True:
        draw_scene(screen)
        key = screen.getch()
        if key == ord('q'):
            break
        elif key == ord('p'):
            state['pdb'] = True
        else:
            update_state(key, state)
        state['frames'] += 1
        state['time'] += 1/FPS
    screen.clear()
    screen.getkey()


def run():
    curses.wrapper(main)


================================================
FILE: asciiracer/hud.py
================================================
from .ascii_factory import num2str


def init(screen):
    global width, height
    height, width = screen.getmaxyx()


def draw_speedmeter(screen, state):
    margin_y, margin_x = 4, 4
    hud = ['▛▀▀▀▀▀▀▀▀▀▀▀▀▀▜',
           '▍             ▐',
           '▍             ▐',
           '▍             ▐',
           '▍             ▐',
           '▙▃▃▃▃▃▃▃▃▃▃▃▃▃▟',
           '▍     MPH     ▐',
           '▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀']
    hud_width = len(hud[0])
    speed = num2str(state['speed'])
    for l, (hud_line, speed_line) in enumerate(zip(hud[1:-1], speed)):
        hud[l+1] = hud_line[0] + speed_line + hud_line[-1]
    x0 = width - margin_x - hud_width
    y0 = margin_y
    for y, line in enumerate(hud):
        screen.addstr(y0+y, x0, line)


def draw_hud(screen, state):
    draw_speedmeter(screen, state)


================================================
FILE: asciiracer/mechanics.py
================================================
from .config import SPEED_INCREMENT, SPEED_DECREMENT, BASE_SPEED, \
                   STEERING_STEP, MAX_SPEED, \
                   STEERING_STICKY_TIME, SPEED_STICKY_TIME
from .misc import make_in_range, rectangle_overlap


def update_state(key, state):
    steer_tuple = state['car_steer_tuple']
    speed_tuple = state['car_speed_tuple']
    # respond to keys
    if key in {ord('w'), ord('s')}:
        direction = 1 if key == ord('w') else -1
        if speed_tuple is None or speed_tuple[1] != direction:
            state['car_speed_tuple'] = (state['time'], direction)
    elif key in {ord('d'), ord('a')}:
        direction = 1 if key == ord('d') else -1
        if steer_tuple is None or steer_tuple[1] != direction:
            state['car_steer_tuple'] = (state['time'], direction)
    elif key == -1:
        # no key pressed
        pass

    if steer_tuple is not None:
        update_steering(state, steer_tuple)

    if speed_tuple is not None:
        update_speed(state, speed_tuple)

    collect_money(state)


def collect_money(state):
    c_ys, c_xs = state['car'].current_coords
    for money_object in state['money']:
        ys, xs = money_object.current_coords
        if rectangle_overlap(*c_ys, *c_xs, *ys, *xs):
            (_, score), *args = money_object.attrs
            state['score'] += score
            state['money'].remove(money_object)


def update_steering(state, steer_tuple):
    t0, direction = steer_tuple
    elapsed_time = state['time'] - t0
    if elapsed_time > STEERING_STICKY_TIME:
        state['car_steer_tuple'] = None
    else:
        new_car_x = state['car_x'] + direction*STEERING_STEP
        state['car_x'] = make_in_range(new_car_x, -1, 1)


def update_speed(state, speed_tuple):
    t0, direction = speed_tuple
    if state['time'] - t0 > SPEED_STICKY_TIME:
        state['car_speed_tuple'] = None
    else:
        change = SPEED_INCREMENT if direction == 1 \
                                    else SPEED_DECREMENT
        new_car_speed = state['speed'] + change
        state['speed'] = make_in_range(new_car_speed,
                                       BASE_SPEED, MAX_SPEED)


================================================
FILE: asciiracer/misc.py
================================================
import time
from time import sleep
import os
import sys


def limit_fps(fps):
    delay = 1/fps

    def run_fps_capped(func):
        def run(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            elapsed_time = time.time() - start_time
            sleep_time = delay-elapsed_time
            if sleep_time >= 0:
                sleep(sleep_time)
        return run
    return run_fps_capped


def linear_interpolate(x1, y1, x2, y2, x3):
    y3 = y1 + (x3-x1)*(y2-y1)/(x2-x1)
    return y3


def make_in_range(x, x_min, x_max):
    x = min(x, x_max)
    x = max(x_min, x)
    return x


def rectangle_overlap(r1_y1, r1_y2, r1_x1, r1_x2,
                      r2_y1, r2_y2, r2_x1, r2_x2):
    if r2_x2 < r1_x1 or r2_x1 > r1_x2:
        return False
    elif r2_y2 < r1_y1 or r2_y1 > r1_y2:
        return False
    else:
        return True


def get_terminal_size():
    if sys.platform == 'win32':
        return _get_terminal_size_windows()
    else:
        return _get_terminal_size_unix()


def _get_terminal_size_windows():
    # http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/
    from ctypes import windll, create_string_buffer

    # stdin handle is -10
    # stdout handle is -11
    # stderr handle is -12

    h = windll.kernel32.GetStdHandle(-12)
    csbi = create_string_buffer(22)
    res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)

    if res:
        import struct
        (_, _, _, _, _, left, top, right, bottom,
         *_) = struct.unpack("hhhhHhhhhhh", csbi.raw)
        sizex = right - left + 1
        sizey = bottom - top + 1
    else:
        sizex, sizey = 80, 25  # can't determine actual size
    return (sizey, sizex)


def _get_terminal_size_unix():
    return tuple(int(i) for i in os.popen('stty size', 'r').read().split())


================================================
FILE: asciiracer/tests/test_general.py
================================================
def func(x):
    return x + 1


def test_answer():
    assert func(3) == 4


================================================
FILE: requirements.txt
================================================


================================================
FILE: setup.py
================================================
import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name='asciiracer',
    version='1.0.3',
    python_requires='>=3.6.0',
    author='Ahmed Gado',
    author_email='ahmedehabg@gmail.com',
    description='A racing game that runs in terminal',
    long_description=long_description,
    long_description_content_type="text/markdown",
    url='https://github.com/UpGado/ascii_racer',
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    entry_points={
        'console_scripts': [
            'asciiracer = asciiracer.__main__:main'
        ]
    },
    install_requires=[
        'windows-curses >= 2.0;platform_system=="Windows"'
    ]
)
Download .txt
gitextract_36pgqf48/

├── .gitignore
├── .replit
├── .travis.yml
├── LICENSE
├── README.md
├── asciiracer/
│   ├── __init__.py
│   ├── __main__.py
│   ├── ascii_factory.py
│   ├── config.py
│   ├── environment.py
│   ├── game.py
│   ├── hud.py
│   ├── mechanics.py
│   ├── misc.py
│   └── tests/
│       └── test_general.py
├── requirements.txt
└── setup.py
Download .txt
SYMBOL INDEX (36 symbols across 8 files)

FILE: asciiracer/__main__.py
  function main (line 4) | def main():

FILE: asciiracer/ascii_factory.py
  function num2str (line 55) | def num2str(num):

FILE: asciiracer/environment.py
  function init (line 10) | def init(screen):
  function in_range (line 18) | def in_range(y, x):
  function draw_background (line 23) | def draw_background(screen, state):
  function draw_statusbar (line 31) | def draw_statusbar(screen, state):
  function draw_tracks (line 37) | def draw_tracks(screen, state):
  function spawn_debris (line 50) | def spawn_debris(state, x_ranges):
  function spawn_money (line 58) | def spawn_money(state, x_ranges):
  function spawn_sprite (line 87) | def spawn_sprite(state, x_ranges, sprites, speed_multiplier):
  function draw_debris (line 99) | def draw_debris(screen, state):
  function draw_money (line 107) | def draw_money(screen, state):
  function draw_sprite (line 114) | def draw_sprite(screen, state, key, max_num, x_ranges, spawn_func):
  function draw_parallax (line 122) | def draw_parallax(sprites, screen, state):
  function draw_horizon (line 142) | def draw_horizon(screen, state):
  function draw_car (line 147) | def draw_car(screen, state):
  function parallax_slope (line 169) | def parallax_slope(x0):

FILE: asciiracer/game.py
  function draw_scene (line 28) | def draw_scene(screen):
  function main (line 34) | def main(screen):
  function run (line 54) | def run():

FILE: asciiracer/hud.py
  function init (line 4) | def init(screen):
  function draw_speedmeter (line 9) | def draw_speedmeter(screen, state):
  function draw_hud (line 29) | def draw_hud(screen, state):

FILE: asciiracer/mechanics.py
  function update_state (line 7) | def update_state(key, state):
  function collect_money (line 32) | def collect_money(state):
  function update_steering (line 42) | def update_steering(state, steer_tuple):
  function update_speed (line 52) | def update_speed(state, speed_tuple):

FILE: asciiracer/misc.py
  function limit_fps (line 7) | def limit_fps(fps):
  function linear_interpolate (line 22) | def linear_interpolate(x1, y1, x2, y2, x3):
  function make_in_range (line 27) | def make_in_range(x, x_min, x_max):
  function rectangle_overlap (line 33) | def rectangle_overlap(r1_y1, r1_y2, r1_x1, r1_x2,
  function get_terminal_size (line 43) | def get_terminal_size():
  function _get_terminal_size_windows (line 50) | def _get_terminal_size_windows():
  function _get_terminal_size_unix (line 73) | def _get_terminal_size_unix():

FILE: asciiracer/tests/test_general.py
  function func (line 1) | def func(x):
  function test_answer (line 5) | def test_answer():
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (23K chars).
[
  {
    "path": ".gitignore",
    "chars": 1713,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": ".replit",
    "chars": 50,
    "preview": "language = \"python3\"\nrun = \"python -m asciiracer\"\n"
  },
  {
    "path": ".travis.yml",
    "chars": 1001,
    "preview": "language: python\npython:\n  - \"3.6\"\n  - \"3.7\"\n  - \"nightly\"\ninstall:\n  - pip install -r requirements.txt\n  - pip install "
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2019 Ahmed Gado\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 2615,
    "preview": "```\n                    _ _                           \n     /\\            (_(_)                          \n    /  \\   ___"
  },
  {
    "path": "asciiracer/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "asciiracer/__main__.py",
    "chars": 57,
    "preview": "from . import game\n\n\ndef main():\n    game.run()\n\n\nmain()\n"
  },
  {
    "path": "asciiracer/ascii_factory.py",
    "chars": 1261,
    "preview": "# All digits are 6 characters wide and 4 high\nnums = {\n    0:     ['██████',\n            '█    █',\n            '█    █',"
  },
  {
    "path": "asciiracer/config.py",
    "chars": 519,
    "preview": "from .misc import get_terminal_size\n\n#\n# Definitions:\n# - [X]_STICKY_TIME: amount of time a key press of action [X]\n#   "
  },
  {
    "path": "asciiracer/environment.py",
    "chars": 5580,
    "preview": "import random\nfrom collections import namedtuple\nfrom .config import HORIZON, TRACK_SLOPE, DEBRIS_SPEED_MULTIPLIER, \\\n  "
  },
  {
    "path": "asciiracer/game.py",
    "chars": 1496,
    "preview": "import curses\nfrom . import environment\nfrom .environment import draw_background, draw_tracks, draw_statusbar, \\\n       "
  },
  {
    "path": "asciiracer/hud.py",
    "chars": 815,
    "preview": "from .ascii_factory import num2str\n\n\ndef init(screen):\n    global width, height\n    height, width = screen.getmaxyx()\n\n\n"
  },
  {
    "path": "asciiracer/mechanics.py",
    "chars": 2145,
    "preview": "from .config import SPEED_INCREMENT, SPEED_DECREMENT, BASE_SPEED, \\\n                   STEERING_STEP, MAX_SPEED, \\\n     "
  },
  {
    "path": "asciiracer/misc.py",
    "chars": 1856,
    "preview": "import time\nfrom time import sleep\nimport os\nimport sys\n\n\ndef limit_fps(fps):\n    delay = 1/fps\n\n    def run_fps_capped("
  },
  {
    "path": "asciiracer/tests/test_general.py",
    "chars": 75,
    "preview": "def func(x):\n    return x + 1\n\n\ndef test_answer():\n    assert func(3) == 4\n"
  },
  {
    "path": "requirements.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "setup.py",
    "chars": 857,
    "preview": "import setuptools\n\nwith open(\"README.md\", \"r\") as fh:\n    long_description = fh.read()\n\nsetuptools.setup(\n    name='asci"
  }
]

About this extraction

This page contains the full source code of the UpGado/ascii_racer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 17 files (20.6 KB), approximately 6.6k tokens, and a symbol index with 36 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!