277 lines
4.8 KiB
Go
277 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const max_rows = 23
|
|
const max_cols = 80
|
|
const max_len = max_rows * max_cols + max_rows - 1
|
|
|
|
type player struct {
|
|
row int
|
|
col int
|
|
dir int
|
|
p string
|
|
}
|
|
|
|
type bg struct {
|
|
tick int
|
|
tunnel string
|
|
l int
|
|
r int
|
|
c_count int
|
|
c_to int
|
|
pl player
|
|
}
|
|
|
|
|
|
var game bg
|
|
|
|
func SetCharMode(on bool) {
|
|
cmd := exec.Command("stty", "-cbreak", "echo")
|
|
if on {
|
|
cmd = exec.Command("stty", "cbreak", "-echo")
|
|
}
|
|
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdout
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Print("\033[?25l")
|
|
}
|
|
|
|
func makeBg(p player) bg {
|
|
out := bg{0, "", 3, 77, 0, 5, p}
|
|
var line strings.Builder
|
|
line.WriteString("####")
|
|
for i := 0; i < 72; i++ {
|
|
line.WriteString(" ")
|
|
}
|
|
line.WriteString("####")
|
|
out.tunnel = line.String()
|
|
return out
|
|
}
|
|
|
|
func makePlayer() player {
|
|
return player{4, max_cols / 2, 0, "!"}
|
|
}
|
|
|
|
func exit(code int) {
|
|
SetCharMode(false)
|
|
fmt.Print("\033[2J\033[0;0H\033[?25h")
|
|
os.Exit(0)
|
|
}
|
|
|
|
func getInput(ch chan int) {
|
|
var m int
|
|
reader := bufio.NewReader(os.Stdin)
|
|
for {
|
|
r, _, err := reader.ReadRune()
|
|
if err != nil {
|
|
close(ch)
|
|
panic("Rune read error")
|
|
}
|
|
|
|
switch r {
|
|
case 'h', 'H':
|
|
m = -1
|
|
case 'l', 'L':
|
|
m = 1
|
|
case 'k', 'K':
|
|
m = 0
|
|
case 'r', 'R':
|
|
m = 100
|
|
case 'q', 'Q':
|
|
exit(0)
|
|
default:
|
|
continue
|
|
}
|
|
ch <- m
|
|
}
|
|
}
|
|
|
|
func (b *bg) newLeft() int {
|
|
rand.Seed(time.Now().UnixNano())
|
|
var change int
|
|
if b.c_count > 0 && b.c_count < b.c_to {
|
|
b.c_count++
|
|
if b.l > 4 {
|
|
return rand.Intn(2) - 1
|
|
}
|
|
return rand.Intn(2)
|
|
} else {
|
|
b.c_count = 0
|
|
}
|
|
|
|
change = rand.Intn(4) - 1
|
|
|
|
if b.r - b.l < 5 {
|
|
change = rand.Intn(2) - 1
|
|
b.c_count++
|
|
b.c_to = rand.Intn(8) + rand.Intn(4) + 1
|
|
}
|
|
if b.l < 4 || change > 1 {
|
|
change = 1
|
|
}
|
|
|
|
if change < -1 {
|
|
change = -1
|
|
}
|
|
|
|
return change
|
|
}
|
|
|
|
func (b *bg) newRight() int {
|
|
rand.Seed(time.Now().UnixNano())
|
|
var change int = 100
|
|
if b.c_count > 1 {
|
|
if b.r < max_cols - 5 {
|
|
return 1
|
|
}
|
|
return rand.Intn(2) - 1
|
|
}
|
|
|
|
if b.r - b.l < 4 {
|
|
change = rand.Intn(2)
|
|
}
|
|
if b.r > max_cols - 4 {
|
|
change = -1
|
|
}
|
|
|
|
if change > 10 {
|
|
change = rand.Intn(2) - 1
|
|
}
|
|
|
|
if change > 1 {
|
|
change = 1
|
|
}
|
|
if change < -1 {
|
|
change = -1
|
|
}
|
|
|
|
return change
|
|
}
|
|
|
|
func (b *bg) buildNextLine() string {
|
|
|
|
b.l = b.l + b.newLeft()
|
|
b.r = b.r + b.newRight()
|
|
if b.l < 4 {
|
|
b.l = 4
|
|
}
|
|
if b.r > max_cols - 4 {
|
|
b.r = max_cols - 4
|
|
}
|
|
|
|
var out strings.Builder
|
|
out.WriteString("\n")
|
|
out.WriteString(strings.Repeat("#", b.l))
|
|
out.WriteString(strings.Repeat(" ", b.r - b.l))
|
|
out.WriteString(strings.Repeat("#", max_cols - b.r))
|
|
return out.String()
|
|
}
|
|
|
|
func (b *bg) collision() bool {
|
|
if b.tunnel[b.pl.row * max_cols + b.pl.col + b.pl.row - 1] == '#' {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (b *bg) update() {
|
|
ln := b.buildNextLine()
|
|
var out strings.Builder
|
|
if len(b.tunnel) <= max_len {
|
|
out.WriteString(b.tunnel)
|
|
} else {
|
|
out.WriteString(b.tunnel[max_cols + 1:])
|
|
}
|
|
out.WriteString(ln)
|
|
b.tunnel = out.String()
|
|
b.pl.col += b.pl.dir
|
|
if b.pl.col < 1 {
|
|
b.pl.col = 1
|
|
} else if b.pl.col > max_cols - 1 {
|
|
b.pl.col = max_cols - 1
|
|
}
|
|
}
|
|
|
|
func (b *bg) draw() {
|
|
fmt.Print("\033[0;0H")
|
|
fmt.Print(b.tunnel)
|
|
fmt.Printf("\nDepth: %d ft.", b.tick * 6)
|
|
fmt.Printf("\033[%d;%dH%s",b.pl.row,b.pl.col,b.pl.p)
|
|
}
|
|
|
|
func main(){
|
|
var ch = make(chan int)
|
|
defer close(ch)
|
|
SetCharMode(true)
|
|
defer SetCharMode(false)
|
|
game := makeBg(makePlayer())
|
|
restart:
|
|
rand.Seed(time.Now().UnixNano())
|
|
for i := 0; i < max_rows; i++ {
|
|
game.update()
|
|
}
|
|
fmt.Print("\033[2J\033[0;0H")
|
|
fmt.Print(`
|
|
_ _
|
|
_ __| |_ _ _ __ _ __ ___| |_
|
|
| '_ \ | || | ' \| ' \/ -_) _|
|
|
| .__/_|\_,_|_|_|_|_|_|_\___|\__|
|
|
|_|`)
|
|
fmt.Printf("\033[8;%dHTHREE",max_cols/2-3)
|
|
time.Sleep(1 * time.Second)
|
|
fmt.Printf("\033[9;%dHTWO",max_cols/2-2)
|
|
time.Sleep(1 * time.Second)
|
|
fmt.Printf("\033[10;%dHONE",max_cols/2-2)
|
|
time.Sleep(1 * time.Second)
|
|
go getInput(ch)
|
|
oldtime := time.Now().UnixNano() / 1000000
|
|
for {
|
|
select {
|
|
case val, ok := <-ch:
|
|
if ok && val < 5 {
|
|
game.pl.dir = val
|
|
game.pl.col += game.pl.dir
|
|
game.pl.dir = 0
|
|
}
|
|
default:
|
|
// do nothing
|
|
}
|
|
game.tick++
|
|
game.update()
|
|
game.draw()
|
|
if game.collision() {
|
|
time.Sleep(1 * time.Second)
|
|
fmt.Printf("\033[2J\033[10;%dHGame Over",max_cols/2-6)
|
|
fmt.Printf("\033[11;%dHDepth: %d ft.",max_cols/2-8, game.tick * 6)
|
|
fmt.Printf("\033[13;%dHR To Restart",max_cols/2-7)
|
|
fmt.Printf("\033[14;%dHQ To Exit",max_cols/2-6)
|
|
for {
|
|
val := <-ch
|
|
if val == 100 {
|
|
game = makeBg(makePlayer())
|
|
goto restart
|
|
}
|
|
}
|
|
}
|
|
newtime := time.Now().UnixNano() / 1000000
|
|
if dt := newtime - oldtime; dt < 100 && dt >= 0 {
|
|
diff := time.Duration(100 - dt)
|
|
time.Sleep(diff * time.Millisecond)
|
|
}
|
|
oldtime = newtime
|
|
}
|
|
}
|