This commit is contained in:
Patrick Devine 2019-10-30 19:48:42 -07:00
Родитель 4ae3943fca
Коммит 00a4d5252e
4 изменённых файлов: 564 добавлений и 0 удалений

10
halloween2019/Dockerfile Normal file
Просмотреть файл

@ -0,0 +1,10 @@
FROM golang:1.13-alpine AS builder
RUN apk add --no-cache git
RUN go get github.com/pdevine/go-asciisprite && go get github.com/pdevine/goMoonPhase
WORKDIR /project
COPY *.go /project/
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o halloween halloween.go art.go
FROM scratch
COPY --from=builder /project/halloween /halloween
ENTRYPOINT ["/halloween"]

Просмотреть файл

@ -0,0 +1,20 @@
FROM --platform=$BUILDPLATFORM golang:1.13-alpine AS builder
RUN apk add --no-cache git
RUN go get github.com/pdevine/go-asciisprite && go get github.com/pdevine/goMoonPhase
WORKDIR /project
COPY *.go /project/
ARG TARGETOS
ARG TARGETARCH
ENV GOOS=$TARGETOS GOARCH=$TARGETARCH
RUN CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o halloween halloween.go art.go
FROM scratch AS release-linux
COPY --from=builder /project/halloween /halloween
ENTRYPOINT ["/summer"]
FROM mcr.microsoft.com/windows/nanoserver:1809 AS release-windows
COPY --from=builder /project/halloween /halloween.exe
ENTRYPOINT ["\\halloween.exe"]
FROM release-$TARGETOS

193
halloween2019/art.go Normal file
Просмотреть файл

