Skip to content
This repository has been archived by the owner on Nov 22, 2024. It is now read-only.

Commit

Permalink
Merge branch 'moonbitlang:main' into new
Browse files Browse the repository at this point in the history
  • Loading branch information
Ceasiumz authored Nov 21, 2024
2 parents da94210 + 3ec5771 commit 5dba95e
Show file tree
Hide file tree
Showing 238 changed files with 22,225 additions and 95 deletions.
1 change: 0 additions & 1 deletion MoonBit-Code-JAM-2024
Submodule MoonBit-Code-JAM-2024 deleted from d5c842
189 changes: 110 additions & 79 deletions src/build.mts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ const md = markdownit({
typographer: true,
})

const FINAL_TEAMS = [
'布丁大馍',
'汪汪立功',
'GoToTheDoor',
'天地一!屋!大爱盟',
'Arc_En_Ciel',
]

function githubBtn(
authorName: string,
repoName: string,
Expand Down Expand Up @@ -45,7 +53,7 @@ type MetaInfo = {
control?: string
readme?: string
cover: boolean
prInfo: Awaited<ReturnType<typeof getPRInfo>>
prInfo?: Awaited<ReturnType<typeof getPRInfo>>
}

const metaInfos = new Map<string, MetaInfo>()
Expand Down Expand Up @@ -78,6 +86,48 @@ async function allPulls() {
return pulls
}

async function collectTeamInfo(teamName: string, pull_number?: number) {
if (!fs.existsSync(`teams/${teamName}/game.wasm`)) {
return
}
const prInfo = pull_number ? await getPRInfo(pull_number) : undefined
const metaInfo: MetaInfo = {
prInfo,
cover: false,
}

const files = fs
.readdirSync(`teams/${teamName}`, { withFileTypes: true })
.filter(d => d.isFile())
.map(d => d.name)

for (const file of files) {
const read = (file: string): string =>
fs.readFileSync(`teams/${teamName}/${file}`, 'utf8')
switch (file) {
case 'cover.png': {
metaInfo.cover = true
continue
}
case 'README.md': {
metaInfo.readme = read(file)
continue
}
case 'title': {
metaInfo.title = read(file)
continue
}
case 'control': {
metaInfo.control = read(file)
continue
}
}
}

console.log(`metainfo of ${teamName}:`, metaInfo)
metaInfos.set(teamName, metaInfo)
}

async function collectMetaInfos(): Promise<void> {
const pulls = await allPulls()
for (const pull of pulls) {
Expand All @@ -102,45 +152,16 @@ async function collectMetaInfos(): Promise<void> {
if (!fs.existsSync(`teams/${teamName}`)) {
continue
}
const prInfo = await getPRInfo(pull_number)
const metaInfo: MetaInfo = {
prInfo,
cover: false,
}

const files = fs
.readdirSync(`teams/${teamName}`, { withFileTypes: true })
.filter(d => d.isFile())
.map(d => d.name)

for (const file of files) {
const read = (file: string): string =>
fs.readFileSync(`teams/${teamName}/${file}`, 'utf8')
switch (file) {
case 'cover.png': {
metaInfo.cover = true
continue
}
case 'README.md': {
metaInfo.readme = read(file)
continue
}
case 'title': {
metaInfo.title = read(file)
continue
}
case 'control': {
metaInfo.control = read(file)
continue
}
}
}

console.log(`metainfo of ${teamName}:`, metaInfo)
metaInfos.set(teamName, metaInfo)
await collectTeamInfo(teamName, pull_number)
}
}
}
const teams = fs.readdirSync('teams', { withFileTypes: true })
for (const team of teams) {
if (!team.isDirectory()) continue
if (metaInfos.has(team.name)) continue
await collectTeamInfo(team.name)
}
}

