4820 / 2286 / 287
Регистрация: 01.03.2013
Сообщений: 5,970
Записей в блоге: 30

Очередной консольный тетрис

19.09.2015, 01:37. Показов 1352. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Для виндового эмулятора терминала. Хотя должен работать и на линуксах и прочих макосях, если верить документации. Компилировать с флагом -threaded
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
module Tetris where
 
import Control.Concurrent
import System.Console.ANSI
import System.IO
import System.Random
import qualified Data.Map.Strict as M
import Data.Char
import Foreign.C.Types
 
getHiddenChar = fmap (chr.fromEnum) c_getch
foreign import ccall "conio.h getch" -- unsafe "conio.h getch"
    c_getch :: IO CInt
 
(cols, rows, lboard, uboard, numStrScore) = (10, 20, 25, 4, 14)
scoreChart = map (^2) [0..]
 
type Point = (Int, Int)        -- (row, column)
type Field = [(Int, [Point])]  -- (type index, points)
type Item  = (Int, Int, Point) -- (type index, orientation, central point)
data GameState =
     GameState { field :: Field, item :: Item, run :: Bool, score :: Int, timerDelay :: Int }
 
makeGS f i r s t = GameState { field = f, item = i, run = r, score = s, timerDelay = t }
 
 
timer :: MVar GameState -> IO ()
timer m = do
    inGS @ GameState { field = f, item = i, run = r, score = s, timerDelay = t } <- takeMVar m
 
    newGameState <- if not r then return inGS else do
 
        let i' = move (-1) 0 i
        if testItem f i' then do
            drawPoints ' ' $ itemTypePoints i
            drawPoints '*' $ itemTypePoints i'
            return $ makeGS f i' r s t
 
        else do
            let f' = itemTypePoints i : f
                (fnew, delLines) = compressField f'
                snew = (s+) . sum . map (scoreChart !!) $ delLines
                tnew = t -- надо бы дописать увеличение скорости
 
            if null delLines then return () else do
                setCursorPosition numStrScore 0
                putStr $ "Score: " ++ show snew
                setCursorPosition (numStrScore + 2) 0
                putStr $ "Speed: " ++ show (tnew `div` 10^5)
                mapM_ (drawPoints ' ') f'
                mapM_ (drawPoints '*') fnew
 
            inew <- newItem
            if testItem fnew inew then do
                drawPoints '*' $ itemTypePoints inew
                return $ makeGS fnew inew r snew tnew
 
            else do
                setCursorPosition (numStrScore + 4) 0 >> putStr "Game over!"
                return $ makeGS fnew inew False snew tnew
 
    putMVar m $! newGameState
    threadDelay t
    timer m
 
 
waitKeyPress :: MVar GameState -> IO ()
waitKeyPress m = do
    a <- getHiddenChar --getChar
    inGS @ GameState { field = f, item = i, run = r, score = s, timerDelay = t } <- takeMVar m
 
    let execCommand transform = do
            let i' = transform i
            if not $ testItem f i' then return inGS else do
                drawPoints ' ' $ itemTypePoints i
                drawPoints '*' $ itemTypePoints i'
                return $ makeGS f i' r s t
 
    newGameState <- case a of
 
        'n' -> do                          -- new game
            drawBackground
            inew <- newItem
            drawPoints '*' $ itemTypePoints inew
            return $ makeGS [] inew True 0 (10^6)
 
        'p' -> do                         -- pause / go
            setCursorPosition (numStrScore + 4) 0
            putStr $ if r then "Pause..." else "        "
            return $ makeGS f i (not r) s t
 
        'a' -> execCommand $ move 0 (-1)  -- move left
        'd' -> execCommand $ move 0 1     -- move right
        'w' -> execCommand $ move 1 0     -- move up :)
        's' -> execCommand $ move (-1) 0  -- move down :)
        'q' -> execCommand $ rotate 1     -- rotate left
        'e' -> execCommand $ rotate (-1)  -- rotate right
        ' ' -> execCommand $ fallDown f   -- fall down
        _   -> return inGS                -- nothing
 
    putMVar m $! newGameState
    waitKeyPress m
 
 