@ -0,0 +1,193 @@
package main
const moon_p0 = `
xxxx_..._
xx.:::::::.
x:::::::::::
x:::::::::::
x`+"`"+`:::::::::'
xxx`+"`"+`':::''`
const moon_p1 = `
xxxx_..._
xx.::::. `+"`"+`.
x:::::::. :
x:::::::: :
x`+"`"+`::::::' .'
xxx`+"`"+`'::'-'`
const moon_p2 = `
xxxx_..._
xx.:::: `+"`"+`.
x:::::: :
x:::::: :
x`+"`"+`::::: .'
xxx`+"`"+`'::.-'`
const moon_p3 = `
xxxx_..._
xx.::' `+"`"+`.
x::: :
x::: :
x`+"`"+`::. .'
xxx`+"`"+`':..-'`
const moon_p4 = `
xxxx_..._
xx.' `+"`"+`.
x: :
x: :
x`+"`"+`. .'
xxx`+"`"+`-...-'`
const moon_p5 = `
xxxx_..._
xx.' `+"`"+`::.
x: :::
x: :::
x`+"`"+`. .::'
xxx`+"`"+`-..:''`
const moon_p6 = `
xxxx_..._
xx.' ::::.
x: ::::::
x: ::::::
x`+"`"+`. :::::'
xxx`+"`"+`-.::''`
const moon_p7 = `
xxxx_..._
xx.' .::::.
x: ::::::::
x: ::::::::
x`+"`"+`. '::::::'
xxx`+"`"+`-.::''`
const moon_p8 = `
xxxx_..._
xx.:::::::.
x:::::::::::
x:::::::::::
x`+"`"+`:::::::::'
xxx`+"`"+`':::''`
const happy_halloween_c0 = `
@@@xx@@@xxx@@@@@@xxx@@@@@@@xxx@@@@@@@xxx@@@x@@@xxxxx@@@xx@@@xxx@@@@@@xxx@@@xxxxxxx@@@xxxxxxxx@@@@@@xxx@@@xx@@@xx@@@xx@@@@@@@@xx@@@@@@@@xx@@@xx@@@
@@@xx@@@xx@@@@@@@@xx@@@@@@@@xx@@@@@@@@xx@@@x@@@xxxxx@@@xx@@@xx@@@@@@@@xx@@@xxxxxxx@@@xxxxxxx@@@@@@@@xx@@@xx@@@xx@@@xx@@@@@@@@xx@@@@@@@@xx@@@@x@@@
@@!xx@@@xx@@!xx@@@xx@@!xx@@@xx@@!xx@@@xx@@!x!@@xxxxx@@!xx@@@xx@@!xx@@@xx@@!xxxxxxx@@!xxxxxxx@@!xx@@@xx@@!xx@@!xx@@!xx@@!xxxxxxx@@!xxxxxxx@@!@!@@@
!@!xx@!@xx!@!xx@!@xx!@!xx@!@xx!@!xx@!@xx!@!x@!!xxxxx!@!xx@!@xx!@!xx@!@xx!@!xxxxxxx!@!xxxxxxx!@!xx@!@xx!@!xx!@!xx!@!xx!@!xxxxxxx!@!xxxxxxx!@!!@!@!
@!@!@!@!xx@!@!@!@!xx@!@@!@!xxx@!@@!@!xxxx!@!@!xxxxxx@!@!@!@!xx@!@!@!@!xx@!!xxxxxxx@!!xxxxxxx@!@xx!@!xx@!!xx!!@xx@!@xx@!!!:!xxxx@!!!:!xxxx@!@x!!@!
!!!@!!!!xx!!!@!!!!xx!!@!!!xxxx!!@!!!xxxxxx@!!!xxxxxx!!!@!!!!xx!!!@!!!!xx!!!xxxxxxx!!!xxxxxxx!@!xx!!!xx!@!xx!!!xx!@!xx!!!!!:xxxx!!!!!:xxxx!@!xx!!!
!!:xx!!!xx!!:xx!!!xx!!:xxxxxxx!!:xxxxxxxxx!!:xxxxxxx!!:xx!!!xx!!:xx!!!xx!!:xxxxxxx!!:xxxxxxx!!:xx!!!xx!!:xx!!:xx!!:xx!!:xxxxxxx!!:xxxxxxx!!:xx!!!
:!:xx!:!xx:!:xx!:!xx:!:xxxxxxx:!:xxxxxxxxx:!:xxxxxxx:!:xx!:!xx:!:xx!:!xxx:!:xxxxxxx:!:xxxxxx:!:xx!:!xx:!:xx:!:xx:!:xx:!:xxxxxxx:!:xxxxxxx:!:xx!:!
::xxx:::xx::xxx:::xxx::xxxxxxxx::xxxxxxxxxx::xxxxxxx::xxx:::xx::xxx:::xxx:: ::::xxx:: ::::xx:::::x::xxx::::x::x:::xxxx::x::::xxx::x::::xxx::xxx::
x:xxx:x:xxx:xxx:x:xxx:xxxxxxxxx:xxxxxxxxxxx:xxxxxxxxx:xxx:x:xxx:xxx:x:xx:x::x:x:xx:x::x:x:xxx:x:xx:xxxxx::x:xx:x:xxxx:x::x::xxx:x::x::xxx::xxxx:
`
const whale_c0 = `xxxxxxxxxxxxxxx##xxxxxxxx.xxxxx
xxxxxxxxx##x##x##xxxxxxx==xxxxx
xxxxxx##x##x##x##xxxxxx===xxxxx
xx/""""""""""""""""\___/x===xxx
x{ /xx===x
xx\______ X __/xxxxxxx
xxxx\ \ __/xxxxxxxxxx
xxxxx\____\______/xxxxxxxxxxxxx`
const whale_c0_rev = `xxxxx.xxxxxxxx##xxxxxxxxxxxxxxx
xxxxx==xxxxxxx##x##x##xxxxxxxxx
xxxxx===xxxxxx##x##x##x##xxxxxx
xxx===x\___/""""""""""""""""\xx
x===xx\ }x
xxxxxxx\__ X ______/xx
xxxxxxxxxx\__ / /xxxx
xxxxxxxxxxxxx\______/____/xxxxx`
const cloud_c0 = `
xxxxxxxxx_ _ __.
xxxxxxx(' ).
xxxxxx( ).
xxxxx_( '''.
x.=('( . )
(( (..____.:'-'
'( )_),
xx' _______.:' )
xxxxxxxxxx-----'`
const cloud_c1 = `
xxxx.--
x.+( )
x( . )
( ( ))
x'- __.'`
const coffin_top_c0 = `
xxxxx,________________________________________,`
const coffin_c0 = `
xxx,-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-,
xx+==============================================+
xx| |
x(| ===== ===== ===== |)
xx| |
xx|______________________________________________|
xxx`+"`"+`| |""""""""""""""""""""""""""""""""""""""| |'
xxxx| |""""""""""""""""""""""""""""""""""""""| |
xxxx| |""""""""""""""""""""""""""""""""""""""| |
xxx==============================================`
const bigFlame1 = `
xx.
x.,
xooO,
xoOOoO
OoOOooO`
const bigFlame2 = `
xx,
xxx,+
xx,Oo.
x,ooOo
oO+oOO+`
const bigFlame3 = `
xxx.
xx.,
xx.oO,
x+OO,O
OoOOoOO`
const torch = `
.=======,
( -. _ )
`+"`"+`._____,'
| |
| |
| , |
| |
| |
| | |
| |
|. |
=======`
const ghost_c0 = `
x.-.
(o o)
| O \
x\ \
xx`+"`"+`~~~'
`
const ghost_c1 = `
xxx.-.
xx(o o)
xx/ O |
x/ /
`+"`"+`~~~'
`

