from flask import Flask, render_template, request, jsonify, session from flask_socketio import SocketIO, emit, join_room, leave_room import os import random import json from datetime import datetime from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(24) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///typing_game.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False socketio = SocketIO(app) db = SQLAlchemy(app) # Модель для хранения результатов игроков class GameResult(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(50), nullable=False) wpm = db.Column(db.Float, nullable=False) # скорость в словах в минуту accuracy = db.Column(db.Float, nullable=False) # точность в процентах date = db.Column(db.DateTime, default=datetime.utcnow) # Создание базы данных with app.app_context(): db.create_all() # Тексты для набора typing_texts = [ "Быстрый набор текста - это навык, который может значительно повысить вашу продуктивность.", "Практика ежедневного набора текста поможет вам стать быстрее и точнее.", "Хороший наборщик текста может печатать, не глядя на клавиатуру.", "Скорость набора измеряется в количестве слов в минуту.", "Точность набора так же важна, как и скорость.", "Регулярные тренировки помогут вам улучшить навыки набора текста.", "Все счастливые семьи похожи друг на друга, каждая несчастливая семья несчастлива по-своему. Все смешалось в доме Облонских.", "Мой дядя самых честных правил, когда не в шутку занемог, он уважать себя заставил и лучше выдумать не мог.", "В начале было Слово, и Слово было у Бога, и Слово было Бог. Оно было в начале у Бога. Все чрез Него начало быть, и без Него ничто не начало быть, что начало быть.", "Двадцать лет назад никто не слыхал о капитане Немо, а теперь все знают, что он существует. Точно так же и я, профессор Пьер Аронакс, единственный спутник капитана Немо, расскажу вам то, что до сих пор было скрыто.", "Над всем этим возвышался громадный замок с высокими башнями, с длинными флюгерами, развевающимися по ветру. Он был окружен глубоким рвом с водой, в которой плавали дикие лебеди и росли красивейшие тростники.", "Человек, который смеется, не всегда смеется от радости. Иногда он смеется от горя, от отчаяния, от ненависти. Смех бывает разный.", "Все мы родом из детства. Но не все помнят об этом. Взрослые забывают, что когда-то были детьми. А я помню.", "Мы все глядим в Наполеоны; двуногих тварей миллионы для нас орудие одно; нам чувство дико и смешно.", "Я памятник себе воздвиг нерукотворный, к нему не зарастет народная тропа, вознесся выше он главою непокорной Александрийского столпа.", "Тот, кто не помнит своего прошлого, обречен на то, чтобы пережить его вновь. История учит лишь тому, что она никогда ничему не научила народы.", "Мой дом - моя крепость. Но даже крепость можно взять штурмом, если найти в ней слабое место. Поэтому я всегда начеку.", "Время - самая большая ценность, которая у нас есть. Его нельзя вернуть, его нельзя накопить, его можно только потратить. И от того, как мы его тратим, зависит наша жизнь.", "Книги - корабли мысли, странствующие по волнам времени и бережно несущие свой драгоценный груз от поколения к поколению.", "Жизнь - это то, что с тобой происходит, пока ты строишь планы на будущее. Не откладывай на завтра то, что можно сделать сегодня.", "Утро туманное, утро седое, нивы печальные, снегом покрытые. Нехотя вспомнишь и время былое, вспомнишь и лица, давно позабытые.", "Я пришел к тебе с приветом, рассказать, что солнце встало, что оно горячим светом по листам затрепетало.", "Мороз и солнце; день чудесный! Еще ты дремлешь, друг прелестный - пора, красавица, проснись: открой сомкнуты негой взоры навстречу северной Авроры, звездою севера явись!", "Белеет парус одинокий в тумане моря голубом. Что ищет он в стране далекой? Что кинул он в краю родном?", "Люблю грозу в начале мая, когда весенний, первый гром, как бы резвяся и играя, грохочет в небе голубом.", "Однажды в студеную зимнюю пору я из лесу вышел; был сильный мороз. Гляжу, поднимается медленно в гору лошадка, везущая хворосту воз.", "Ночь, улица, фонарь, аптека, бессмысленный и тусклый свет. Живи еще хоть четверть века - все будет так. Исхода нет.", "Я вас любил: любовь еще, быть может, в душе моей угасла не совсем; но пусть она вас больше не тревожит; я не хочу печалить вас ничем.", "Я помню чудное мгновенье: передо мной явилась ты, как мимолетное виденье, как гений чистой красоты.", "Мой первый друг, мой друг бесценный! И я судьбу благословил, когда мой двор уединенный, печальным снегом занесенный, твой колокольчик огласил.", # Дополнительные фрагменты из русской классической литературы "Герой нашего времени, милостивые государи мои, точно портрет, но не одного человека: это портрет, составленный из пороков всего нашего поколения, в полном их развитии.", "Чичиков подъехал к дому, который был ни мал, ни велик, но опрятен и прочен. Две русские избы, перенесенные сюда бревно в бревно, заменили флигеля.", "Тарас Бульба остановился перед крыльцом и увидел жену свою, которая только что успела его обнять, как уже вскрикнула, вглядываясь в него пристально.", "Старик Хоттабыч сидел на диване, поджав под себя ноги, и с упоением читал какую-то толстую книгу. Он был в своем любимом белом костюме и красной феске.", "Вечера на хуторе близ Диканьки. Как упоителен, как роскошен летний день в Малороссии! Как томительно жарки те часы, когда полдень блещет в тишине и зное!", "Капитанская дочка. Отец мой Андрей Петрович Гринев в молодости своей служил при графе Минихе и вышел в отставку премьер-майором в 17.. году.", "Война и мир. Ну, князь, Генуя и Лукка стали не больше, как поместьями фамилии Бонапарте. Нет, я вам вперед говорю, если вы мне не скажете, что у нас война, если вы еще позволите себе защищать все гадости, все ужасы этого антихриста (право, я верю, что он антихрист), — я вас больше не знаю, вы уж не друг мой, вы уж не мой верный раб, как вы говорите.", "Преступление и наказание. В начале июля, в чрезвычайно жаркое время, под вечер, один молодой человек вышел из своей каморки, которую нанимал от жильцов в С-м переулке, на улицу и медленно, как бы в нерешимости, отправился к К-ну мосту.", "Идиот. В конце ноября, в оттепель, часов в девять утра, поезд Петербургско-Варшавской железной дороги на всех парах подходил к Петербургу. Было так сыро и туманно, что насилу рассвело.", "Мастер и Маргарита. Однажды весною, в час небывало жаркого заката, в Москве, на Патриарших прудах, появились два гражданина. Первый из них, одетый в летнюю серенькую пару, был маленького роста, упитан, лыс, свою приличную шляпу пирожком нес в руке, а на хорошо выбритом лице его помещались сверхъестественных размеров очки в черной роговой оправе.", "Собачье сердце. На обоях золотые корзины, букеты роз, над ними вьются голубые птички. На высоком узком камине прислонен к стене кремовый пастушок. Перед камином на стеклянном столике лежат раскрытая громадная книга с пестрыми картинками и мертвая птица с распущенным хвостом.", "Тихий Дон. Мелеховский двор - на самом краю хутора. Воротца со скотиньего база ведут на север к Дону. Крутой восьмисаженный спуск меж замшелых в прозелени меловых глыб, и вот берег: перламутровая россыпь ракушек, серая изломистая кайма нацелованной волнами гальки и дальше - перекипающее под ветром вороненой рябью стремя Дона.", "Обломов. В Гороховой улице, в одном из больших домов, народонаселения которого стало бы на целый уездный город, лежал утром в постели, на своей квартире, Илья Ильич Обломов.", "Отцы и дети. - Что, Петр, не видать еще? - спрашивал 20 мая 1859 года, выходя без шапки на низкое крылечко постоялого двора на *** шоссе, барин лет сорока с небольшим, в запыленном пальто и клетчатых панталонах, у своего слуги, молодого и щекастого малого с беловатым пухом на подбородке и маленькими тусклыми глазенками.", "Анна Каренина. Степан Аркадьич Облонский - Стива, как его звали в свете, - проснулся в обычный час, то есть в восемь часов утра, не в спальне жены, а в своем кабинете, на сафьянном диване.", "Евгений Онегин. Мой брат двоюродный, Буянов, в пуху, в картузе с козырьком (Как вам, конечно, он знаком), явился; мой поэт, Буянов мне друг и родственник.", "Горе от ума. Чацкий. Ну вот и день прошел, и с ним все призраки, весь чад и дым надежд, насмешливых речей, невыполнимых планов, загадок и сомнений... Какое-то волненье в крови, а голове пустота.", "Вишневый сад. Любовь Андреевна. Детская, милая моя, прекрасная комната... Я тут спала, когда была маленькой... И вот я как маленькая... А я родилась здесь, тут прошло мое детство, моя юность.", "Ревизор. Городничий. Я пригласил вас, господа, с тем, чтобы сообщить вам пренеприятное известие: к нам едет ревизор.", "Мертвые души. Чичиков. Эх, русский народец! Не любит умирать своею смертью!", # Фрагменты из зарубежной литературы "Гамлет. Быть или не быть - вот в чем вопрос. Достойно ль смиряться под ударами судьбы, иль надо оказать сопротивленье и в смертной схватке с целым морем бед покончить с ними?", "Ромео и Джульетта. Но мягче свет! Что за краса в окне? То свет зари, и солнце - Джульетта! Встань, ясная заря, убей луну-завистницу: она и без того больна и зелена от горя, что ты ее прекрасней во сто крат.", "Дон Кихот. В некоем селе Ламанчском, которого название у меня нет охоты припоминать, не так давно жил-был один из тех идальго, чье имущество заключается в фамильном копье, древнем щите, тощей кляче и борзой собаке.", "Три мушкетера. В первый понедельник апреля 1625 года все население городка Менга, где некогда родился автор «Романа о розе», казалось взволнованным так, словно гугеноты собирались превратить его во вторую Ла-Рошель.", "Граф Монте-Кристо. 24 февраля 1815 года дозорный Нотр-Дам де-ла-Гард дал знать о приближении трехмачтового корабля «Фараон», идущего из Смирны, Триеста и Неаполя.", "Гордость и предубеждение. Все знают, что молодой человек, располагающий средствами, должен подыскивать себе жену.", "Джейн Эйр. В тот день нельзя было и думать о прогулке. Правда, утром мы еще бродили часок по дорожкам облетевшего сада, но после обеда холодный зимний ветер нагнал угрюмые тучи и полил такой пронизывающий дождь, что и речи не могло быть ни о какой попытке выйти еще раз.", "Портрет Дориана Грея. Густой аромат роз наполнял мастерскую художника, а когда в саду поднимался летний ветерок, он, влетая в открытую дверь, приносил с собой то пьянящий запах сирени, то нежное благоухание алых цветов шиповника.", "Алиса в Стране чудес. Алисе наскучило сидеть с сестрой без дела на берегу реки; разок-другой она заглянула в книжку, которую читала сестра, но там не было ни картинок, ни разговоров. «Что толку в книжке, – подумала Алиса, – если в ней нет ни картинок, ни разговоров?»", "Маленький принц. Когда мне было шесть лет, в книге под названием «Правдивые истории», где рассказывалось про девственные леса, я увидел однажды удивительную картинку.", "Властелин колец. Когда господин Бильбо Бэггинс из Бэг-Энда объявил, что скоро отпразднует свое стоодиннадцатилетие весьма пышным угощением, весь Хоббитон загудел и заволновался.", "Гарри Поттер и философский камень. Мистер и миссис Дурсль проживали в доме номер четыре по Тисовой улице и всегда с гордостью заявляли, что они, слава богу, абсолютно нормальные люди.", "Хоббит, или Туда и обратно. В земле была нора, а в норе жил хоббит. Не мерзкая грязная сырая нора, где со всех сторон торчат хвосты червей и противно пахнет тиной, но и не сухая песчаная голая нора, где не на что сесть и нечего съесть.", "Шерлок Холмс. Для Шерлока Холмса она всегда оставалась «той женщиной». Я редко слышал, чтобы он называл ее каким-либо другим именем. В его глазах она затмевала всех представительниц своего пола.", "Великий Гэтсби. В юные и ранимые годы отец дал мне совет, который с тех пор не выходит у меня из головы. «Если тебе вдруг захочется осудить кого-то, – сказал он, – вспомни, что не все люди на свете обладают теми преимуществами, которыми обладал ты».", "Над пропастью во ржи. Если вам на самом деле хочется услышать эту историю, вы, наверное, прежде всего захотите узнать, где я родился, как провел свое дурацкое детство, что делали мои родители до моего рождения, – словом, всю эту давид-копперфилдовскую муть.", "Сто лет одиночества. Много лет спустя, перед самым расстрелом, полковник Аурелиано Буэндиа вспомнит тот далекий день, когда отец повел его поглядеть на лед.", "1984. Был холодный ясный апрельский день, и часы пробили тринадцать. Уткнув подбородок в грудь, чтобы спастись от злого ветра, Уинстон Смит торопливо шмыгнул за стеклянную дверь жилого дома «Победа», но все-таки впустил за собой вихрь зернистой пыли.", "Преступление и наказание. Раскольников. Я хотел Наполеоном сделаться, оттого и убил... Вошь ли я, как все, или человек? Смогу ли я переступить или не смогу?", "Мастер и Маргарита. Рукописи не горят.", # Современные тексты "Метро 2033. Артём. Станция казалась обреченной. Еще немного - и она погибнет, ее жители будут убиты, а те, кому повезет умереть сразу, избегнут страшной участи оказаться пищей для мутантов.", "Ночной дозор. Иные не умирают насовсем. Мы уходим в сумрак и становимся его частью.", "Географ глобус пропил. Служкин сидел на подоконнике в школьном коридоре и курил, опасливо поглядывая на двери учительской.", "Generation П. Вавилен Татарский. Когда-то в России и правда жило беспечальное юное поколение, которое улыбнулось лету, морю и солнцу – и выбрало «Пепси».", "Лавр. Евгений Водолазкин. Прежде Лавр был Арсением. Когда он родился, никто не предполагал, что впоследствии его назовут Устином, Амвросием и, наконец, Лавром.", "Текст. Глеб Янковский. Телефон – это вообще единственное, что у человека по-настоящему личное. Раньше, может, это была душа, но теперь – телефон.", "Зулейха открывает глаза. Зулейха открывает глаза. Темно, как в погребе. Сонно вздыхают за тонкой занавеской гуси. Месяц скоро народится, а пока стоят самые темные ночи.", "Теория бесконечности. Мы все живем в мире, где каждый день происходят миллионы событий, и каждое из них может изменить нашу жизнь навсегда.", "Цифровая крепость. Сьюзан Флетчер бросила быстрый взгляд на ТРАНСТЕКСТ. Она всегда думала, что шифры весьма, весьма сложны. Но ведь для обычных пользователей они не должны быть сложнее обычных слов.", "Код да Винчи. Роберт Лэнгдон. Знаменитый куратор Лувра Жак Соньер был найден мертвым в Большой галерее музея. Рядом с телом полиция обнаружила загадочное послание.", "Облачный атлас. Тихоокеанский дневник Адама Юинга. Четверг, 7 ноября. За бортом Пропеллер, судна капитана Моллинью, показался остров Чатем.", "Бойцовский клуб. Тайлер Дёрден. Первое правило Бойцовского клуба: никому не рассказывать о Бойцовском клубе. Второе правило Бойцовского клуба: никогда никому не рассказывать о Бойцовском клубе.", "Голодные игры. Китнисс Эвердин. Когда я просыпаюсь, другая половина кровати уже остыла. Я протягиваю руку, ищу тепло Прим, но нахожу лишь грубую холщовую обивку матраса.", "Дивергент. Беатрис Прайор. В нашем доме есть только одно зеркало, и оно спрятано за раздвижной панелью во втором этаже коридора. Наша фракция позволяет смотреться в него раз в три месяца.", "Марсианин. Марк Уотни. Я в полной заднице. Вот моя обдуманная оценка ситуации: я в полной заднице.", "Игра престолов. Эддард Старк. Зима близко." ] # Комнаты для многопользовательской игры rooms = {} @app.route('/') def index(): return render_template('index.html') @app.route('/game') def game(): return render_template('game.html') @app.route('/multiplayer') def multiplayer(): return render_template('multiplayer.html') @app.route('/leaderboard') def leaderboard(): results = GameResult.query.order_by(GameResult.wpm.desc()).limit(10).all() return render_template('leaderboard.html', results=results) @app.route('/get_text', methods=['GET']) def get_text(): text = random.choice(typing_texts) return jsonify({'text': text}) @app.route('/save_result', methods=['POST']) def save_result(): data = request.json username = data.get('username', 'Anonymous') wpm = data.get('wpm', 0) accuracy = data.get('accuracy', 0) # Проверяем, есть ли уже результат с таким именем пользователя existing_result = GameResult.query.filter_by(username=username).first() # Если результат существует и новый результат лучше, обновляем его if existing_result: if wpm > existing_result.wpm: existing_result.wpm = wpm existing_result.accuracy = accuracy existing_result.date = datetime.utcnow() db.session.commit() else: # Если результата нет, создаем новый result = GameResult(username=username, wpm=wpm, accuracy=accuracy) db.session.add(result) db.session.commit() return jsonify({'success': True}) # Обработка WebSocket событий для многопользовательской игры @socketio.on('join') def on_join(data): username = data['username'] room = data['room'] join_room(room) if room not in rooms: rooms[room] = { 'players': {}, 'text': random.choice(typing_texts), 'started': False } rooms[room]['players'][request.sid] = { 'username': username, 'progress': 0, 'wpm': 0, 'accuracy': 0, 'finished': False } # Отправляем обновление всем в комнате emit('room_update', rooms[room], to=room) # Отладочное сообщение print(f"Игрок {username} присоединился к комнате {room}") print(f"Текущие игроки в комнате: {rooms[room]['players'].keys()}") @socketio.on('player_ready') def on_player_ready(data): room = data['room'] if room in rooms: # Отмечаем игрока как готового rooms[room]['players'][request.sid]['ready'] = True # Проверяем, все ли игроки готовы all_ready = True for player_id in rooms[room]['players']: if not rooms[room]['players'][player_id].get('ready', False): all_ready = False break # Если все готовы, начинаем обратный отсчет if all_ready and len(rooms[room]['players']) > 0: emit('countdown_start', {}, to=room) print(f"Все игроки в комнате {room} готовы. Начинаем обратный отсчет.") @socketio.on('start_game') def on_start_game(data): room = data['room'] if room in rooms: rooms[room]['started'] = True emit('game_started', {'text': rooms[room]['text']}, to=room) print(f"Игра в комнате {room} началась. Текст: {rooms[room]['text'][:20]}...") @socketio.on('update_progress') def on_update_progress(data): room = data['room'] progress = data['progress'] wpm = data['wpm'] accuracy = data['accuracy'] if room in rooms and request.sid in rooms[room]['players']: rooms[room]['players'][request.sid]['progress'] = progress rooms[room]['players'][request.sid]['wpm'] = wpm rooms[room]['players'][request.sid]['accuracy'] = accuracy if progress >= 100: rooms[room]['players'][request.sid]['finished'] = True emit('progress_update', rooms[room]['players'], to=room) @socketio.on('disconnect') def on_disconnect(): for room_id, room_data in list(rooms.items()): if request.sid in room_data['players']: del room_data['players'][request.sid] leave_room(room_id) if not room_data['players']: del rooms[room_id] else: emit('room_update', room_data, to=room_id) if __name__ == '__main__': socketio.run(app, debug=True)