itO = [(0,-1),(0,0),(-1,-1),(-1,0)]; itI = [(0,-2),(0,-1),(0,0),(0,1)]
itS = [(-1,-1),(-1,0),(0,0),(0,1)];  itZ = [(0,-1),(0,0),(-1,0),(-1,1)]
itL = [(0,-1),(0,0),(0,1),(-1,-1)];  itJ = [(0,-1),(0,0),(0,1),(-1,1)]
itT = [(0,-1),(0,0),(0,1),(-1,0)]
 
items :: [[[Point]]]
items = [replicate 4 itO, or2 itI, or2 itS, or2 itZ, ori 4 itL, ori 4 itJ, ori 4 itT] where
    ori k = take k . iterate (map $ \(r,c) -> (c,-r)) -- for right rotate \(r,c) -> (-c,r)
    or2 i = ori 2 i ++ ori 2 i
 
itemTypePoints :: Item -> (Int, [Point])
itemTypePoints (n, o, (cpr, cpc)) = (,) n . map (\(r,c) -> (r+cpr, c+cpc)) $ items !! n !! o
 
move :: Int -> Int -> Item -> Item
move dr dc (n, o, (cpr, cpc)) = (n, o, (cpr+dr, cpc+dc))
 
rotate :: Int -> Item -> Item
rotate d (n, o, cp) = (n, (o+d) `mod` 4, cp)
 
testItem :: Field -> Item -> Bool
testItem f = all (\p@(r,c) -> r>=0 && c>=0 && c<cols && all (not . elem p) (map snd f))
    . snd . itemTypePoints
 
fallDown :: Field -> Item -> Item
fallDown f i | testItem f i' = fallDown f i' | otherwise = i where i' = move (-1) 0 i
 
compressField :: Field -> (Field, [Int])
compressField f | null fl  = (f, []) | otherwise = (f', [length fl]) where
    fl = M.keys . M.filter (>=cols) . M.fromListWith (+) . map (\(r,_) -> (r,1)) . concat . map snd $ f
    f' = filter (not . null . snd) . map (fmap $ map (\(r,c) -> (r - length (filter (<r) fl), c))
         . filter (not . (`elem` fl) . fst) ) $ f
 
newItem :: IO Item
newItem = getStdRandom (randomR (0, 6)) >>= \n -> return (n, 0, (rows - 1, cols `div` 2))
 
drawPoint :: Char -> Point -> IO ()
drawPoint sym (r,c) =
    setCursorPosition r0 c0 >> putStr s >> setCursorPosition (r0+1) c0 >> putStr s where
        r0 = uboard + (rows - 1 - r)*2
        c0 = lboard + c*2
        s  = [sym, sym]
 
drawPoints :: Char -> (Int, [Point]) -> IO ()
drawPoints sym (n, ps) = do
    if sym == ' ' then setSGR [Reset]
    else do
        setSGR [SetColor Background Dull White]
        setSGR [SetColor Foreground Vivid (toEnum $ n + 1)]
    mapM_ (drawPoint sym) ps
    setSGR [Reset]
 
drawBackground :: IO ()
drawBackground = do
    clearScreen
 
    setCursorPosition uboard 0
    let leftSpase = replicate (lboard - 1) ' '
    putStr $ unlines $ replicate (rows*2) (leftSpase ++ '|':replicate (cols*2) ' ' ++ "|")
    putStr $ leftSpase ++ '+':replicate (cols*2) '-' ++ "+"
 
    setCursorPosition uboard 0
    putStrLn "Controls:"
    putStrLn ""
    putStrLn "move left - 'a'"
    putStrLn "    right - 'd'"
    putStrLn "rot  left - 'q'"
    putStrLn "    right - 'e'"
    putStrLn "fall down - ' '"
    putStrLn "new  game - 'n'"
 
    setCursorPosition numStrScore 0 >> putStr "Score: 0"
    setCursorPosition (numStrScore + 2) 0 >> putStr "Speed: 0"
 