341
halloween2019/halloween.go Normal file
Просмотреть файл

@ -0,0 +1,341 @@
package main
import (
"math"
"math/rand"
"strings"
"time"
sprite "github.com/pdevine/go-asciisprite"
tm "github.com/pdevine/go-asciisprite/termbox"
MoonPhase "github.com/pdevine/goMoonPhase"
)
var random *rand.Rand
var allSprites sprite.SpriteGroup
var Width int
var Height int
const cloud_c0_timer = 22
const cloud_c1_timer = 19
type Title struct {
sprite.BaseSprite
Timer int
TimeOut int
}
type Whale struct {
sprite.BaseSprite
Facing int
MinX int
MaxX int
Timer int
TimeOut int
TargetX int
}
type Cloud struct {
sprite.BaseSprite
Timer int
TimeOut int
VX int
}
type Moon struct {
sprite.BaseSprite
Timer int
TimeOut int
PosX float64
PosY float64
}
type Flame struct {
sprite.BaseSprite
Timer int
TimeOut int
}
type Ghost struct {
sprite.BaseSprite
Timer int
TimeOut int
}
func NewTitle() *Title {
t := &Title{BaseSprite: sprite.BaseSprite{
Visible: true,
Y: 6},
TimeOut: 5,
}
title_list := strings.Split(happy_halloween_c0, "\n")
for c, _ := range title_list {
t.AddCostume(sprite.NewCostume(strings.Join(title_list[0:c], "\n"), 'x'))
}
return t
}
func (t *Title) Update() {
t.Timer++
if t.Timer > t.TimeOut && t.CurrentCostume < len(t.Costumes)-1{
t.CurrentCostume++
t.Timer = 0
}
}
func NewMoon() *Moon {
m := &Moon{BaseSprite: sprite.BaseSprite{
Visible: true},
TimeOut: 60,
}
for _, c := range []string{moon_p0, moon_p1, moon_p2, moon_p3, moon_p4, moon_p5, moon_p6, moon_p7, moon_p8} {
m.AddCostume(sprite.NewCostume(c, 'x'))
}
m.CurrentCostume = m.GetPhase()
return m
}
func (m *Moon) GetPhase() int {
moon := MoonPhase.New(time.Now())
i := int(math.Floor(( moon.Phase() + 0.0625 ) * 8))
return i
}
func (m *Moon) Update() {
m.Timer++
if m.Timer > m.TimeOut {
m.PosX++
// arc the moon down in a parabola
m.PosY = 0.00625 * m.PosX * m.PosX
m.X = int(m.PosX)
m.Y = int(m.PosY)
if m.Y >= 25 {
m.Visible = false
}
m.Timer = 0
}
}
func NewCoffin() *sprite.BaseSprite {
c := &sprite.BaseSprite{
Visible: true,
X: 40,
Y: 30,
}
c.AddCostume(sprite.NewCostume(coffin_c0, 'x'))
return c
}
func NewCoffinBack() *sprite.BaseSprite {
c := &sprite.BaseSprite{
Visible: true,
X: 40,
Y: 29,
}
c.AddCostume(sprite.NewCostume(coffin_top_c0, 'x'))
return c
}
func NewTorch(x, y int) *sprite.BaseSprite {
t := &sprite.BaseSprite{
Visible: true,
X: x,
Y: y,
}
t.AddCostume(sprite.NewCostume(torch, 'x'))
return t
}
func NewCloud(cloudType, posX, posY int) *Cloud {
c := &Cloud{BaseSprite: sprite.BaseSprite{
Visible: true,
Y: posY,
X: posX},
VX: -1,
}
if cloudType == 0 {
c.AddCostume(sprite.NewCostume(cloud_c0, 'x'))
c.TimeOut = cloud_c0_timer
} else if cloudType == 1 {
c.AddCostume(sprite.NewCostume(cloud_c1, 'x'))
c.TimeOut = cloud_c1_timer
}
return c
}
func (c *Cloud) Update() {
c.Timer++
if c.Timer > c.TimeOut {
c.X = c.X + c.VX
if c.VX < 0 && c.X + c.Width < 0 {
c.X = 102
}
c.Timer = 0
}
}
func NewWhale() *Whale {
w := &Whale{BaseSprite: sprite.BaseSprite{
Visible: true,
X: 50,
Y: 30},
Facing: -1,
MinX: 40,
TimeOut: 20,
}
w.AddCostume(sprite.NewCostume(whale_c0, 'x'))
w.AddCostume(sprite.NewCostume(whale_c0_rev, 'x'))
return w
}
func (w *Whale) FaceLeft() {
w.CurrentCostume = 0
}
func (w *Whale) FaceRight() {
w.CurrentCostume = 1
}
func (w *Whale) Update() {
w.Timer++
if w.Timer >= w.TimeOut && w.Y > 21 {
w.Y--
w.Timer = 0
}
}
func NewFlame(x, y int) *Flame {
f := &Flame{BaseSprite: sprite.BaseSprite{
Visible: true,
X: x,
Y: y},
TimeOut: 3,
}
for _, c := range []string{bigFlame1, bigFlame2, bigFlame3} {
f.AddCostume(sprite.NewCostume(c, 'x'))
}
return f
}
func (f *Flame) Update() {
f.Timer++
if f.Timer >= f.TimeOut {
f.NextCostume()
f.Timer = 0
}
}
func NewGhost() *Ghost {
g := &Ghost{BaseSprite: sprite.BaseSprite{
Visible: true,
X: random.Intn(50)+25,
Y: 30},
TimeOut: 3,
}
g.AddCostume(sprite.NewCostume(ghost_c0, 'x'))
g.AddCostume(sprite.NewCostume(ghost_c1, 'x'))
return g
}
func (g *Ghost) Update() {
var x int
var y int
g.Timer++
if g.Timer >= g.TimeOut {
x = random.Intn(3)
x--
y = random.Intn(3)
y--
if x < 0 {
g.CurrentCostume = 0
} else if x > 0 {
g.CurrentCostume = 1
}
g.X += x
g.Y += y
g.Timer = 0
}
}
func main() {
// XXX - Wait a bit until the terminal is properly initialized
time.Sleep(1000 * time.Millisecond)
err := tm.Init()
if err != nil {
panic(err)
}
defer tm.Close()
Width, Height = tm.Size()
random = rand.New(rand.NewSource(time.Now().UnixNano()))
event_queue := make(chan tm.Event)
go func() {
for {
event_queue <- tm.PollEvent()
}
}()
txt := "Press 'ESC' to quit. 'Up' for more ghosts."
c := sprite.NewCostume(txt, '~')
text := sprite.NewBaseSprite(Width/2-len(txt)/2, Height-2, c)
w := NewWhale()
m := NewMoon()
cl0 := NewCloud(0, 102, 2)
cl1 := NewCloud(1, 71, 2)
cl2 := NewCloud(1, 23, 3)
t := NewTitle()
f0 := NewFlame(15, 20)
t0 := NewTorch(13, 25)
f1 := NewFlame(110, 20)
t1 := NewTorch(108, 25)
coffin := NewCoffin()
coffinB := NewCoffinBack()
for _, spr := range []sprite.Sprite{m, t, cl0, cl1, cl2, coffinB, w, f0, t0, f1, t1, coffin, text} {
allSprites.Sprites = append(allSprites.Sprites, spr)
}
mainloop:
for {
tm.Clear(tm.ColorDefault, tm.ColorDefault)
select {
case ev := <-event_queue:
if ev.Type == tm.EventKey {
if ev.Key == tm.KeyCtrlC || ev.Key == tm.KeyEsc || ev.Ch == 'q' {
break mainloop
} else if ev.Key == tm.KeyArrowLeft {
w.FaceLeft()
} else if ev.Key == tm.KeyArrowRight {
w.FaceRight()
} else if ev.Key == tm.KeyArrowUp {
g := NewGhost()
allSprites.Sprites = append(allSprites.Sprites, g)
}
} else if ev.Type == tm.EventResize {
Width = ev.Width
Height = ev.Height
}
default:
allSprites.Update()
allSprites.Render()
time.Sleep(50 * time.Millisecond)
}
}
}