function renderGameCard(teamName: string, metaInfo: MetaInfo): string {
Expand All @@ -149,22 +170,24 @@ function renderGameCard(teamName: string, metaInfo: MetaInfo): string {
: 'default-cover.png'

const teamPath = querystring.escape(teamName)
const authorName = metaInfo.prInfo.head.user.login
const repoName = metaInfo.prInfo.head.repo?.name

if (repoName === undefined) {
throw new Error(`renderGameCard: repoName is undefined`)
}
const authorName = metaInfo.prInfo?.head.user.login
const repoName = metaInfo.prInfo?.head.repo?.name

const footer = metaInfo.title
? `<h2>${metaInfo.title}</h2><p>${teamName}</p>`
: `<p>${teamName}</p>`

let button
if (authorName && repoName) {
button = githubBtn(authorName, repoName, { large: true })
} else {
button = ''
}
return /*html*/ `
<div class='game-card'>
<a href='${teamPath}/index.html'>
<div class='game-card__star'>
${githubBtn(authorName, repoName, { large: true })}
${button}
</div>
<div class='game-card__cover'>
<img src='${coverPath}'/>
Expand All @@ -182,6 +205,10 @@ function indexHtml(): string {
.map(e => renderGameCard(...e))
.join('\n')

const finalGameCards = FINAL_TEAMS.map(teamName =>
renderGameCard(teamName, metaInfos.get(teamName)!),
).join('\n')

return /*html*/ `
<!DOCTYPE html>
<html lang="en">
Expand Down Expand Up @@ -250,6 +277,12 @@ function indexHtml(): string {
}
}
.game-cards-final {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
.game-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
Expand Down Expand Up @@ -326,11 +359,13 @@ function indexHtml(): string {
<main>
<section class='intro-section'>
<h1>MoonBit Code JAM 2024</h1>
<p>决赛作品展示</p>
</section>
<div class='game-cards-final'>
${finalGameCards}
</div>
<section class='intro-section'>
<p>选手提交作品展示</p>
<div class='buttons'>
<a class='button' href='https://tianchi.aliyun.com/competition/entrance/532262'>立即报名</a>
<a class='button' href='https://github.com/moonbitlang/MoonBit-Code-JAM-2024'>提交作品</a>
</div>
</section>
<div class='game-cards'>
${gameCards}
Expand All @@ -346,35 +381,24 @@ function gameIndexHtml(teamName: string, metaInfo: MetaInfo): string {
const title = metaInfo.title ?? teamName
const control = metaInfo.control ?? ''
const readme = metaInfo.readme ? md.render(metaInfo.readme) : ''
const authorName = metaInfo.prInfo.head.user.login
const repoName = metaInfo.prInfo.head.repo?.name
const authorUrl = metaInfo.prInfo.head.user.html_url
const avatarUrl = metaInfo.prInfo.head.user.avatar_url
const updateTime = metaInfo.prInfo.merged_at

if (repoName === undefined || updateTime === null) {
throw new Error(
JSON.stringify(
{
title,
control,
readme,
avatarUrl,
updateTime,
},
null,
2,
),
)
}

const updateDate = new Date(updateTime).toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
})

const avatar = /*html*/ `
const authorName = metaInfo.prInfo?.head.user.login
const repoName = metaInfo.prInfo?.head.repo?.name
const authorUrl = metaInfo.prInfo?.head.user.html_url
const avatarUrl = metaInfo.prInfo?.head.user.avatar_url
const updateTime = metaInfo.prInfo?.merged_at

const updateDate = updateTime
? new Date(updateTime).toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
})
: undefined

const avatar =
authorUrl && avatarUrl && authorName && updateDate
? /*html*/ `
<div class="avatar">
<a href="${authorUrl}" class="avatar__photo" target="_blank">
<img src="${avatarUrl}"/>
Expand All @@ -387,6 +411,7 @@ function gameIndexHtml(teamName: string, metaInfo: MetaInfo): string {
</div>
</div>
`
: ''
return /*html*/ `
<!DOCTYPE html>
<html lang="en">
Expand Down Expand Up @@ -503,9 +528,15 @@ function gameIndexHtml(teamName: string, metaInfo: MetaInfo): string {
<iframe class="wasm4-game" src="game.html" frameborder="0"></iframe>
<p class="control">${control}</p>
<h1>${title}</h1>
<p class="vote">Star 仓库,为 ta 投票
${githubBtn(authorName, repoName, { large: true })}
</p>
${
authorName && repoName
? `<p class="vote">Star 仓库,为 ta 投票 ${githubBtn(
authorName,
repoName,
{ large: true },
)}</p>`
: ''
}
${avatar}
<article>
${readme}
Expand Down
90 changes: 90 additions & 0 deletions teams/Anago/top.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
pub struct Game {
mut score : Int
mut timeLeft : Int
mut requiredButton : Int
mut buttonMatched : Bool
mut preGamePad : @wasm4.GamePad
}

let g : Game = Game::{
score: 0,
timeLeft: 600, // 每局10秒钟
requiredButton: random_button(),
buttonMatched: false,
preGamePad: @wasm4.GamePad::default(),
}

let random : @random.Rand = @random.new()

// 生成随机按键组合(1-4代表不同按键)
fn random_button() -> Int {
return 1 + random.int(limit=4) // 1代表上,2代表下,3代表左,4代表右
}

pub fn start() -> Unit {
@wasm4.set_palette(1, @wasm4.rgb(0xfbf7f3))
@wasm4.set_palette(2, @wasm4.rgb(0xe5b083))
@wasm4.set_palette(3, @wasm4.rgb(0x426e5d))
@wasm4.set_palette(4, @wasm4.rgb(0x20283d))
}

pub fn update() -> Unit {
if g.timeLeft > 0 {
let gamePad = @wasm4.get_gamepad()

// 检测按键匹配
if (g.requiredButton == 1 && gamePad.button_up) ||
(g.requiredButton == 2 && gamePad.button_down) ||
(g.requiredButton == 3 && gamePad.button_left) ||
(g.requiredButton == 4 && gamePad.button_right) {
if not(g.buttonMatched) {
g.buttonMatched = true
g.score += 1
g.requiredButton = random_button() // 新的按键要求
g.timeLeft += 60 // 增加1秒时间

// 正确按下音效
@wasm4.tone(
(800, 1000),
@wasm4.ADSR::new(15, release=5, attack=5),
@wasm4.ADSRVolume::new(30, peak=60),
@wasm4.ToneFlag::new(),
)
}
} else {
g.buttonMatched = false
}

// 动画和显示分数
@wasm4.text("Quick Reaction Game", 10, 10)
@wasm4.text("Score: " + g.score.to_string(), 10, 30)
@wasm4.text("Time Left: " + (g.timeLeft / 60).to_string(), 10, 50)
display_button_hint(g.requiredButton)

// 倒计时
g.timeLeft -= 1
} else {
// 游戏结束
@wasm4.text("Game Over! Score: " + g.score.to_string(), 0, 60)
@wasm4.text("Press X to Restart", 0, 80)
let gamePad = @wasm4.get_gamepad()
if gamePad.button_1 && not(g.preGamePad.button_1) {
g.timeLeft = 600
g.score = 0
g.requiredButton = random_button()
}
}
g.preGamePad = @wasm4.get_gamepad()
}

// 显示当前要求的按键提示
fn display_button_hint(button : Int) -> Unit {
let hintText = match button {
1 => "Press Up"
2 => "Press Down"
3 => "Press Left"
4 => "Press Right"
_ => ""
}
@wasm4.text(hintText, 10, 70)
}
Binary file modified teams/Arc_En_Ciel/game.wasm
Binary file not shown.
Loading

0 comments on commit 5dba95e

Please sign in to comment.