main :: IO ()
main = do
    hSetBuffering stdin NoBuffering
    hSetBuffering stdout NoBuffering
 
    setTitle "Tetris v 1.0"
    hideCursor
    setCursorPosition uboard 0
    putStrLn "Hello, Windows user! Resize the heigth of terminal window to maximum"
    putStrLn "and press any key..."
    _ <- getHiddenChar --getChar
    drawBackground
 
    m <- newEmptyMVar
    putMVar m $! makeGS [] (0, 0, (0,0)) False 0 (10^6)
    forkIO (timer m)
    waitKeyPress m
3
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.09.2015, 01:37
Ответы с готовыми решениями:

Консольный Тетрис на С++
Написать консольный Тетрис на С++ используя процедурное программирование(без классов и go to). Реализовать: 1) меню 2) уровни...

Написать консольный тетрис
пытаюсь сделать консольный тетрис на си. создал матрицу поле (грубо говоря), границам присвоил 2, внутриигровому полю 1 (чтобы потом было...

Обещаный консольный графический Тетрис (исходники и релиз)
Вот обещал людям консольный графический тетрис Выкладываю все с исходниками Извеняйте, что названия все на родном. Но кому надо...

4
Антикодер
Эксперт функциональных языков программирования
1888 / 870 / 48
Регистрация: 15.09.2012
Сообщений: 3,084
19.09.2015, 06:52
Сделал первый форк:
ivana-tetris
в Linuxe не удаётся скрывать символы от кнопок управления с правой стороны.
С conio.h собрать не удаётся так как в линуксе его нету.

вот ещё нашёл hackage ncurses
проверил пример в
шаблоне консольного приложения
- работает.

ещё есть идея сделать конвертор графики в стереограмму tetris-stereogramma - но тут идея раскрыта не до конца, детальки должны висеть перед монитором. Если вы гляните стереограммы в интернете, то увидите, что есть намного более качественные стереоизображения.

Лучшие стереограммы, которые мне удалось найти, находятся в конце статьи:
stereokartinki-kak-ih-smotret-podborka-stereofoto.html
очень жаль, что картинки статичны...
1
 Аватар для Araneo
650 / 260 / 16
Регистрация: 02.03.2014
Сообщений: 587
19.09.2015, 14:08
Кстати, в самом деле как сделать чтобы ввод не отображался?

Добавлено через 2 часа 42 минуты
Нашёл. True -- включить эхо, False -- выключить.
Haskell
1
2
3
4
5
> :m System.IO
> :i hSetEcho
hSetEcho :: Handle -> Bool -> IO ()     -- Defined in ‘GHC.IO.Handle’
> :i hGetEcho
hGetEcho :: Handle -> IO Bool       -- Defined in ‘GHC.IO.Handle’
0
4820 / 2286 / 287
Регистрация: 01.03.2013
Сообщений: 5,970
Записей в блоге: 30
19.09.2015, 15:14  [ТС]
Насчет линуксов и conio.h - я конечно не пробовал, но последнее - это вынужденная для эмулятора виндового терминала мера-костыль, т.к. на виндах не работает асинхронный ввод-вывод в хаскеле. Для линукса же можно вообще убрать эту фореинг-си функцию гетчар, а в коде везде использовать getChar - вроде по отзывам линуксоидов при установленном флаге hSetBuffering stdin NoBuffering она не требует энтера.

Добавлено через 8 минут
PS собственно, в форке это и сделано
0
Модератор
 Аватар для Curry
5148 / 3397 / 536
Регистрация: 01.06.2013
Сообщений: 7,309
Записей в блоге: 9
19.09.2015, 18:22

Не по теме:

Разработчики базовых библиотек ghc для win портят настройку консоли функцией SetConsoleMode, а саму функцию прячут, так что её приходится снова ручками импортировать. Вредительство, ясчетаю!


Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import System.IO
import Graphics.Win32.Misc
import System.Win32.Types
 
-- для Win64 может, вместо stdcall потребоваться ccall (???)
foreign import stdcall "windows.h SetConsoleMode" c_SetConsoleMode
    :: HANDLE -> DWORD -> IO Bool
 
main :: IO ()
main = do
    h <- getStdHandle sTD_INPUT_HANDLE
-- [url]https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033.aspx[/url]
    c_SetConsoleMode h 0xE1 
    putStr "Input char : "
    hFlush stdout
    c <- getChar
    putStrLn $ "\nInput was  : " ++ [c]
Так и эхо нет, и getChar не ждёт ввода Enter.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.09.2015, 18:22
Помогаю со студенческими работами здесь

Тетрис на c++
Я решил проверить свои скудные знания языка и написать всем известную игру тетрис. Вот что получилось. #include &lt;iostream&gt; ...

Тетрис
Всем добрый вечер! Решил попытаться написать игру &quot;Тетрис&quot; в Borland Builder C++ нашел ролик обучающий, но столкнулся с проблемой,...

Тетрис
Пишу на c++ for DOS! Вобщем не могу сделать передвижение фигуры влево или вправо при нажатии на клавишу. Вот код падения фигуры в...

Тетрис
Задали сделать тетрис на Турбо СИ но незнаю даже с чего начать....только учить начали и уже курсак((

Тетрис на C++
Вот надо написать тетрис на курсовую. Проблема в том, что незнаю с чего начать. Есть , что то вроде гайдов по написанию подобного? И еще,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

Новые блоги и статьи
Популярные LM модели ориентированы на увеличение затрат ресурсов пользователями сгенерированного кода (грязь -заслуги чистоплюев).
Hrethgir 12.06.2025
Вообще обратил внимание, что они генерируют код (впрочем так-же ориентированы разработчики чипов даже), чтобы пользователь их использующий уходил в тот или иной убыток. Это достаточно опытные модели,. . .
Топ10 библиотек C для квантовых вычислений
bytestream 12.06.2025
Квантовые вычисления - это та область, где теория встречается с практикой на границе наших знаний о физике. Пока большая часть шума вокруг квантовых компьютеров крутится вокруг языков высокого уровня. . .
Dispose и Finalize в C#
stackOverflow 12.06.2025
Работая с C# больше десяти лет, я снова и снова наблюдаю одну и ту же историю: разработчики наивно полагаются на сборщик мусора, как на волшебную палочку, которая решит все проблемы с памятью. Да,. . .
Повышаем производительность игры на Unity 6 с GPU Resident Drawer
GameUnited 11.06.2025
Недавно копался в новых фичах Unity 6 и наткнулся на GPU Resident Drawer - штуку, которая заставила меня присвистнуть от удивления. По сути, это внутренний механизм рендеринга, который автоматически. . .
Множества в Python
py-thonny 11.06.2025
В Python существует множество структур данных, но иногда я сталкиваюсь с задачами, где ни списки, ни словари не дают оптимального решения. Часто это происходит, когда мне нужно быстро проверять. . .
Работа с ccache/sccache в рамках C++
Loafer 11.06.2025
Утилиты ccache и sccache занимаются тем, что кешируют промежуточные результаты компиляции, таким образом ускоряя последующие компиляции проекта. Это означает, что если проект будет компилироваться. . .
Настройка MTProxy
Loafer 11.06.2025
Дополнительная информация к инструкции по настройке MTProxy: Перед сборкой проекта необходимо добавить флаг -fcommon в конец переменной CFLAGS в Makefile. Через crontab -e добавить задачу: 0 3. . .
Изучаем Docker: что это, как использовать и как это работает
Mr. Docker 10.06.2025
Суть Docker проста - это платформа для разработки, доставки и запуска приложений в контейнерах. Контейнер, если говорить образно, это запечатанная коробка, в которой находится ваше приложение вместе. . .
Тип Record в C#
stackOverflow 10.06.2025
Многие годы я разрабатывал приложения на C#, используя классы для всего подряд - и мне это казалось естественным. Но со временем, особенно в крупных проектах, я стал замечать, что простые классы. . .
Разработка плагина для Minecraft
Javaican 09.06.2025
За годы существования Minecraft сформировалась сложная экосистема серверов. Оригинальный (ванильный) сервер не поддерживает плагины, поэтому сообщество разработало множество альтернатив. CraftBukkit. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru