2.1.28, initiation update to PXT v5.28.24 (#54)
This commit is contained in:
committed by
Peli de Halleux
parent
38a964516e
commit
5c114a0c57
232
tests/hat-game.ts
Normal file
232
tests/hat-game.ts
Normal file
@ -0,0 +1,232 @@
|
||||
let correctBall: number
|
||||
let ballRevealing: boolean
|
||||
let cupSelect: string
|
||||
let index: number
|
||||
let score: number
|
||||
let level: number
|
||||
let swapSpeed: number
|
||||
|
||||
initializeGame()
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
if (ballRevealing) {
|
||||
index = index + 1
|
||||
if (index > 2) {
|
||||
index = 0
|
||||
}
|
||||
basic.showString(cupSelect[index], 150)
|
||||
}
|
||||
})
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
if (ballRevealing) {
|
||||
ballRevealing = false
|
||||
if (correctBall == index) {
|
||||
score = score + level
|
||||
images.createImage(`
|
||||
. . . . .
|
||||
. . . . #
|
||||
. . . # .
|
||||
# . # . .
|
||||
. # . . .
|
||||
`).showImage(0)
|
||||
basic.pause(1000)
|
||||
basic.showString("+".concat(level.toString()), 150)
|
||||
basic.pause(1000)
|
||||
} else {
|
||||
images.createImage(`
|
||||
# . . . #
|
||||
. # . # .
|
||||
. . # . .
|
||||
. # . # .
|
||||
# . . . #
|
||||
`).showImage(0)
|
||||
basic.pause(1000)
|
||||
basic.clearScreen()
|
||||
revealBall(correctBall)
|
||||
basic.pause(1000)
|
||||
}
|
||||
}
|
||||
level = level + 1
|
||||
if (level == 4) {
|
||||
basic.showString("FINAL SCORE:", 75)
|
||||
basic.showNumber(score, 150)
|
||||
} else {
|
||||
playLevel(level)
|
||||
}
|
||||
})
|
||||
playLevel(1)
|
||||
|
||||
function revealBall(p: number) {
|
||||
let xCoordinate = 2 * p
|
||||
for (let j = 0; j < 3; j++) {
|
||||
led.plot(j * 2, 2)
|
||||
}
|
||||
for (let i = 0; i < 3; i++) {
|
||||
led.unplot(xCoordinate, 2)
|
||||
led.plot(xCoordinate, 1)
|
||||
basic.pause(100)
|
||||
led.unplot(xCoordinate, 1)
|
||||
led.plot(xCoordinate, 0)
|
||||
basic.pause(200)
|
||||
led.unplot(xCoordinate, 0)
|
||||
led.plot(xCoordinate, 1)
|
||||
basic.pause(100)
|
||||
led.unplot(xCoordinate, 1)
|
||||
led.plot(xCoordinate, 2)
|
||||
basic.pause(75)
|
||||
}
|
||||
basic.pause(1000)
|
||||
}
|
||||
|
||||
function initializeGame() {
|
||||
ballRevealing = false
|
||||
level = 1
|
||||
score = 0
|
||||
cupSelect = "LMR"
|
||||
}
|
||||
|
||||
function swapCups(cup_1: number, cup_2: number, pauseDifficulty: number) {
|
||||
let cup_1X = 2 * cup_1
|
||||
let cup_2X = 2 * cup_2
|
||||
let cupXAverage = (cup_1X + cup_2X) / 2
|
||||
led.unplot(cup_1X, 2)
|
||||
led.unplot(cup_2X, 2)
|
||||
led.plot(cup_1X, 3)
|
||||
led.plot(cup_2X, 1)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_1X, 3)
|
||||
led.unplot(cup_2X, 1)
|
||||
led.plot(cup_1X, 4)
|
||||
led.plot(cup_2X, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_1X, 4)
|
||||
led.unplot(cup_2X, 0)
|
||||
if (cupXAverage == 2) {
|
||||
led.plot((cupXAverage + cup_1X) / 2, 4)
|
||||
led.plot((cupXAverage + cup_2X) / 2, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot((cupXAverage + cup_1X) / 2, 4)
|
||||
led.unplot((cupXAverage + cup_2X) / 2, 0)
|
||||
}
|
||||
led.plot(cupXAverage, 4)
|
||||
led.plot(cupXAverage, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cupXAverage, 4)
|
||||
led.unplot(cupXAverage, 0)
|
||||
if (cupXAverage == 2) {
|
||||
led.plot((cupXAverage + cup_2X) / 2, 4)
|
||||
led.plot((cupXAverage + cup_1X) / 2, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot((cupXAverage + cup_2X) / 2, 4)
|
||||
led.unplot((cupXAverage + cup_1X) / 2, 0)
|
||||
}
|
||||
led.plot(cup_2X, 4)
|
||||
led.plot(cup_1X, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_2X, 4)
|
||||
led.unplot(cup_1X, 0)
|
||||
led.plot(cup_2X, 3)
|
||||
led.plot(cup_1X, 1)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_2X, 3)
|
||||
led.unplot(cup_1X, 1)
|
||||
led.plot(cup_2X, 2)
|
||||
led.plot(cup_1X, 2)
|
||||
basic.pause(pauseDifficulty)
|
||||
if (correctBall == cup_1) {
|
||||
correctBall = cup_2
|
||||
} else if (correctBall == cup_2) {
|
||||
correctBall = cup_1
|
||||
}
|
||||
}
|
||||
|
||||
function swapFake(cup_1: number, cup_2: number, pauseDifficulty: number) {
|
||||
let cup_1X = 2 * cup_1
|
||||
let cup_2X = 2 * cup_2
|
||||
let cupXAverage = (cup_1X + cup_2X) / 2
|
||||
led.unplot(cup_1X, 2)
|
||||
led.unplot(cup_2X, 2)
|
||||
led.plot(cup_1X, 3)
|
||||
led.plot(cup_2X, 1)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_1X, 3)
|
||||
led.unplot(cup_2X, 1)
|
||||
led.plot(cup_1X, 4)
|
||||
led.plot(cup_2X, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_1X, 4)
|
||||
led.unplot(cup_2X, 0)
|
||||
if (cupXAverage == 2) {
|
||||
led.plot((cupXAverage + cup_1X) / 2, 4)
|
||||
led.plot((cupXAverage + cup_2X) / 2, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot((cupXAverage + cup_1X) / 2, 4)
|
||||
led.unplot((cupXAverage + cup_2X) / 2, 0)
|
||||
}
|
||||
led.plot(cupXAverage, 4)
|
||||
led.plot(cupXAverage, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cupXAverage, 4)
|
||||
led.unplot(cupXAverage, 0)
|
||||
if (cupXAverage == 2) {
|
||||
led.plot((cupXAverage + cup_1X) / 2, 4)
|
||||
led.plot((cupXAverage + cup_2X) / 2, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot((cupXAverage + cup_1X) / 2, 4)
|
||||
led.unplot((cupXAverage + cup_2X) / 2, 0)
|
||||
}
|
||||
led.plot(cup_1X, 4)
|
||||
led.plot(cup_2X, 0)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_1X, 4)
|
||||
led.unplot(cup_2X, 0)
|
||||
led.plot(cup_1X, 3)
|
||||
led.plot(cup_2X, 1)
|
||||
basic.pause(pauseDifficulty)
|
||||
led.unplot(cup_1X, 3)
|
||||
led.unplot(cup_2X, 1)
|
||||
led.plot(cup_1X, 2)
|
||||
led.plot(cup_2X, 2)
|
||||
basic.pause(pauseDifficulty)
|
||||
}
|
||||
|
||||
function playLevel(level1: number) {
|
||||
basic.showNumber(level, 150)
|
||||
basic.pause(3000)
|
||||
basic.clearScreen()
|
||||
for (let i = 0; i < 3; i++) {
|
||||
led.plot(2 * i, 2)
|
||||
}
|
||||
basic.pause(1000)
|
||||
correctBall = Math.randomInt(3)
|
||||
revealBall(correctBall)
|
||||
basic.pause(1000)
|
||||
let swaps = 5 + 10 * level1
|
||||
if (level1 == 1) {
|
||||
swapSpeed = 80
|
||||
} else if (level1 == 2) {
|
||||
swapSpeed = 40
|
||||
} else {
|
||||
swapSpeed = 20
|
||||
}
|
||||
for (let i1 = 0; i1 < swaps; i1++) {
|
||||
let swapType = Math.randomInt(3)
|
||||
let not = Math.randomInt(3)
|
||||
if (swapType < 2) {
|
||||
let swapOrientation = Math.randomInt(2)
|
||||
if (swapOrientation == 0) {
|
||||
swapCups((not + 1) % 3, (not + 2) % 3, swapSpeed)
|
||||
} else {
|
||||
swapCups((not + 2) % 3, (not + 1) % 3, swapSpeed)
|
||||
}
|
||||
} else {
|
||||
let swapOrientation1 = Math.randomInt(2)
|
||||
if (swapOrientation1 == 0) {
|
||||
swapFake((not + 1) % 3, (not + 2) % 3, swapSpeed)
|
||||
} else {
|
||||
swapFake((not + 2) % 3, (not + 1) % 3, swapSpeed)
|
||||
}
|
||||
}
|
||||
}
|
||||
index = -1
|
||||
ballRevealing = true
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
|
||||
let item = pins.i2cReadNumber(123, NumberFormat.Int8LE)
|
||||
pins.i2cWriteNumber(123, 0, NumberFormat.Int8LE)
|
||||
let item = pins.i2cReadNumber(123, NumberFormat.Int8LE, true)
|
||||
pins.i2cWriteNumber(123, 0, NumberFormat.Int8LE, true)
|
||||
|
||||
let item2 = pins.i2cReadNumber(123, NumberFormat.Int8LE, true)
|
||||
pins.i2cWriteNumber(123, 0, NumberFormat.Int8LE, true)
|
||||
|
@ -11908,62 +11908,111 @@
|
||||
:10071000F19501004198010039B1010099B901003A
|
||||
:10072000D5C901009D26020061270200C180010099
|
||||
:10073000708E3B92C615A841C49866C975EE519754
|
||||
:100740002D0CF6CB4FCF31AA3852319F38B256E537
|
||||
:100740002D0CF6CB4FCF31AA187FF87FFC58A9E9C2
|
||||
:100750000000000000000000000000000000000099
|
||||
:1007600000B5002001B4002001B4002001B4002035
|
||||
:1007700000028C30024602BC01BCE8F745FC01B423
|
||||
:10078000E8F7CAFC01BCF9F731FA0098F9F72EFA3C
|
||||
:1007900001B000BD00B5002001B4069801B4069870
|
||||
:1007A000014601BCF8F759FE01B4039801B405985D
|
||||
:1007B000014601BCF8F751FE014601BCF8F753FEB3
|
||||
:1007C00001B4059801B40798014601BCF8F745FE4D
|
||||
:1007D000014601BCF8F743FE01B40498014601BC90
|
||||
:1007E000F8F739FE0090FFE7009801B000BD00B5B2
|
||||
:1007F000002001B4002000900298002802D0FF20C1
|
||||
:100800000090FFE7059801B4F9F7C9F9059801B41C
|
||||
:10081000059801B40398034604BC02BC0098F9F79C
|
||||
:100820000AF901BCF9F7E2F90598F9F7DFF901B027
|
||||
:1008300000BD00B5002001B40020E8F77DFB00906A
|
||||
:10084000FFE7009801B000BDFFFF000020B50D4696
|
||||
:1008500000200002A83001B40120000290300146BF
|
||||
:1008600001BCE8F70FFA00200002B83001B4012003
|
||||
:1008700000029030014601BCE8F704FA20BD0000F8
|
||||
:10088000FFFF05000500000000000000010001005E
|
||||
:100890000000000000000000000000010101002A2B
|
||||
:1008A000FFFF050005000000000000000000000040
|
||||
:1008B0000000000000000000000000000000002A0E
|
||||
:1008C00041140E2FB82FA2BB4C00A3010000000062
|
||||
:1008D0007B22636F6D7072657373696F6E223A224B
|
||||
:1008E0004C5A4D41222C2268656164657253697AC5
|
||||
:1008F00065223A3133392C227465787453697A65EC
|
||||
:10090000223A323439342C226E616D65223A2262E9
|
||||
:100910006C6F636B73626C696E6B227D5D0000802F
|
||||
:1009200000490A000000000000003D888867041CA0
|
||||
:10093000BCC1C8A25578869B4D69261C354501422D
|
||||
:100940001948E37B0692B2DBE3A99A218E18EFA542
|
||||
:100950006421FF3A50DF5CB84D25B831BC1D9BD0F7
|
||||
:10096000A3720BD23F36166C9FFADA84711D2EB338
|
||||
:100970003291D1DEB646B0BE0FFADE6FD7AD7C1134
|
||||
:10098000573353851403078AD6AEE9A5C8D021B2E0
|
||||
:100990007FFAB45E1D9AF8C10C1AEF12B167A5C2B6
|
||||
:1009A000329D2DC02570F67BAF4E1FC2923CE042B7
|
||||
:1009B00028E478417276160D1F06CE6E0CCBD84C0B
|
||||
:1009C000B456FF79CC0DE99E98FE0D65BED6F7842E
|
||||
:1009D000890D2B69552360DED35DCD22F579D8E4EE
|
||||
:1009E000F214F5717F1C2CEF0D59E583D995AC807D
|
||||
:1009F0000624B660B3E376A4C5A4C62BC0B1766066
|
||||
:100A00005B5E6DBBD94336CEF28C58753EF5E6176A
|
||||
:100A10000D454E5EA91A60E7F9BAA6413CFDB93210
|
||||
:100A2000CC8DC16D25BCBA7ECF28A19D88036FAD4A
|
||||
:100A30008EF21F6085E68BBD74D011870E15C5320E
|
||||
:100A4000CAB0F268C6FF6A8E3DB568FF545C98A5CF
|
||||
:100A5000041DFD9090BB3978F3995097661EE126EE
|
||||
:100A60000993D095AB665AE4626AC471DC13A6D4CC
|
||||
:100A700012F078262A98D778E53BE920E252773DB4
|
||||
:100A8000206C0C9FA0E8589826BD5F95814AC5BE92
|
||||
:100A90007BC997717460085C806C1CD9B85CCD33DD
|
||||
:100AA0000016DD6FD865555605505938E15B941135
|
||||
:100AB000D2FAC2F686783310D2E2FF86A151000046
|
||||
:1007600000B5002001B401B401B401B401B401200A
|
||||
:1007700001B4002001B4002001B400200002F630D2
|
||||
:10078000024602BC01BCE8F73FFC014601BC02B4D2
|
||||
:10079000F9F7B0FC01BCF9F729FA022001B40020F6
|
||||
:1007A00001B4002001B4012000021A30024602BC4C
|
||||
:1007B00001BCE8F729FC014601BC02B4F9F79AFC38
|
||||
:1007C00001BCF9F713FA002001B4002001B40120A4
|
||||
:1007D00000024030024602BC01BCE8F715FC01B43F
|
||||
:1007E000E8F79AFC01BCF9F701FA02209621E7F735
|
||||
:1007F00021FF01200002483001B4012000029030A6
|
||||
:10080000014601BCE8F73EFA012000025830E8F743
|
||||
:10081000CDF801B4962001460098F9F72FF901BCF4
|
||||
:10082000F9F7E4F90120E7F73FFEE7F785FDE8F780
|
||||
:1008300065FAE7F7AFFE0020E7F71CFEE7F784FD57
|
||||
:100840000020E7F7F9FD0020E7F714FE0020E7F7A6
|
||||
:1008500083FD0098F9F7CAF90298F9F7C7F90498E7
|
||||
:10086000F9F7C4F905B000BD00B5002001B4069841
|
||||
:1008700001B40698014601BCF8F7EFFD01B40398F6
|
||||
:1008800001B40598014601BCF8F7E7FD014601BC3B
|
||||
:10089000F8F7E9FD01B4059801B40798014601BCD9
|
||||
:1008A000F8F7DBFD014601BCF8F7D9FD01B4049867
|
||||
:1008B000014601BCF8F7CFFD0090FFE7009801B0BA
|
||||
:1008C00000BD00B5002001B400200090029800286F
|
||||
:1008D00002D0FF200090FFE7059801B4F9F75FF917
|
||||
:1008E000059801B4059801B40398034604BC02BC02
|
||||
:1008F0000098F9F7A0F801BCF9F778F90598F9F72D
|
||||
:1009000075F901B000BD00B5002001B40020E8F782
|
||||
:1009100013FB0090FFE7009801B000BDFFFF00004F
|
||||
:1009200020B50D46002001B401B404200190002040
|
||||
:100930000090009801B40298014601BCF8F767FDE9
|
||||
:10094000002805D000980121F8F785FD0090F0E718
|
||||
:1009500000200021F8F75BFD002800D0FFE702B07F
|
||||
:1009600020BD0000FFFF000020B50D46002001B4AF
|
||||
:1009700001B40120002819D004200121F8F76BFDF3
|
||||
:10098000019000200090009801B40298014601BC3B
|
||||
:10099000F8F73DFD002805D000980121F8F75BFD30
|
||||
:1009A0000090F0E71420E7F79BFDE2E702B020BDDE
|
||||
:1009B000FFFF000020B50D466420E7F791FD20BD44
|
||||
:1009C000FFFF05000500000000000000010001001D
|
||||
:1009D0000000000000010000000100010101002AE8
|
||||
:1009E000FFFF060048656C6C6F21000000000000EE
|
||||
:1009F00041140E2FB82FA2BB55006F03000000005A
|
||||
:100A00007B22636F6D7072657373696F6E223A2219
|
||||
:100A10004C5A4D41222C2268656164657253697A93
|
||||
:100A200065223A3133352C227465787453697A65BE
|
||||
:100A3000223A343236362C226E616D65223A2261BA
|
||||
:100A400077652D696E73706972696E672073637262
|
||||
:100A5000697074227D5D000080003111000000008B
|
||||
:100A60000000003D888867041CBCC1C8A255788678
|
||||
:100A70009B4D69261C354501421948E37B0692B21D
|
||||
:100A8000DBE3A99A218E18EFA56421FF3A50DF5CC1
|
||||
:100A9000B84D25B831BC1D9BD0A3720BD23F361682
|
||||
:100AA0006C9FFADA84711D2EC9AC893737C3C8E24E
|
||||
:100AB0003144571FA844D7A3963E762405463739BC
|
||||
:100AC000562C2741749E7ADF8947F2C0F16D27E6E4
|
||||
:100AD000671D21D7B68962CD4A32EB0C6D831DCEDE
|
||||
:100AE000D938679D3E575063D676C5D1AD67714AF8
|
||||
:100AF000DF5E908FB74BF1BA71BE31AF0D068F211B
|
||||
:100B000042E1428B1A26AEB037DFB75E85844F6F65
|
||||
:100B10007EFD07E78A8E10F0509394D2D3D10F89CF
|
||||
:100B200079E24994B05EC5B4191F8F8732BA2EADF1
|
||||
:100B3000BDA33AEA6B799E8F238650EED8A213129A
|
||||
:100B40004CE8DBDF1CBC54075FAB965AB71F196437
|
||||
:100B500057356BE317D9558961C31B5E7A253D8BE9
|
||||
:100B6000101FCAEA6E9334AFDEB378209D13B0B283
|
||||
:100B7000BBD03BC203BE98A78036163F9B529787D7
|
||||
:100B800047E2EBB8DB41A6C2DE8D0437572CBDC867
|
||||
:100B900070C5D57E332A3633384DAC966B5EE0F89F
|
||||
:100BA0001A4FFBEE3BD5FE46C1FF358742209871B8
|
||||
:100BB000585520F96EAAEF9324E9B1252895D54719
|
||||
:100BC0006CFC464A13EB3A3899E7D46BA3C2027B1C
|
||||
:100BD0008A502E8AA3F91A7AFD6DD225F44D72102F
|
||||
:100BE00013FB3F888E41786D06AA9C6CBC12DB4DCE
|
||||
:100BF000FCEAB9619A1C30A75D2426231876ED041F
|
||||
:100C0000E1F6A1976F1202A06C6DA23FB9ED17B982
|
||||
:100C10004661EAE80727E90B820F1648E858286B77
|
||||
:100C2000C4312974DA972D1A5681A72E31DA22FFA2
|
||||
:100C3000C68CE7BBCBACAA9EBD6FF5C91D62E4B9FB
|
||||
:100C40009C1B6E664633ECFCC88C169A8DF048539C
|
||||
:100C50009687FAB48B5DD1A1CC7568CBA05DBDC27F
|
||||
:100C6000E485A7A1BA020C34F54A5876D5793EF24C
|
||||
:100C7000240921FA568D22B801545A7140A289D50F
|
||||
:100C8000C96E7F553E45B8911C762CA743E18DDF98
|
||||
:100C90007FDB0D260FF7DC95B1454CB8B4A06BEEA9
|
||||
:100CA000BBAB7A21557231ADDA411E05EDAD8E7ABE
|
||||
:100CB000FCE220D686E36BD35922FC6BDA31BDD43B
|
||||
:100CC000FF06648ED8A908BADFF63CE91A3B5874CF
|
||||
:100CD00070836F6C9461A68A19299865D6BA06B894
|
||||
:100CE00063C874A840820066F1BD40FC0816A4F8F1
|
||||
:100CF000B8505B1E18047413CFA130569896E37950
|
||||
:100D0000941201C53A972167887F1258FB9D85B3DD
|
||||
:100D1000D1111EFAFB63E87B849CE3166143E8F281
|
||||
:100D2000B3EA7C8B03B40E241F13F43DD24309ECC9
|
||||
:100D30000B7F066F94CC1DFC0606F9B2284BA2BDB2
|
||||
:100D4000BBBA5A03F54A5646DB56956B1D5CEC9FC1
|
||||
:100D50005112F313C27CED0D7921A38A36C35D01D4
|
||||
:100D6000485A30A244E32C82C52EEB6C9F260F51CB
|
||||
:100D700076E9E1C367F794A852FDAC99CA3B1364C6
|
||||
:100D80006F4F839EA694170E8339279977896845FC
|
||||
:100D900011BD5F9646D7966E61E47FCF282FBD4C7C
|
||||
:100DA0001709BFF597D59E441D6CDB5B74C44A1DC3
|
||||
:100DB000C29F9A9190DFE13600061A2252F094FF0A
|
||||
:100DC000BEF48D7000000000000000000000000074
|
||||
:10C00000903C002061DC030073DC030075DC03005E
|
||||
:10C010000000000000000000000000000000000020
|
||||
:10C0200000000000000000000000000069C10300E3
|
||||
|
155
tests/meteorite.ts
Normal file
155
tests/meteorite.ts
Normal file
@ -0,0 +1,155 @@
|
||||
let oneX: number
|
||||
let oneY: number
|
||||
let twoX: number
|
||||
let twoY: number
|
||||
let pause: number
|
||||
let meteoriteOneX: number
|
||||
let meteoriteOneY: number
|
||||
let meteoriteTwoX: number
|
||||
let meteoriteTwoY: number
|
||||
let counter: number
|
||||
|
||||
basic.pause(2000)
|
||||
oneX = 0
|
||||
oneY = 4
|
||||
twoX = 1
|
||||
twoY = 4
|
||||
counter = 0
|
||||
pause = 700
|
||||
led.plot(oneX, oneY)
|
||||
led.plot(twoX, twoY)
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
if (oneX > 0) {
|
||||
led.unplot(oneX, oneY)
|
||||
led.unplot(twoX, twoY)
|
||||
oneX = oneX - 1
|
||||
twoX = twoX - 1
|
||||
led.plot(oneX, oneY)
|
||||
led.plot(twoX, twoY)
|
||||
}
|
||||
})
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
if (twoX < 4) {
|
||||
led.unplot(oneX, oneY)
|
||||
led.unplot(twoX, twoY)
|
||||
oneX = oneX + 1
|
||||
twoX = twoX + 1
|
||||
led.plot(oneX, oneY)
|
||||
led.plot(twoX, twoY)
|
||||
}
|
||||
})
|
||||
meteoriteOneX = Math.randomInt(5)
|
||||
meteoriteOneY = 0
|
||||
meteoriteTwoX = Math.randomInt(5)
|
||||
meteoriteTwoY = -3
|
||||
basic.pause(1000)
|
||||
for (let i = 0; i < 3; i++) {
|
||||
led.plot(meteoriteTwoX, meteoriteTwoY)
|
||||
led.plot(meteoriteOneX, meteoriteOneY)
|
||||
basic.pause(pause)
|
||||
led.unplot(meteoriteTwoX, meteoriteTwoY)
|
||||
led.unplot(meteoriteOneX, meteoriteOneY)
|
||||
meteoriteOneY = meteoriteOneY + 1
|
||||
meteoriteTwoY = meteoriteTwoY + 1
|
||||
}
|
||||
basic.forever(() => {
|
||||
for (let i1 = 0; i1 < 3; i1++) {
|
||||
led.plot(meteoriteTwoX, meteoriteTwoY)
|
||||
led.plot(meteoriteOneX, meteoriteOneY)
|
||||
basic.pause(pause)
|
||||
led.unplot(meteoriteOneX, meteoriteOneY)
|
||||
led.unplot(meteoriteTwoX, meteoriteTwoY)
|
||||
meteoriteOneY = meteoriteOneY + 1
|
||||
meteoriteTwoY = meteoriteTwoY + 1
|
||||
if (meteoriteOneY == 4) {
|
||||
if (meteoriteOneX == oneX) {
|
||||
for (let j = 0; j < 10; j++) {
|
||||
led.plotAll()
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
basic.pause(200)
|
||||
}
|
||||
basic.showNumber(counter, 150)
|
||||
basic.pause(10000)
|
||||
} else if (meteoriteOneX == twoX) {
|
||||
for (let j1 = 0; j1 < 10; j1++) {
|
||||
led.plotAll()
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
basic.pause(200)
|
||||
}
|
||||
basic.showNumber(counter, 150)
|
||||
basic.pause(10000)
|
||||
}
|
||||
}
|
||||
}
|
||||
while (Math.abs(meteoriteTwoX - meteoriteOneX) < 1) {
|
||||
meteoriteOneX = Math.randomInt(5)
|
||||
}
|
||||
meteoriteOneY = 0
|
||||
counter = counter + 1
|
||||
if (counter == 3) {
|
||||
pause = pause - 250
|
||||
} else if (counter == 8) {
|
||||
pause = pause - 100
|
||||
} else if (counter == 12) {
|
||||
pause = pause - 100
|
||||
} else if (counter == 20) {
|
||||
pause = pause - 100
|
||||
} else if (counter == 30) {
|
||||
pause = pause - 70
|
||||
}
|
||||
if (counter == 40) {
|
||||
pause = pause - 70
|
||||
}
|
||||
for (let i2 = 0; i2 < 3; i2++) {
|
||||
led.plot(meteoriteOneX, meteoriteOneY)
|
||||
led.plot(meteoriteTwoX, meteoriteTwoY)
|
||||
basic.pause(pause)
|
||||
led.unplot(meteoriteOneX, meteoriteOneY)
|
||||
led.unplot(meteoriteTwoX, meteoriteTwoY)
|
||||
meteoriteOneY = meteoriteOneY + 1
|
||||
meteoriteTwoY = meteoriteTwoY + 1
|
||||
if (meteoriteTwoY == 4) {
|
||||
if (meteoriteTwoX == oneX) {
|
||||
for (let j2 = 0; j2 < 10; j2++) {
|
||||
led.plotAll()
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
basic.pause(200)
|
||||
}
|
||||
basic.showNumber(counter, 150)
|
||||
basic.pause(10000)
|
||||
} else if (meteoriteTwoX == twoX) {
|
||||
for (let j3 = 0; j3 < 10; j3++) {
|
||||
led.plotAll()
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
basic.pause(200)
|
||||
}
|
||||
basic.showNumber(counter, 150)
|
||||
basic.pause(10000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
meteoriteTwoX = Math.randomInt(5)
|
||||
while (Math.abs(meteoriteTwoX - meteoriteOneX) < 1) {
|
||||
meteoriteTwoX = Math.randomInt(5)
|
||||
}
|
||||
meteoriteTwoY = 0
|
||||
counter = counter + 1
|
||||
if (counter == 3) {
|
||||
pause = pause - 250
|
||||
} else if (counter == 8) {
|
||||
pause = pause - 100
|
||||
} else if (counter == 12) {
|
||||
pause = pause - 100
|
||||
} else if (counter == 20) {
|
||||
pause = pause - 100
|
||||
} else if (counter == 30) {
|
||||
pause = pause - 70
|
||||
} else if (counter == 40) {
|
||||
pause = pause - 70
|
||||
}
|
||||
})
|
230
tests/pac-man-runaway.ts
Normal file
230
tests/pac-man-runaway.ts
Normal file
@ -0,0 +1,230 @@
|
||||
let levelTime: number
|
||||
let person: Entity
|
||||
let monsters: Entity[]
|
||||
let totalMonsters: number
|
||||
let playing: boolean
|
||||
let gameSuspended: boolean
|
||||
let busyPos: Point[]
|
||||
|
||||
class Entity {
|
||||
public x: number
|
||||
public y: number
|
||||
public dirX: number
|
||||
public dirY: number
|
||||
public hitHorizontalWall(): boolean {
|
||||
return this.y == 0 && this.dirY == -1 || this.y == 4 && this.dirY == 1
|
||||
}
|
||||
|
||||
public hitVerticalWall(): boolean {
|
||||
return this.x == 0 && this.dirX == -1 || this.x == 4 && this.dirX == 1
|
||||
}
|
||||
|
||||
public possHorizontalDir(): number {
|
||||
if (this.x == 0) {
|
||||
return 1
|
||||
} else if (this.x == 4) {
|
||||
return - 1
|
||||
} else {
|
||||
return Math.randomInt(2) * 2 - 1
|
||||
}
|
||||
}
|
||||
|
||||
public possVerticalDir(): number {
|
||||
if (this.y == 0) {
|
||||
return 1
|
||||
} else if (this.y == 4) {
|
||||
return - 1
|
||||
} else {
|
||||
return Math.randomInt(2) * 2 - 1
|
||||
}
|
||||
}
|
||||
|
||||
public collidesX(p2: Entity): boolean {
|
||||
return this.y == p2.y && this.y + this.dirY == p2.y + p2.dirY && (this.x + this.dirX == p2.x || this.x + this.dirX == p2.x + p2.dirX || p2.x + p2.dirX == this.x)
|
||||
}
|
||||
|
||||
public collidesY(p2: Entity): boolean {
|
||||
return this.x == p2.x && this.x + this.dirX == p2.x + p2.dirX && (this.y + this.dirY == p2.y || this.y + this.dirY == p2.y + p2.dirY || p2.y + p2.dirY == this.y)
|
||||
}
|
||||
|
||||
public move1() {
|
||||
this.x = this.x + this.dirX
|
||||
this.y = this.y + this.dirY
|
||||
}
|
||||
|
||||
public towardsX(p2: Entity): number {
|
||||
return Math.sign(p2.x - this.x)
|
||||
}
|
||||
|
||||
public towardsY(p2: Entity): number {
|
||||
return Math.sign(p2.y - this.y)
|
||||
}
|
||||
|
||||
public plot() {
|
||||
led.plot(this.x, this.y)
|
||||
}
|
||||
|
||||
public blink() {
|
||||
led.plot(this.x, this.y)
|
||||
basic.pause(125)
|
||||
led.unplot(this.x, this.y)
|
||||
basic.pause(125)
|
||||
led.plot(this.x, this.y)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Point {
|
||||
public x: number
|
||||
public y: number
|
||||
}
|
||||
|
||||
initializeState()
|
||||
redraw()
|
||||
basic.pause(1000)
|
||||
basic.forever(() => {
|
||||
levelTime = levelTime + 12
|
||||
basic.pause(12)
|
||||
if (!playing) {
|
||||
levelTime = 0
|
||||
playing = true
|
||||
}
|
||||
if (levelTime >= 5000) {
|
||||
gameSuspended = true
|
||||
game.levelUp()
|
||||
levelUp()
|
||||
levelTime = 0
|
||||
resetState()
|
||||
redraw()
|
||||
basic.pause(1000)
|
||||
gameSuspended = false
|
||||
}
|
||||
})
|
||||
basic.forever(() => {
|
||||
if (!gameSuspended) {
|
||||
logic()
|
||||
redraw()
|
||||
basic.pause(500)
|
||||
}
|
||||
})
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
let temp = Math.abs(person.dirX) * (-1)
|
||||
person.dirX = Math.abs(person.dirY) * (-1)
|
||||
person.dirY = temp
|
||||
})
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
let temp1 = Math.abs(person.dirX)
|
||||
person.dirX = Math.abs(person.dirY)
|
||||
person.dirY = temp1
|
||||
})
|
||||
|
||||
function redraw() {
|
||||
basic.clearScreen()
|
||||
person.plot()
|
||||
for (let i = 0; i < totalMonsters; i++) {
|
||||
monsters[i].blink()
|
||||
}
|
||||
}
|
||||
|
||||
function initializeState() {
|
||||
person = new Entity()
|
||||
playing = false
|
||||
busyPos = ([] as Point[])
|
||||
let busyPos1 = new Point()
|
||||
busyPos1.x = 1
|
||||
busyPos1.y = 1
|
||||
let busyPos2 = new Point()
|
||||
busyPos2.x = 1
|
||||
busyPos2.y = 3
|
||||
let busyPos3 = new Point()
|
||||
busyPos3.x = 3
|
||||
busyPos3.y = 1
|
||||
busyPos.push(busyPos1)
|
||||
busyPos.push(busyPos2)
|
||||
busyPos.push(busyPos3)
|
||||
monsters = ([] as Entity[])
|
||||
addMonster()
|
||||
resetState()
|
||||
}
|
||||
|
||||
function logic() {
|
||||
if (person.hitHorizontalWall()) {
|
||||
person.dirY = 0
|
||||
person.dirX = person.possHorizontalDir()
|
||||
}
|
||||
if (person.hitVerticalWall()) {
|
||||
person.dirX = 0
|
||||
person.dirY = person.possVerticalDir()
|
||||
}
|
||||
let lost = false
|
||||
for (let i = 0; i < totalMonsters; i++) {
|
||||
let m = monsters[i]
|
||||
m.dirX = m.towardsX(person)
|
||||
m.dirY = m.towardsY(person)
|
||||
if (m.dirX != 0 && m.dirY != 0) {
|
||||
let x = Math.randomInt(2)
|
||||
if (x == 1) {
|
||||
m.dirX = 0
|
||||
} else {
|
||||
m.dirY = 0
|
||||
}
|
||||
}
|
||||
if (person.collidesX(m) || person.collidesY(m)) {
|
||||
lost = true
|
||||
}
|
||||
}
|
||||
if (!lost) {
|
||||
moveAll()
|
||||
} else {
|
||||
loseLife()
|
||||
}
|
||||
}
|
||||
|
||||
function loseLife() {
|
||||
moveAll()
|
||||
basic.pause(500)
|
||||
basic.showLeds(`
|
||||
. # . # .
|
||||
. . # . .
|
||||
. . . . .
|
||||
. # # # .
|
||||
# . . . #
|
||||
`, 400)
|
||||
basic.pause(1000)
|
||||
basic.clearScreen()
|
||||
game.removeLife(1)
|
||||
playing = false
|
||||
resetState()
|
||||
}
|
||||
|
||||
function moveAll() {
|
||||
person.move1()
|
||||
for (let i = 0; i < totalMonsters; i++) {
|
||||
monsters[i].move1()
|
||||
}
|
||||
}
|
||||
|
||||
function addMonster() {
|
||||
let m = new Entity()
|
||||
monsters.push(m)
|
||||
totalMonsters = totalMonsters + 1
|
||||
}
|
||||
|
||||
function levelUp() {
|
||||
addMonster()
|
||||
}
|
||||
|
||||
function resetState() {
|
||||
levelTime = 0
|
||||
game.setLife(5)
|
||||
person.x = 4
|
||||
person.y = 4
|
||||
person.dirX = -1
|
||||
person.dirY = 0
|
||||
for (let i = 0; i < totalMonsters; i++) {
|
||||
let busy = busyPos[i]
|
||||
let m = monsters[i]
|
||||
m.x = (busy.x + Math.randomInt(3)) - 1
|
||||
m.y = (busy.y + Math.randomInt(3)) - 1
|
||||
}
|
||||
}
|
222
tests/wg-canoe-polo-timer.ts
Normal file
222
tests/wg-canoe-polo-timer.ts
Normal file
@ -0,0 +1,222 @@
|
||||
let AWasPressed: boolean
|
||||
let BWasPressed: boolean
|
||||
let ABWasPressed: boolean
|
||||
let wasShake: boolean
|
||||
let scoreA: number
|
||||
let scoreB: number
|
||||
|
||||
scoreA = 0
|
||||
scoreB = 0
|
||||
startIOMonitor()
|
||||
let gameTime = getGameTime()
|
||||
basic.showLeds(`
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # # #
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
while (!BWasPressed) {
|
||||
basic.pause(100)
|
||||
}
|
||||
BWasPressed = false
|
||||
playOneGame(gameTime)
|
||||
showFinalScores(scoreA, scoreB)
|
||||
|
||||
function startIOMonitor() {
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
AWasPressed = true
|
||||
})
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
BWasPressed = true
|
||||
})
|
||||
input.onButtonPressed(Button.AB, () => {
|
||||
ABWasPressed = true
|
||||
AWasPressed = false
|
||||
BWasPressed = false
|
||||
})
|
||||
input.onShake(() => {
|
||||
wasShake = true
|
||||
})
|
||||
AWasPressed = false
|
||||
BWasPressed = false
|
||||
ABWasPressed = false
|
||||
wasShake = false
|
||||
}
|
||||
|
||||
/**
|
||||
* display score for A and B on same screen as a graphic
|
||||
* this shows a tug of war line, in the middle if scores the same,
|
||||
* Can cope with differences +/-10
|
||||
* @param scoreA1 TODO
|
||||
* @param scoreB1 TODO
|
||||
*/
|
||||
function showScore(scoreA1: number, scoreB1: number) {
|
||||
let img = images.createImage(`
|
||||
# . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . #
|
||||
# . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . #
|
||||
# . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . #
|
||||
# . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . #
|
||||
# . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . #
|
||||
`)
|
||||
let diff = Math.clamp(-10, 10, scoreB1 - scoreA1)
|
||||
diff = diff + 10
|
||||
img.plotFrame(diff)
|
||||
}
|
||||
|
||||
/**
|
||||
* show digits 0..10
|
||||
* @param digits TODO
|
||||
*/
|
||||
function showDigits(digits: number) {
|
||||
digits = Math.clamp(0, 10, digits)
|
||||
let img = images.createImage(`
|
||||
. . # . . . . # . . . # # . . . # # . . . # . . . . # # # . . . # # . . # # # . . . # . . . . # . . # . . # .
|
||||
. # . # . . # # . . . . . # . . . . # . . # . . . . # . . . . # . . . . . . # . . # . # . . # . # . # . # . #
|
||||
. # . # . . . # . . . . # . . . . # . . . # # # . . . # # . . # # . . . . # . . . . # . . . . # # . # . # . #
|
||||
. # . # . . . # . . . # . . . . . . # . . . # . . . . . # . . # . # . . # . . . . # . # . . . . # . # . # . #
|
||||
. . # . . . # # # . . # # # . . # # . . . . # . . . # # . . . . # . . . # . . . . . # . . . # # . . # . . # .
|
||||
`)
|
||||
img.plotFrame(digits)
|
||||
}
|
||||
|
||||
/**
|
||||
* show time graphic for time remaining
|
||||
* @param gameTime TODO
|
||||
*/
|
||||
function showTime(gameTime: number) {
|
||||
let minutes = Math.clamp(0, 10, gameTime / 60)
|
||||
let seconds = gameTime % 60
|
||||
// divide seconds into 10 second stripes
|
||||
let stripes = seconds / 10
|
||||
let img = images.createImage(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . # . . . . # # . . . # # # . . # # # # . # # # # #
|
||||
. . . . . # . . . . # # . . . # # # . . # # # # . # # # # #
|
||||
`)
|
||||
img.plotFrame(stripes)
|
||||
// leave middle row blank
|
||||
// display up to 10 dots in raster on top two rows
|
||||
if (minutes > 0) {
|
||||
for (let i = 0; i < minutes; i++) {
|
||||
let y = i / 5
|
||||
let x = i % 5
|
||||
led.plot(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getGameTime(): number {
|
||||
let chosenGameTime = 7
|
||||
showDigits(chosenGameTime)
|
||||
while (!BWasPressed) {
|
||||
if (AWasPressed) {
|
||||
if (chosenGameTime < 10) {
|
||||
chosenGameTime = chosenGameTime + 1
|
||||
} else {
|
||||
chosenGameTime = 1
|
||||
}
|
||||
showDigits(chosenGameTime)
|
||||
AWasPressed = false
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
BWasPressed = false
|
||||
return chosenGameTime
|
||||
}
|
||||
|
||||
function playOneGame(gameTime: number) {
|
||||
let gameStartTime = input.runningTime()
|
||||
let gameElapsedTime = 0
|
||||
let gameTimeRemaining = gameTime * 60
|
||||
let timeout = 0
|
||||
let lastDisplayedTime = 0
|
||||
showScore(scoreA, scoreB)
|
||||
let state = "TIME"
|
||||
while (gameTimeRemaining >= 0) {
|
||||
// Tick the game time
|
||||
gameElapsedTime = (input.runningTime() - gameStartTime) / 1000
|
||||
gameTimeRemaining = gameTime * 60 - gameElapsedTime
|
||||
// Handle any global events such as point buttons
|
||||
if (AWasPressed) {
|
||||
AWasPressed = false
|
||||
scoreA = scoreA + 1
|
||||
if (state != "LAST10") {
|
||||
showScore(scoreA, scoreB)
|
||||
state = "SCORE"
|
||||
}
|
||||
} else if (BWasPressed) {
|
||||
BWasPressed = false
|
||||
scoreB = scoreB + 1
|
||||
if (state != "LAST10") {
|
||||
showScore(scoreA, scoreB)
|
||||
state = "SCORE"
|
||||
}
|
||||
}
|
||||
// Handle global transitions
|
||||
if (gameTimeRemaining <= 10 && state != "LAST10") {
|
||||
state = "LAST10"
|
||||
}
|
||||
// Handle game states
|
||||
if (state == "SCORE") {
|
||||
if (wasShake) {
|
||||
wasShake = false
|
||||
showTime(gameTimeRemaining)
|
||||
lastDisplayedTime = gameTimeRemaining
|
||||
timeout = input.runningTime() + 5 * 1000
|
||||
state = "TIME"
|
||||
}
|
||||
} else if (state == "TIME") {
|
||||
if (input.runningTime() > timeout) {
|
||||
showScore(scoreA, scoreB)
|
||||
state = "SCORE"
|
||||
}
|
||||
} else if (state == "LAST10") {
|
||||
if (gameTimeRemaining != lastDisplayedTime) {
|
||||
showDigits(gameTimeRemaining)
|
||||
lastDisplayedTime = gameTimeRemaining
|
||||
}
|
||||
}
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function showFinalScores(scoreA1: number, scoreB1: number) {
|
||||
basic.showLeds(`
|
||||
# . . . #
|
||||
. # . # .
|
||||
. . # . .
|
||||
. # . # .
|
||||
# . . . #
|
||||
`)
|
||||
while (true) {
|
||||
if (AWasPressed) {
|
||||
basic.showString("A", 150)
|
||||
basic.showNumber(scoreA1, 150)
|
||||
basic.showLeds(`
|
||||
# . . . #
|
||||
. # . # .
|
||||
. . # . .
|
||||
. # . # .
|
||||
# . . . #
|
||||
`)
|
||||
AWasPressed = false
|
||||
} else if (BWasPressed) {
|
||||
basic.showString("B", 150)
|
||||
basic.showNumber(scoreB1, 150)
|
||||
basic.showLeds(`
|
||||
# . . . #
|
||||
. # . # .
|
||||
. . # . .
|
||||
. # . # .
|
||||
# . . . #
|
||||
`)
|
||||
BWasPressed = false
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
}
|
248
tests/wg-catching-raindrops.ts
Normal file
248
tests/wg-catching-raindrops.ts
Normal file
@ -0,0 +1,248 @@
|
||||
let speed: number
|
||||
let cupCapacity: number
|
||||
let maxMisses: number
|
||||
let autoEmpty: boolean
|
||||
let movement: boolean
|
||||
let sensitivity: number
|
||||
let cupX: number
|
||||
let cupInverted: boolean
|
||||
|
||||
let highscore = 0
|
||||
while (true) {
|
||||
// configure game settings
|
||||
// ##CHALLENGE1: reconfigure game
|
||||
cupCapacity = 5
|
||||
speed = 6
|
||||
maxMisses = 3
|
||||
autoEmpty = false
|
||||
movement = true
|
||||
sensitivity = 400
|
||||
cupX = 2
|
||||
// show the spash screen
|
||||
// ##CHALLENGE 2: CHANGE SPLASH SCREEN
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . .
|
||||
. . . . . . # . # .
|
||||
. . . . . . . . . .
|
||||
. # . # . . # . # .
|
||||
. # # # . . # # # .
|
||||
`, 400)
|
||||
// Decide what to do based on which button is pressed
|
||||
if (input.buttonIsPressed(Button.A)) {
|
||||
let finalScore = playGame()
|
||||
// ##CHALLENGE 3 ADD HIGH SCORE
|
||||
if (finalScore > highscore) {
|
||||
basic.showString("HIGH", 150)
|
||||
highscore = finalScore
|
||||
}
|
||||
basic.showNumber(finalScore, 150)
|
||||
} else if (input.buttonIsPressed(Button.B)) {
|
||||
testMovement()
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function playGame(): number {
|
||||
let cup = images.createImage(`
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . # . # . . . . . .
|
||||
. . . . . . # # # . . . . . .
|
||||
`)
|
||||
let score = 0
|
||||
let dropsInCup = 0
|
||||
let misses = 0
|
||||
let dropX = 0
|
||||
let dropY = 0
|
||||
let prevDropY = -1
|
||||
let cupX1 = 2
|
||||
let prevCupX = -1
|
||||
let state = "NEWDROP"
|
||||
startGame()
|
||||
while (true) {
|
||||
if (state == "NEWDROP") {
|
||||
// create a new drop at a random position
|
||||
dropX = Math.randomInt(5)
|
||||
dropY = 0
|
||||
state = "RAINING"
|
||||
} else if (state == "RAINING") {
|
||||
// calculate new positions
|
||||
cupX1 = getCupPosition()
|
||||
let thisDropY = dropY / speed
|
||||
// Only redraw the screen if something has changed (prevent flashing)
|
||||
if (cupX1 != prevCupX || thisDropY != prevDropY) {
|
||||
basic.clearScreen()
|
||||
// draw cup
|
||||
cup.showImage(7 - cupX1)
|
||||
if (dropsInCup == cupCapacity) {
|
||||
// a full cup
|
||||
led.plot(cupX1, 3)
|
||||
}
|
||||
// draw drop
|
||||
led.plot(dropX, thisDropY)
|
||||
prevCupX = cupX1
|
||||
prevDropY = thisDropY
|
||||
}
|
||||
basic.pause(100)
|
||||
if (thisDropY >= 4) {
|
||||
state = "ATCUP"
|
||||
} else {
|
||||
dropY = dropY + 1
|
||||
}
|
||||
if (cupInverted && dropsInCup >= cupCapacity) {
|
||||
state = "EMPTYING"
|
||||
}
|
||||
} else if (state == "ATCUP") {
|
||||
if (dropX == cupX1) {
|
||||
state = "CATCH"
|
||||
} else {
|
||||
state = "MISS"
|
||||
}
|
||||
} else if (state == "MISS") {
|
||||
// ##CHALLENGE: long beep on miss
|
||||
beep(500)
|
||||
misses = misses + 1
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . # . # . . . . . . . . . . .
|
||||
. . . . . . # # # . . # . # . . . . . .
|
||||
. # . # . . . . . . . # # # . . # . # .
|
||||
. # # # . . . # . . . . . . . . # # # .
|
||||
`, 400)
|
||||
if (misses > maxMisses) {
|
||||
state = "GAMEOVER"
|
||||
} else {
|
||||
state = "NEWDROP"
|
||||
}
|
||||
} else if (state == "CATCH") {
|
||||
// ##CHALLENGE: short beep on catch
|
||||
beep(200)
|
||||
dropsInCup = dropsInCup + 1
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . .
|
||||
. # # # . # . # . # . # . # .
|
||||
. # # # . # # # # # . # # # .
|
||||
`, 400)
|
||||
if (dropsInCup == cupCapacity) {
|
||||
state = "FULL"
|
||||
score = score + 1
|
||||
} else if (dropsInCup > cupCapacity) {
|
||||
state = "OVERFLOW"
|
||||
} else {
|
||||
score = score + 1
|
||||
state = "NEWDROP"
|
||||
}
|
||||
} else if (state == "FULL") {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . .
|
||||
. . . . . . # # # . . . . . .
|
||||
. # # # . . # # # . . # # # .
|
||||
. # # # . . # # # . . # # # .
|
||||
`, 400)
|
||||
if (autoEmpty) {
|
||||
state = "EMPTYING"
|
||||
} else {
|
||||
state = "NEWDROP"
|
||||
}
|
||||
} else if (state == "EMPTYING") {
|
||||
if (cupInverted) {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . # . . . . . . .
|
||||
. . . . . . . . . . . . # . . . . . . . . . . . .
|
||||
. . . . . . . # . . . . . . . . . . . . . . . . .
|
||||
. # # # . . # . # . . # . # . . # . # . . # . # .
|
||||
. # # # . . # # # . . # # # . . # # # . . # # # .
|
||||
`, 400)
|
||||
} else {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . # # # . . # # # . . # # # . . # # # . . # # # . . . . . . . . . . .
|
||||
. . . . . . # # . . . # # # . . # . # . . # . # . . # . # . . # . # . . # # . . . . . . .
|
||||
. . . . . . # # . . . . . . . . . # . . . . . . . . . . . . . . . . . . # . . . . . . . .
|
||||
. # # # . . # # . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # . . . # . # .
|
||||
. # # # . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # # .
|
||||
`, 400)
|
||||
}
|
||||
dropsInCup = 0
|
||||
// ##CHALLENGE: Speed up on every level change
|
||||
if (speed > 1) {
|
||||
speed = speed - 1
|
||||
}
|
||||
state = "NEWDROP"
|
||||
} else if (state == "OVERFLOW") {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . # # # . . # . # . . . . . . . . . . . . . . . .
|
||||
. # # # . . # # # . # # # # # # # # # # . # # # . . # # # .
|
||||
. # # # . . # # # . . # # # . . # # # . # # # # # . # # # .
|
||||
`, 400)
|
||||
state = "GAMEOVER"
|
||||
} else if (state == "GAMEOVER") {
|
||||
// ##CHALLENGE: Make a sound on game over
|
||||
beep(700)
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . # . # . . . . . . . . . . . . # . # . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . # . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. # . # . . . . . . . # # # . # # # # # . # . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. # # # . # # # # # . # . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
`, 400)
|
||||
break
|
||||
}
|
||||
}
|
||||
return score
|
||||
}
|
||||
|
||||
function testMovement() {
|
||||
while (!input.buttonIsPressed(Button.A)) {
|
||||
// ##CHALLENGE 5: Add accelerometer test mode
|
||||
let x = getCupPosition()
|
||||
basic.clearScreen()
|
||||
led.plot(x, 2)
|
||||
basic.pause(200)
|
||||
}
|
||||
}
|
||||
|
||||
function getCupPosition(): number {
|
||||
if (movement) {
|
||||
let acc = input.acceleration(Dimension.X) / sensitivity
|
||||
cupX = Math.clamp(0, 4, acc + 2)
|
||||
return cupX
|
||||
}
|
||||
if (input.buttonIsPressed(Button.A)) {
|
||||
if (cupX > 0) {
|
||||
cupX = cupX - 1
|
||||
}
|
||||
} else if (input.buttonIsPressed(Button.B)) {
|
||||
if (cupX < 4) {
|
||||
cupX = cupX + 1
|
||||
}
|
||||
}
|
||||
return cupX
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
basic.clearScreen()
|
||||
// If button still held from start-game, wait until it is released
|
||||
while (input.buttonIsPressed(Button.A)) {
|
||||
// wait for button to be released
|
||||
}
|
||||
// handlers that work out if cup is turned upside down or not
|
||||
input.onLogoDown(() => {
|
||||
cupInverted = true
|
||||
})
|
||||
input.onLogoUp(() => {
|
||||
cupInverted = false
|
||||
})
|
||||
}
|
||||
|
||||
function beep(p: number) {
|
||||
pins.digitalWritePin(DigitalPin.P0, 1)
|
||||
basic.pause(p)
|
||||
pins.digitalWritePin(DigitalPin.P0, 0)
|
||||
}
|
716
tests/wg-dr-who.ts
Normal file
716
tests/wg-dr-who.ts
Normal file
@ -0,0 +1,716 @@
|
||||
let AWasPressed: boolean
|
||||
let BWasPressed: boolean
|
||||
let ABWasPressed: boolean
|
||||
let wasShake: boolean
|
||||
|
||||
startIOMonitor()
|
||||
let gameNo = 0
|
||||
while (true) {
|
||||
// select a new game
|
||||
if (AWasPressed) {
|
||||
gameNo = (gameNo + 1) % 4
|
||||
AWasPressed = false
|
||||
}
|
||||
// show selected game
|
||||
if (gameNo == 0) {
|
||||
basic.showLeds(`
|
||||
# # # # #
|
||||
# . . . #
|
||||
. # . # .
|
||||
. . . . .
|
||||
. # # # .
|
||||
`)
|
||||
} else if (gameNo == 1) {
|
||||
basic.showLeds(`
|
||||
# # # . .
|
||||
# . . . .
|
||||
# # # # #
|
||||
# # . . .
|
||||
# # # . .
|
||||
`)
|
||||
} else if (gameNo == 2) {
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
# . . . .
|
||||
# # # # #
|
||||
# . . . .
|
||||
. . . . .
|
||||
`)
|
||||
} else if (gameNo == 3) {
|
||||
basic.showLeds(`
|
||||
# . # # #
|
||||
# # # # #
|
||||
. . . # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
`)
|
||||
}
|
||||
// start selected game
|
||||
if (BWasPressed) {
|
||||
// Play the selected game
|
||||
basic.clearScreen()
|
||||
waitBReleased()
|
||||
resetButtons()
|
||||
let finalScore = 0
|
||||
basic.clearScreen()
|
||||
if (gameNo == 0) {
|
||||
finalScore = playCybermen()
|
||||
} else if (gameNo == 1) {
|
||||
finalScore = playDalek()
|
||||
} else if (gameNo == 2) {
|
||||
finalScore = playSonicScrewdriver()
|
||||
} else if (gameNo == 3) {
|
||||
finalScore = playJudoonLanguage()
|
||||
}
|
||||
flashDigit(finalScore, 3)
|
||||
resetButtons()
|
||||
waitBPressed()
|
||||
basic.clearScreen()
|
||||
waitBReleased()
|
||||
resetButtons()
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Game parameters
|
||||
* Percentage chance that cyberman will move left/right to line up with you
|
||||
*/
|
||||
function playCybermen(): number {
|
||||
let maxGameTime = 60
|
||||
let cybermanMoveXProbability = 20
|
||||
// How long (in 100ms ticks) cyberman must line up before moving forward
|
||||
let cybermanMoveYCount = 10
|
||||
// Game variables
|
||||
let startTime = input.runningTime()
|
||||
let gameTime = 0
|
||||
let playerX = 2
|
||||
let cybermanX = 1
|
||||
let cybermanY = 0
|
||||
let cybermanLineupCount = 0
|
||||
let redraw = true
|
||||
while (gameTime < maxGameTime) {
|
||||
if (redraw) {
|
||||
basic.clearScreen()
|
||||
led.plot(playerX, 4)
|
||||
led.plot(cybermanX, cybermanY)
|
||||
redraw = false
|
||||
}
|
||||
// Handle Player Movement
|
||||
if (AWasPressed) {
|
||||
if (playerX > 0) {
|
||||
playerX = playerX - 1
|
||||
redraw = true
|
||||
}
|
||||
AWasPressed = false
|
||||
} else if (BWasPressed) {
|
||||
if (playerX < 4) {
|
||||
playerX = playerX + 1
|
||||
redraw = true
|
||||
}
|
||||
BWasPressed = false
|
||||
}
|
||||
// Handle Cyberman line-of-sight checking
|
||||
if (cybermanX == playerX) {
|
||||
cybermanLineupCount = cybermanLineupCount + 1
|
||||
if (cybermanLineupCount >= cybermanMoveYCount) {
|
||||
if (cybermanY == 4) {
|
||||
// Cyberman caught you, game over
|
||||
break
|
||||
} else {
|
||||
cybermanY = cybermanY + 1
|
||||
redraw = true
|
||||
cybermanLineupCount = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cybermanLineupCount = 0
|
||||
// Move Cyberman closer to player, slowly
|
||||
if (Math.randomInt(100) < cybermanMoveXProbability) {
|
||||
if (cybermanX > playerX) {
|
||||
cybermanX = cybermanX - 1
|
||||
} else if (cybermanX < playerX) {
|
||||
cybermanX = cybermanX + 1
|
||||
}
|
||||
redraw = true
|
||||
}
|
||||
}
|
||||
basic.pause(100)
|
||||
gameTime = (input.runningTime() - startTime) / 1000
|
||||
}
|
||||
return convertSurvivalTimeToScore(gameTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Game parameters, all probabilities as a percentage
|
||||
*/
|
||||
function playDalek(): number {
|
||||
let maxGameTime = 60
|
||||
let userMoveSensitivity = 40
|
||||
let dalekMoveSensitivity = 20
|
||||
let dalekShootChance = 10
|
||||
let dalekHitChance = 10
|
||||
// Game variables
|
||||
let gameTime = 0
|
||||
let startTime = input.runningTime()
|
||||
let dalekY = 2
|
||||
let userY = 1
|
||||
let redraw = true
|
||||
while (gameTime < maxGameTime) {
|
||||
// Redraw screen if necessary
|
||||
if (redraw) {
|
||||
basic.clearScreen()
|
||||
led.plot(0, dalekY)
|
||||
led.plot(4, userY)
|
||||
redraw = false
|
||||
}
|
||||
// Work out if the user has moved, and move them
|
||||
let tilt = getTilt()
|
||||
if (tilt > 2) {
|
||||
// Moving up, slowly
|
||||
if (userY < 4) {
|
||||
if (Math.randomInt(100) < userMoveSensitivity) {
|
||||
userY = userY + 1
|
||||
redraw = true
|
||||
}
|
||||
}
|
||||
} else if (tilt < 2) {
|
||||
// Moving down (slowly)
|
||||
if (userY > 0) {
|
||||
if (Math.randomInt(100) < userMoveSensitivity) {
|
||||
userY = userY - 1
|
||||
redraw = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// Move the Dalek to line up with user
|
||||
if (dalekY < userY) {
|
||||
if (Math.randomInt(100) < dalekMoveSensitivity) {
|
||||
dalekY = dalekY + 1
|
||||
redraw = true
|
||||
}
|
||||
} else if (dalekY > userY) {
|
||||
if (Math.randomInt(100) < dalekMoveSensitivity) {
|
||||
dalekY = dalekY - 1
|
||||
redraw = true
|
||||
}
|
||||
} else {
|
||||
// Dalek lines up
|
||||
if (Math.randomInt(100) < dalekShootChance) {
|
||||
// Shoot a raygun at the user
|
||||
for (let i = 0; i < 3; i++) {
|
||||
led.plot(i + 1, dalekY)
|
||||
basic.pause(100)
|
||||
}
|
||||
if (Math.randomInt(100) < dalekHitChance) {
|
||||
// User has been hit, game over
|
||||
break
|
||||
}
|
||||
redraw = true
|
||||
}
|
||||
}
|
||||
gameTime = (input.runningTime() - startTime) / 1000
|
||||
basic.pause(100)
|
||||
}
|
||||
return convertSurvivalTimeToScore(gameTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this in steps of 60
|
||||
*/
|
||||
function playSonicScrewdriver(): number {
|
||||
let maxGameTime = 120
|
||||
let gameTime = 0
|
||||
// @=0, A=1 etc
|
||||
// bit0=N, bit1=E, bit2=S, bit3=W
|
||||
// bit=0 means it is a wall (can not be opened)
|
||||
// bit=1 means it is a door (can be opened)
|
||||
let mazestr = "BLFL@GOIFIGLCJIA"
|
||||
let maze = ([] as number[])
|
||||
// Locks use same number encoding (bits 0,1,2,3)
|
||||
// bit=0 means door is locked (cannot be walked through)
|
||||
// bit=1 means door is open (can be walked through)
|
||||
let doorOpen = ([] as number[])
|
||||
for (let i = 0; i < 16; i++) {
|
||||
doorOpen.push(0)
|
||||
maze.push(mazestr.charCodeAt(i) - 64)
|
||||
}
|
||||
let redraw = true
|
||||
let cellno = 0
|
||||
let direction = "N"
|
||||
let startTime = input.runningTime()
|
||||
while (gameTime < maxGameTime) {
|
||||
// Draw the screen
|
||||
if (redraw) {
|
||||
basic.clearScreen()
|
||||
// Always draw the maze with N at the top
|
||||
drawMazeCell(doorOpen[cellno])
|
||||
// draw user standing next to selected wall
|
||||
if (direction == "N") {
|
||||
led.plot(2, 1)
|
||||
} else if (direction == "E") {
|
||||
led.plot(3, 2)
|
||||
} else if (direction == "S") {
|
||||
led.plot(2, 3)
|
||||
} else if (direction == "W") {
|
||||
led.plot(1, 2)
|
||||
}
|
||||
redraw = false
|
||||
}
|
||||
// Sense any button presses
|
||||
if (AWasPressed) {
|
||||
if (direction == "N") {
|
||||
direction = "E"
|
||||
} else if (direction == "E") {
|
||||
direction = "S"
|
||||
} else if (direction == "S") {
|
||||
direction = "W"
|
||||
} else if (direction == "W") {
|
||||
direction = "N"
|
||||
}
|
||||
redraw = true
|
||||
AWasPressed = false
|
||||
} else if (BWasPressed) {
|
||||
// Try to walk through an open door
|
||||
if (isDoorOpen(doorOpen[cellno], direction)) {
|
||||
cellno = mazeForward(cellno, 4, 4, direction)
|
||||
redraw = true
|
||||
}
|
||||
BWasPressed = false
|
||||
} else if (wasShake) {
|
||||
// energise sonic screwdriver
|
||||
if (isDoorOpen(maze[cellno], direction)) {
|
||||
// It is a door, but is the door open or closed?
|
||||
if (!(isDoorOpen(doorOpen[cellno], direction))) {
|
||||
// Open the door in front of us
|
||||
doorOpen[cellno] = openDoor(doorOpen[cellno], direction)
|
||||
// Also open the return door for when we walk through this door
|
||||
let forwardCellno = mazeForward(cellno, 4, 4, direction)
|
||||
doorOpen[forwardCellno] = openDoor(doorOpen[forwardCellno], opposite(direction))
|
||||
}
|
||||
} else {
|
||||
// Not a door
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. # . # .
|
||||
. . # . .
|
||||
. # . # .
|
||||
. . . . .
|
||||
`)
|
||||
basic.pause(500)
|
||||
}
|
||||
redraw = true
|
||||
wasShake = false
|
||||
}
|
||||
if (cellno == 15) {
|
||||
// Have reached the exit cell
|
||||
break
|
||||
}
|
||||
basic.pause(100)
|
||||
gameTime = (input.runningTime() - startTime) / 1000
|
||||
}
|
||||
return convertPenaltyTimeToScore(gameTime / maxGameTime / 60)
|
||||
}
|
||||
|
||||
function playJudoonLanguage(): number {
|
||||
let maxGameTime = 60
|
||||
let gameTime = 0
|
||||
let startTime = input.runningTime()
|
||||
let font = images.createImage(`
|
||||
# . # # # # . # . # . . . . # # # . . . # # # # # # . # . # # # # . . . . . # # # . . . # # # # # #
|
||||
# # # # # # # # # # . . . # # . # # # # . # . . . # # # # # # # # # # # # # # . # # # # # . . # . .
|
||||
. . . . # # # # . . . . # # # . . . . # . # . . . . . . . # . . . # # . . # # # . . # . . # # # # #
|
||||
# # # # # # # # # # . . # . . # # # # # # # # # # # # # # # # # # # . # # # # # # # # # # # # # . .
|
||||
# # # # # # # # # # # # # # # # . . . . # . . . # # . . . . . . . # # # # # . . # # # # # # # # # #
|
||||
`)
|
||||
let answers = images.createImage(`
|
||||
# # # # # # # # . . . # # # . . . # . . # . # . #
|
||||
# . . . # # . . . . # # # # # . . . . . . . . . .
|
||||
. # . # . # # # # . # . # . # . # . # . # . # . #
|
||||
. . . . . # # # . . # . # . # . . . . . . . . . .
|
||||
. # # # . # # # . . # . # . # # # # # # # . . . #
|
||||
`)
|
||||
let pages = "029 041 167 208 283"
|
||||
let actualAnswer = Math.randomInt(5)
|
||||
let pos = 0
|
||||
let redraw = true
|
||||
while (gameTime < maxGameTime) {
|
||||
// Draw the current frame from pos (0,1,2 codeword, 3,4,5,6,7 answers)
|
||||
if (redraw) {
|
||||
if (pos <= 2) {
|
||||
// Draw codeword symbol for this choice and this position
|
||||
let digit = parseInt(pages[actualAnswer * 4 + pos])
|
||||
font.plotFrame(digit)
|
||||
} else {
|
||||
// Draw answer
|
||||
let item = pos - 3
|
||||
answers.plotFrame(item)
|
||||
}
|
||||
redraw = false
|
||||
}
|
||||
// Process button presses
|
||||
if (AWasPressed) {
|
||||
// Move left, unless at far left already
|
||||
AWasPressed = false
|
||||
if (pos > 0) {
|
||||
pos = pos - 1
|
||||
redraw = true
|
||||
}
|
||||
} else if (BWasPressed) {
|
||||
// Move right, unless already at far right
|
||||
BWasPressed = false
|
||||
if (pos < 7) {
|
||||
pos = pos + 1
|
||||
redraw = true
|
||||
}
|
||||
} else if (wasShake) {
|
||||
// User trying to select an answer, are we at an answer position?
|
||||
wasShake = false
|
||||
if (pos >= 3) {
|
||||
// Is it the right answer?
|
||||
let userChoice = pos - 3
|
||||
if (userChoice == actualAnswer) {
|
||||
// CORRECT
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . #
|
||||
. . . . . . . . . . . . . . . . . . # . . . . # .
|
||||
# . . . . # . . . . # . # . . # . # . . # . # . .
|
||||
. . . . . . # . . . . # . . . . # . . . . # . . .
|
||||
`, 400)
|
||||
basic.pause(1000)
|
||||
break
|
||||
} else {
|
||||
// WRONG
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . # # . . . # # . . . # # . . . # # . . . #
|
||||
. . . . . . . . . . . . . . . . . . # . . . . # . . . . # . . # . # . . # . # . . # . # .
|
||||
. . . . . . . . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . .
|
||||
. . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . # . . # . # .
|
||||
# . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . #
|
||||
`, 400)
|
||||
basic.pause(1000)
|
||||
redraw = true
|
||||
}
|
||||
}
|
||||
}
|
||||
gameTime = (input.runningTime() - startTime) / 1000
|
||||
basic.pause(100)
|
||||
}
|
||||
return convertPenaltyTimeToScore(gameTime)
|
||||
}
|
||||
|
||||
function getDirection(): string {
|
||||
let bearing = input.compassHeading()
|
||||
if (bearing < 45 || bearing > 315) {
|
||||
return "N"
|
||||
} else if (bearing < 135) {
|
||||
return "E"
|
||||
} else if (bearing < 225) {
|
||||
return "S"
|
||||
} else {
|
||||
return "W"
|
||||
}
|
||||
}
|
||||
|
||||
function calibrateCompass() {
|
||||
if (input.compassHeading() == -4) {
|
||||
input.calibrate()
|
||||
}
|
||||
}
|
||||
|
||||
function waitBReleased() {
|
||||
while (input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function waitBPressed() {
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the score 0..9
|
||||
* @param digit TODO
|
||||
* @param times TODO
|
||||
*/
|
||||
function flashDigit(digit: number, times: number) {
|
||||
digit = Math.clamp(0, 9, digit)
|
||||
for (let i = 0; i < times; i++) {
|
||||
basic.showNumber(digit, 0)
|
||||
basic.pause(500)
|
||||
basic.clearScreen()
|
||||
basic.pause(500)
|
||||
}
|
||||
basic.showNumber(digit, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* score is calculated as the amount of time you lasted
|
||||
* @param gameTime TODO
|
||||
*/
|
||||
function convertSurvivalTimeToScore(gameTime: number): number {
|
||||
if (gameTime <= 4) {
|
||||
return 0
|
||||
} else if (gameTime <= 9) {
|
||||
return 1
|
||||
} else if (gameTime <= 14) {
|
||||
return 2
|
||||
} else if (gameTime <= 19) {
|
||||
return 3
|
||||
} else if (gameTime <= 24) {
|
||||
return 4
|
||||
} else if (gameTime <= 29) {
|
||||
return 5
|
||||
} else if (gameTime <= 39) {
|
||||
return 6
|
||||
} else if (gameTime <= 49) {
|
||||
return 7
|
||||
} else if (gameTime <= 59) {
|
||||
return 8
|
||||
} else {
|
||||
return 9
|
||||
}
|
||||
}
|
||||
|
||||
function convertPenaltyTimeToScore(penaltyTime: number): number {
|
||||
if (penaltyTime <= 4) {
|
||||
return 9
|
||||
} else if (penaltyTime <= 9) {
|
||||
return 8
|
||||
} else if (penaltyTime <= 14) {
|
||||
return 7
|
||||
} else if (penaltyTime <= 19) {
|
||||
return 6
|
||||
} else if (penaltyTime <= 24) {
|
||||
return 5
|
||||
} else if (penaltyTime <= 29) {
|
||||
return 4
|
||||
} else if (penaltyTime <= 39) {
|
||||
return 3
|
||||
} else if (penaltyTime <= 49) {
|
||||
return 2
|
||||
} else if (penaltyTime <= 59) {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
function startIOMonitor() {
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
AWasPressed = true
|
||||
})
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
BWasPressed = true
|
||||
})
|
||||
input.onButtonPressed(Button.AB, () => {
|
||||
ABWasPressed = true
|
||||
})
|
||||
input.onShake(() => {
|
||||
wasShake = true
|
||||
})
|
||||
AWasPressed = false
|
||||
BWasPressed = false
|
||||
ABWasPressed = false
|
||||
wasShake = false
|
||||
}
|
||||
|
||||
/**
|
||||
* maze is always drawn with north at top
|
||||
* @param cell TODO
|
||||
*/
|
||||
function drawMazeCell(cell: number) {
|
||||
let n = !(isNorth(cell))
|
||||
let e = !(isEast(cell))
|
||||
let s = !(isSouth(cell))
|
||||
let w = !(isWest(cell))
|
||||
// Draw any visible walls
|
||||
if (n) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
led.plot(i, 0)
|
||||
}
|
||||
}
|
||||
if (e) {
|
||||
for (let l = 0; l < 5; l++) {
|
||||
led.plot(4, l)
|
||||
}
|
||||
}
|
||||
if (s) {
|
||||
for (let k = 0; k < 5; k++) {
|
||||
led.plot(k, 4)
|
||||
}
|
||||
}
|
||||
if (w) {
|
||||
for (let j = 0; j < 5; j++) {
|
||||
led.plot(0, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* work out the cell number in front of this cell
|
||||
* given the direction N E S W (N points to button B)
|
||||
* returns the forward cell number, -1 if outside of maze
|
||||
* Turn cellno into an x and y based on width and height
|
||||
* @param cellno TODO
|
||||
* @param width TODO
|
||||
* @param height TODO
|
||||
* @param direction TODO
|
||||
*/
|
||||
function mazeForward(cellno: number, width: number, height: number, direction: string): number {
|
||||
let y = cellno / width
|
||||
let x = cellno % width
|
||||
// Work out change in x/y and therefore change in cellno
|
||||
// But bounds-check against width and height
|
||||
// as user cannot walk outside of the maze
|
||||
if (direction == "N") {
|
||||
// sub 1 from y
|
||||
if (y > 0) {
|
||||
return cellno - width
|
||||
}
|
||||
} else if (direction == "E") {
|
||||
// Add 1 to x
|
||||
if (x < width - 1) {
|
||||
return cellno + 1
|
||||
}
|
||||
} else if (direction == "S") {
|
||||
// add 1 to y
|
||||
if (y < height - 1) {
|
||||
return cellno + width
|
||||
}
|
||||
} else if (direction == "W") {
|
||||
// sub 1 from x
|
||||
if (x > 0) {
|
||||
return cellno - 1
|
||||
}
|
||||
}
|
||||
// Not allowed to move in this direction, it will go outside of maze
|
||||
return - 1
|
||||
}
|
||||
|
||||
/**
|
||||
* A door is open if the lock bit is 1
|
||||
* A door is present if the maze bit is 1
|
||||
* @param cell TODO
|
||||
* @param direction TODO
|
||||
*/
|
||||
function isDoorOpen(cell: number, direction: string): boolean {
|
||||
if (direction == "N") {
|
||||
return isNorth(cell)
|
||||
} else if (direction == "E") {
|
||||
return isEast(cell)
|
||||
}
|
||||
if (direction == "S") {
|
||||
return isSouth(cell)
|
||||
} else if (direction == "W") {
|
||||
return isWest(cell)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function getTilt(): number {
|
||||
let tilt: number
|
||||
tilt = input.acceleration(Dimension.Y)
|
||||
tilt = Math.clamp(-1024, 1023, tilt)
|
||||
tilt = (tilt + 1024) / 512
|
||||
return tilt
|
||||
}
|
||||
|
||||
function waitAReleased() {
|
||||
while (input.buttonIsPressed(Button.A)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function waitNoButtons() {
|
||||
while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B) || input.buttonIsPressed(Button.AB)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function resetButtons() {
|
||||
AWasPressed = false
|
||||
BWasPressed = false
|
||||
ABWasPressed = false
|
||||
}
|
||||
|
||||
/**
|
||||
* The appropriate bit (0,1,2,3) is set, which unlocks the door
|
||||
* @param cell TODO
|
||||
* @param direction TODO
|
||||
*/
|
||||
function openDoor(cell: number, direction: string): number {
|
||||
if (direction == "N") {
|
||||
return cell | 1
|
||||
} else if (direction == "E") {
|
||||
return cell | 2
|
||||
} else if (direction == "S") {
|
||||
return cell | 4
|
||||
} else if (direction == "W") {
|
||||
return cell | 8
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
/**
|
||||
* is the north bit set in the cell?
|
||||
* @param cell TODO
|
||||
*/
|
||||
function isNorth(cell: number): boolean {
|
||||
if ((cell & 1) != 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* is the east bit set in the cell?
|
||||
* @param cell TODO
|
||||
*/
|
||||
function isEast(cell: number): boolean {
|
||||
if ((cell & 2) != 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* is the south bit set in the cell?
|
||||
* @param cell TODO
|
||||
*/
|
||||
function isSouth(cell: number): boolean {
|
||||
if ((cell & 4) != 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* is the west bit set in the cell?
|
||||
* @param cell TODO
|
||||
*/
|
||||
function isWest(cell: number): boolean {
|
||||
if ((cell & 8) != 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function opposite(direction: string): string {
|
||||
if (direction == "N") {
|
||||
return "S"
|
||||
} else if (direction == "E") {
|
||||
return "W"
|
||||
} else if (direction == "S") {
|
||||
return "N"
|
||||
} else if (direction == "W") {
|
||||
return "E"
|
||||
}
|
||||
return direction
|
||||
}
|
||||
|
||||
function isSount() { }
|
165
tests/wg-flood-monitor.ts
Normal file
165
tests/wg-flood-monitor.ts
Normal file
@ -0,0 +1,165 @@
|
||||
let sensorType: string
|
||||
|
||||
// ANALOG or TILT
|
||||
sensorType = "TILT"
|
||||
while (true) {
|
||||
// splash screen (flood monitor)
|
||||
basic.showLeds(`
|
||||
# # # . .
|
||||
# . . . .
|
||||
# # . # .
|
||||
# . . # .
|
||||
# . . # #
|
||||
`)
|
||||
while (true) {
|
||||
if (input.buttonIsPressed(Button.A)) {
|
||||
// test that the sensor works
|
||||
testMode()
|
||||
break
|
||||
} else if (input.buttonIsPressed(Button.B)) {
|
||||
// run the real flood monitor
|
||||
floodMonitor()
|
||||
break
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* test mode - test that the monitor and buzzer work
|
||||
* no filtering in this mode, direct screen update
|
||||
*/
|
||||
function testMode() {
|
||||
basic.showLeds(`
|
||||
# # # # #
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
`)
|
||||
waitNoButtons()
|
||||
let img = images.createImage(`
|
||||
. . . . . . . . . . . . . . . . . . . . # # # # #
|
||||
. . . . . . . . . . . . . . . # # # # # . . . . .
|
||||
. . . . . . . . . . # # # # # . . . . . . . . . .
|
||||
. . . . . # # # # # . . . . . . . . . . . . . . .
|
||||
# # # # # . . . . . . . . . . . . . . . . . . . .
|
||||
`)
|
||||
while (!input.buttonIsPressed(Button.A)) {
|
||||
// Show live reading on display
|
||||
let value = readSensor()
|
||||
img.showImage(value * 5)
|
||||
// Turn beeper on only if maximum value seen
|
||||
if (value >= 4) {
|
||||
pins.digitalWritePin(DigitalPin.P1, 1)
|
||||
} else {
|
||||
pins.digitalWritePin(DigitalPin.P1, 0)
|
||||
}
|
||||
basic.pause(50)
|
||||
}
|
||||
waitNoButtons()
|
||||
}
|
||||
|
||||
function floodMonitor() {
|
||||
basic.showLeds(`
|
||||
# . . . #
|
||||
# # . # #
|
||||
# . # . #
|
||||
# . . . #
|
||||
# . . . #
|
||||
`)
|
||||
waitNoButtons()
|
||||
let line = images.createImage(`
|
||||
. . . . . . . . . . . . . . . . . . . . # # # # #
|
||||
. . . . . . . . . . . . . . . # # # # # . . . . .
|
||||
. . . . . . . . . . # # # # # . . . . . . . . . .
|
||||
. . . . . # # # # # . . . . . . . . . . . . . . .
|
||||
# # # # # . . . . . . . . . . . . . . . . . . . .
|
||||
`)
|
||||
let state = "SAFE"
|
||||
let averagedValue = 0
|
||||
while (!input.buttonIsPressed(Button.A)) {
|
||||
let value = readSensor()
|
||||
// Apply some 'lag' filtering to the value, so that 'bobbing' doesn't set off alarm
|
||||
// i.e. to go from 0 to 4 takes 4 times round the loop
|
||||
if (value > averagedValue) {
|
||||
// On the way up, changes in reading are slowed down
|
||||
averagedValue = averagedValue + 1
|
||||
} else if (value < averagedValue) {
|
||||
// On the way down, changes in reading happen immediately
|
||||
averagedValue = value
|
||||
}
|
||||
// Work out what to do based on the averaged value (non bobbing value)
|
||||
if (state == "SAFE") {
|
||||
if (averagedValue >= 4) {
|
||||
pins.digitalWritePin(DigitalPin.P1, 1)
|
||||
state = "ALARMING"
|
||||
} else {
|
||||
// Display raw value as a line
|
||||
line.showImage(value * 5)
|
||||
// fill in based on averaged value (long term reading)
|
||||
for (let i = 0; i < averagedValue; i++) {
|
||||
led.plot(2, 4 - i)
|
||||
}
|
||||
}
|
||||
} else if (state == "ALARMING") {
|
||||
if (input.buttonIsPressed(Button.B)) {
|
||||
pins.digitalWritePin(DigitalPin.P1, 0)
|
||||
state = "SAFE"
|
||||
} else {
|
||||
basic.showAnimation(`
|
||||
# # # # # . . . . .
|
||||
# # # # # . . . . .
|
||||
# # # # # . . . . .
|
||||
# # # # # . . . . .
|
||||
# # # # # . . . . .
|
||||
`, 400)
|
||||
}
|
||||
}
|
||||
basic.pause(300)
|
||||
}
|
||||
waitNoButtons()
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a value 0,1,2,3,4 from either ANALOG or TILT
|
||||
*/
|
||||
function readSensor(): number {
|
||||
let value = 0
|
||||
// Produce a sensor value in range 0..1023
|
||||
if (sensorType == "ANALOG") {
|
||||
// Input range is 0..1023
|
||||
value = pins.analogReadPin(AnalogPin.P0)
|
||||
} else if (sensorType == "TILT") {
|
||||
// Input range is -1024 (pads highest)..1023 (pads lowest)
|
||||
value = input.acceleration(Dimension.Y)
|
||||
// Emulator sometimes returns out of range values, so clamp to expected range
|
||||
value = Math.clamp(-1024, 1023, value)
|
||||
// Convert to an entirely positive range from 0 pads full up to 2047 pads full down
|
||||
// (hinged at the 'eyes' end)
|
||||
value = value + 1024
|
||||
// Invert the direction, so that "pads up" is largest, "pads down" is smallest
|
||||
value = 2047 - value
|
||||
// We want the same range as the analog, so halve the range
|
||||
value = value / 2
|
||||
}
|
||||
// 5 possible values (0,1,2,3,4) based on sensible thresholds
|
||||
// We do this by thresholds, so that we have more control over the 5 levels
|
||||
if (value < 200) {
|
||||
return 0
|
||||
} else if (value < 400) {
|
||||
return 1
|
||||
} else if (value < 600) {
|
||||
return 2
|
||||
} else if (value < 800) {
|
||||
return 3
|
||||
}
|
||||
return 4
|
||||
}
|
||||
|
||||
function waitNoButtons() {
|
||||
while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
529
tests/wg-operation.ts
Normal file
529
tests/wg-operation.ts
Normal file
@ -0,0 +1,529 @@
|
||||
let opMaxTime: number
|
||||
let procMaxTime: number
|
||||
let procsToDo: number
|
||||
let recoveryTriesMax: number
|
||||
let tenseTime: number
|
||||
let flatlineTimeMax: number
|
||||
let recoveryProbability: number
|
||||
let aWasPressed: boolean
|
||||
let bWasPressed: boolean
|
||||
let digitsImg: Image
|
||||
let tweezerCount_: number
|
||||
let wasTweezers: boolean
|
||||
let wasNose: boolean
|
||||
let isTweezers: boolean
|
||||
|
||||
// P0 blue wire, tweezers (active high)
|
||||
// P1, green wire nose button/LED (active high)
|
||||
// P2/red speaker (not a self toned beeper, but a piezo or a speaker)
|
||||
opMaxTime = 120 * 1000
|
||||
procsToDo = 3
|
||||
procMaxTime = 60 * 1000
|
||||
tenseTime = 4000
|
||||
flatlineTimeMax = 15 * 1000
|
||||
recoveryTriesMax = 3
|
||||
recoveryProbability = 60
|
||||
let highScore = 0
|
||||
digitsImg = images.createImage(`
|
||||
. . # . . . . # . . . # # . . . # # . . . # . . . . # # # . . . # # . . # # # . . . # . . . . # . .
|
||||
. # . # . . # # . . . . . # . . . . # . . # . . . . # . . . . # . . . . . . . . . # . # . . # . # .
|
||||
. # . # . . . # . . . . # . . . . # . . . # # # . . . # . . . # # . . . . # . . . . # . . . . # # .
|
||||
. # . # . . . # . . . # . . . . . . # . . . # . . . . . # . . # . # . . # . . . . # . # . . . . # .
|
||||
. . # . . . # # # . . # # # . . # # . . . . # . . . # # . . . . # . . . # . . . . . # . . . # # . .
|
||||
`)
|
||||
startIOMonitor()
|
||||
while (true) {
|
||||
splashScreen()
|
||||
if (buttonB()) {
|
||||
basic.showAnimation(`
|
||||
. . . . . # # . . . . # . . . . # . . . . . . # . . . . . .
|
||||
. . . . # . . . . # # # . . # . # . . # . . # . # . . . . #
|
||||
. . . . # . . . . # . . . . # # # . . # # # . . # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# . . . # # . . . # # . . . # # . . . # # . . . # # . . . #
|
||||
`, 400)
|
||||
let finalScore = surgery()
|
||||
if (game.score() > highScore) {
|
||||
basic.showString("HI", 150)
|
||||
highScore = finalScore
|
||||
}
|
||||
flashDigit(finalScore)
|
||||
waitButtonB()
|
||||
} else if (buttonA()) {
|
||||
testMode()
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function surgery(): number {
|
||||
let score = 0
|
||||
let speed = 150
|
||||
let opStartTime = input.runningTime()
|
||||
let procStartTime = -1
|
||||
let procNumber = -1
|
||||
let procsDone = 0
|
||||
let recoveryTry = 0
|
||||
let timer = 0
|
||||
let state = "CHOOSE PROC"
|
||||
resetButtons()
|
||||
while (true) {
|
||||
basic.pause(10)
|
||||
let event = getEvent(state)
|
||||
if (event == "CUT") {
|
||||
state = "ARREST"
|
||||
}
|
||||
// CHECK TIMERS
|
||||
if (!(procStartTime == -1)) {
|
||||
if (input.runningTime() - procStartTime > procMaxTime) {
|
||||
state = "LOST"
|
||||
} else {
|
||||
// TODO add code here to speed up near end of proc
|
||||
}
|
||||
}
|
||||
if (input.runningTime() - opStartTime > opMaxTime) {
|
||||
state = "LOST"
|
||||
} else {
|
||||
// TODO add code here to speed up near end of op
|
||||
}
|
||||
// PROCESS SPECIFIC STATES
|
||||
if (state == "CHOOSE PROC") {
|
||||
if (procNumber == -1) {
|
||||
procNumber = 1
|
||||
showDigit(procNumber)
|
||||
} else if (event == "SCROLL") {
|
||||
procNumber = procNumber + 1
|
||||
if (procNumber > 9) {
|
||||
procNumber = 1
|
||||
}
|
||||
showDigit(procNumber)
|
||||
} else if (event == "SELECT") {
|
||||
procStartTime = input.runningTime()
|
||||
state = "HEALTHY"
|
||||
speed = 100
|
||||
}
|
||||
} else if (state == "HEALTHY") {
|
||||
speed = 100
|
||||
ecg(speed)
|
||||
if (event == "TWINGE") {
|
||||
state = "TENSE"
|
||||
timer = input.runningTime()
|
||||
} else if (event == "DONE") {
|
||||
state = "PROC DONE"
|
||||
}
|
||||
} else if (state == "TENSE") {
|
||||
speed = 25
|
||||
ecg(speed)
|
||||
if (event == "TWINGE") {
|
||||
state = "ARREST"
|
||||
} else if (input.runningTime() - timer > tenseTime) {
|
||||
state = "HEALTHY"
|
||||
}
|
||||
} else if (state == "ARREST") {
|
||||
timer = input.runningTime()
|
||||
recoveryTry = recoveryTriesMax
|
||||
state = "FLATLINE"
|
||||
} else if (state == "FLATLINE") {
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. # . # .
|
||||
. . . . .
|
||||
. . . . .
|
||||
# # # # #
|
||||
`)
|
||||
beepOn()
|
||||
if (event == "SHOCK") {
|
||||
state = "SHOCKING"
|
||||
} else if (input.runningTime() - timer > flatlineTimeMax) {
|
||||
state = "LOST"
|
||||
}
|
||||
} else if (state == "SHOCKING") {
|
||||
charging()
|
||||
basic.showAnimation(`
|
||||
. . . . # . . . . # . . . . . . . . . .
|
||||
. . . # . . . . # . . . . # . . . . . .
|
||||
. . . . . . . # . . . . # . . . . # . .
|
||||
. . . . . . . . . . . # . . . . # . . .
|
||||
. . . . . . . . . . . . . . . . # . . .
|
||||
`, 150)
|
||||
beepNTimesFor(15, 500)
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . # . . . #
|
||||
. . . . . . . . . . # . . # . . . . . .
|
||||
. . . . . # . # . . . . . . . . . . . .
|
||||
. # . . . . # . . . . . . . . . . . . .
|
||||
. # . . . . # . . . . # . . . . # . . .
|
||||
`, 150)
|
||||
state = "SHOCKED"
|
||||
} else if (state == "SHOCKED") {
|
||||
let recover = Math.randomInt(100)
|
||||
if (recover >= recoveryProbability) {
|
||||
state = "RECOVERED"
|
||||
} else {
|
||||
state = "FAILED"
|
||||
}
|
||||
} else if (state == "RECOVERED") {
|
||||
beepOff()
|
||||
basic.pause(500)
|
||||
beep()
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. # . # . . . . . . . # . # . . . . . . . # . # .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
# . . . # . . . . . # . . . # . . . . . # . . . #
|
||||
. # # # . . . . . . . # # # . . . . . . . # # # .
|
||||
`, 400)
|
||||
state = "HEALTHY"
|
||||
} else if (state == "FAILED") {
|
||||
recoveryTry = recoveryTry - 1
|
||||
if (recoveryTry > 0) {
|
||||
state = "FLATLINE"
|
||||
} else {
|
||||
state = "LOST"
|
||||
}
|
||||
} else if (state == "PROC DONE") {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . #
|
||||
. . . . . . . . . . . . . . . . . . # . . . . # .
|
||||
# . . . . # . . . . # . # . . # . # . . # . # . .
|
||||
. . . . . . # . . . . # . . . . # . . . . # . . .
|
||||
`, 400)
|
||||
score = score + pointsForProc(procNumber)
|
||||
procsDone = procsDone + 1
|
||||
procStartTime = -1
|
||||
if (procsDone == procsToDo) {
|
||||
state = "OP DONE"
|
||||
} else {
|
||||
procNumber = -1
|
||||
state = "CHOOSE PROC"
|
||||
}
|
||||
} else if (state == "OP DONE") {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . # . . # . . . . . # . . . . . # . . . . . # . . # . . . . # . . . . . . . . . . . . . . . . .
|
||||
. . . . # . . # . # . # . . # . . # . . . . . # . . . . . # . . # . . . . # . . . # . . . # . . . . . . . . .
|
||||
# # # # # # # . . # # # . . # . # # . . . . # # . . . . # # . # # . . . . # . . . # . . . # . . . . . . . . .
|
||||
# # # # # # # # # # # # # # # . # # # # . . # # # . . . # # . . . # # . . # # # . # . # # # . . # # . . . # #
|
||||
# . . . # # . . . # # . . . # . # . . . . . # . . . . . # . . . . # . . . . # . . # . # . # . . # . . . . # .
|
||||
`, 400)
|
||||
return score
|
||||
} else if (state == "LOST") {
|
||||
beepOn()
|
||||
basic.showLeds(`
|
||||
. # . # .
|
||||
. . # . .
|
||||
. # . # .
|
||||
. . . . .
|
||||
# # # # #
|
||||
`)
|
||||
basic.pause(3000)
|
||||
beepOff()
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . # # # # # # . . . . # . . . . # . . . . # # . # . # . . . . # # . # . # . . . . #
|
||||
# # # # # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . #
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# . . . # # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # # . . . #
|
||||
`, 400)
|
||||
return score
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if any button pressed, terminate the animation immediately
|
||||
*/
|
||||
function splashScreen() {
|
||||
let img = images.createImage(`
|
||||
. # . # . . # . # . . # . # . . # . # . . . # . . . # # . .
|
||||
# # # # # # . # . # # # # # # # . # . # . # . # . . # . # .
|
||||
# # # # # # . . . # # # # # # # . . . # . # . # . . # # . .
|
||||
. # # # . . # . # . . # # # . . # . # . . # . # . . # . . .
|
||||
. . # . . . . # . . . . # . . . . # . . . . # . . . # . . .
|
||||
`)
|
||||
let x = 0
|
||||
while (!aWasPressed && !bWasPressed) {
|
||||
img.showImage(x)
|
||||
basic.pause(500)
|
||||
x = x + 5
|
||||
if (x >= img.width()) {
|
||||
x = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test sensing and buzzing
|
||||
* I/O at moment is (assuming self toning beeper)
|
||||
* P0 is beeper and nose LED
|
||||
* P1 is the tweezer sense wire
|
||||
* P2 is possibly the nose button
|
||||
* If we want amplification, might have to use piezo library
|
||||
* which means using extra pins
|
||||
*/
|
||||
function testMode() {
|
||||
while (!(buttonA())) {
|
||||
if (pins.digitalReadPin(DigitalPin.P1) == 1) {
|
||||
pins.digitalWritePin(DigitalPin.P0, 1)
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. . . . #
|
||||
. . . # .
|
||||
# . # . .
|
||||
. # . . .
|
||||
`)
|
||||
} else {
|
||||
pins.digitalWritePin(DigitalPin.P0, 0)
|
||||
basic.showLeds(`
|
||||
# # # # #
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
`)
|
||||
}
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SENSE TWINGE/CUT FROM TWEEZERS (10ms per sample)
|
||||
* @param state TODO
|
||||
*/
|
||||
function getEvent(state: string): string {
|
||||
if (wasTweezers) {
|
||||
if (tweezerCount_ > 20) {
|
||||
wasTweezers = false
|
||||
tweezerCount_ = 0
|
||||
return "CUT"
|
||||
} else if (!isTweezers) {
|
||||
wasTweezers = false
|
||||
tweezerCount_ = 0
|
||||
return "TWINGE"
|
||||
}
|
||||
}
|
||||
// SENSE A OR B BUTTON PRESSES
|
||||
if (state == "CHOOSE PROC") {
|
||||
if (buttonA()) {
|
||||
return "SCROLL"
|
||||
} else if (buttonB()) {
|
||||
return "SELECT"
|
||||
}
|
||||
} else if (state == "FLATLINE") {
|
||||
if (buttonB()) {
|
||||
return "SHOCK"
|
||||
} else if (nose()) {
|
||||
return "SHOCK"
|
||||
}
|
||||
} else if (state == "HEALTHY") {
|
||||
if (buttonB()) {
|
||||
return "DONE"
|
||||
}
|
||||
}
|
||||
// Clear any flags for unnecessary events in a given state to prevent latching
|
||||
aWasPressed = false
|
||||
bWasPressed = false
|
||||
return "NONE"
|
||||
}
|
||||
|
||||
function flashDigit(digit: number) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
showDigit(digit)
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
basic.pause(200)
|
||||
}
|
||||
showDigit(digit)
|
||||
basic.pause(1000)
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a short beep sound
|
||||
*/
|
||||
function beep() {
|
||||
beepOn()
|
||||
basic.pause(200)
|
||||
beepOff()
|
||||
}
|
||||
|
||||
/**
|
||||
* work out score for a procedure
|
||||
* @param procNumber TODO
|
||||
*/
|
||||
function pointsForProc(procNumber: number): number {
|
||||
if (procNumber < 4) {
|
||||
return 1
|
||||
} else if (procNumber < 7) {
|
||||
return 2
|
||||
} else {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* beep n times, for a total duration of m
|
||||
* @param times TODO
|
||||
* @param duration TODO
|
||||
*/
|
||||
function beepNTimesFor(times: number, duration: number) {
|
||||
let halfCycle = duration / (times * 2)
|
||||
for (let i = 0; i < times; i++) {
|
||||
beepOn()
|
||||
basic.pause(halfCycle)
|
||||
beepOff()
|
||||
basic.pause(halfCycle)
|
||||
}
|
||||
}
|
||||
|
||||
function startIOMonitor() {
|
||||
aWasPressed = false
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
aWasPressed = true
|
||||
})
|
||||
bWasPressed = false
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
bWasPressed = true
|
||||
})
|
||||
wasTweezers = false
|
||||
isTweezers = false
|
||||
tweezerCount_ = 0
|
||||
control.inBackground(() => {
|
||||
let buzzCount = 0
|
||||
while (true) {
|
||||
if (pins.digitalReadPin(DigitalPin.P0) == 1) {
|
||||
wasTweezers = true
|
||||
isTweezers = true
|
||||
tweezerCount_ = tweezerCount_ + 1
|
||||
if (buzzCount == 0) {
|
||||
pins.analogWritePin(AnalogPin.P2, 512)
|
||||
pins.analogSetPeriod(AnalogPin.P2, 5000)
|
||||
}
|
||||
buzzCount = 10
|
||||
} else {
|
||||
isTweezers = false
|
||||
}
|
||||
if (buzzCount > 0) {
|
||||
buzzCount = buzzCount - 1
|
||||
if (buzzCount == 0) {
|
||||
pins.analogWritePin(AnalogPin.P2, 0)
|
||||
}
|
||||
}
|
||||
basic.pause(10)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a single digit, with a nicer font than the standard micro:bit font
|
||||
* @param digit TODO
|
||||
*/
|
||||
function showDigit(digit: number) {
|
||||
digit = Math.clamp(0, 9, digit)
|
||||
digitsImg.showImage(digit * 5)
|
||||
}
|
||||
|
||||
/**
|
||||
* check to see if button A was pressed recently
|
||||
*/
|
||||
function buttonA(): boolean {
|
||||
if (aWasPressed) {
|
||||
aWasPressed = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function waitButtonA() {
|
||||
while (!(buttonA())) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function buttonB(): boolean {
|
||||
if (bWasPressed) {
|
||||
bWasPressed = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function waitButtonB() {
|
||||
while (!(buttonB())) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function beepOn() {
|
||||
pins.analogWritePin(AnalogPin.P2, 512)
|
||||
pins.analogSetPeriod(AnalogPin.P2, 2272)
|
||||
}
|
||||
|
||||
function beepOff() {
|
||||
pins.analogWritePin(AnalogPin.P2, 0)
|
||||
}
|
||||
|
||||
function resetButtons() {
|
||||
aWasPressed = false
|
||||
bWasPressed = false
|
||||
}
|
||||
|
||||
function ecg(speed: number) {
|
||||
beepOn()
|
||||
pins.digitalWritePin(DigitalPin.P1, 1)
|
||||
basic.pause(50)
|
||||
beepOff()
|
||||
basic.showAnimation(`
|
||||
. . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . .
|
||||
. . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . .
|
||||
. . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . .
|
||||
. . . . # . . . # # . . # # . . # # . . # # . . . # . . . . . . . . .
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
`, speed)
|
||||
pins.digitalWritePin(DigitalPin.P1, 0)
|
||||
basic.pause(speed * 10)
|
||||
}
|
||||
|
||||
function nose(): boolean {
|
||||
if (wasNose) {
|
||||
wasNose = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* start period in microseconds
|
||||
*/
|
||||
function charging() {
|
||||
let period = 2000
|
||||
let dec = 500
|
||||
pins.analogWritePin(AnalogPin.P2, 512)
|
||||
pins.analogSetPeriod(AnalogPin.P2, period)
|
||||
basic.showLeds(`
|
||||
. # # . .
|
||||
. . . # .
|
||||
. . # . .
|
||||
. . . # .
|
||||
. # # . .
|
||||
`)
|
||||
basic.pause(500)
|
||||
pins.analogSetPeriod(AnalogPin.P2, period - dec)
|
||||
basic.showLeds(`
|
||||
. # # . .
|
||||
. . . # .
|
||||
. . # . .
|
||||
. # . . .
|
||||
. # # # .
|
||||
`)
|
||||
basic.pause(500)
|
||||
pins.analogSetPeriod(AnalogPin.P2, period - dec * 2)
|
||||
basic.showLeds(`
|
||||
. . # . .
|
||||
. # # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
. # # # .
|
||||
`)
|
||||
basic.pause(500)
|
||||
beepOff()
|
||||
}
|
178
tests/wg-operator-reaction-test.ts
Normal file
178
tests/wg-operator-reaction-test.ts
Normal file
@ -0,0 +1,178 @@
|
||||
let wasShake: boolean
|
||||
|
||||
input.onShake(() => {
|
||||
wasShake = true
|
||||
})
|
||||
wait_6Hours()
|
||||
timeForTest()
|
||||
alertnessTest()
|
||||
wait_2Hours()
|
||||
timeForTest()
|
||||
alertnessTest()
|
||||
wait_2Hours()
|
||||
timeForTest()
|
||||
alertnessTest()
|
||||
|
||||
/**
|
||||
* animate back to work
|
||||
* animate take a rest
|
||||
*/
|
||||
function animations() { }
|
||||
|
||||
/**
|
||||
* wait 6 hours
|
||||
* because this is a test program, we only wait for a short time
|
||||
*/
|
||||
function wait_6Hours() {
|
||||
basic.showAnimation(`
|
||||
. . # . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # . . . .
|
||||
. . # . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . .
|
||||
. . # . . . . # . . . . # # # . . # . . . . # . . . . # . . # # # . . . . # . .
|
||||
. . . . . . . . . . . . . . . . . . # . . . # . . . # . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . # . . # . . # . . . . . . . . . . . . . .
|
||||
`, 500)
|
||||
}
|
||||
|
||||
/**
|
||||
* wait for 2 hours
|
||||
* because this is test code, we only wait a few seconds
|
||||
*/
|
||||
function wait_2Hours() {
|
||||
basic.showAnimation(`
|
||||
. . # . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # . . . .
|
||||
. . # . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . .
|
||||
. . # . . . . # . . . . # # # . . # . . . . # . . . . # . . # # # . . . . # . .
|
||||
. . . . . . . . . . . . . . . . . . # . . . # . . . # . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . # . . # . . # . . . . . . . . . . . . . .
|
||||
`, 500)
|
||||
}
|
||||
|
||||
function alertnessTest() {
|
||||
let goodResponse = 1000
|
||||
let threshold = 5
|
||||
let score = 0
|
||||
// Start test on button press
|
||||
let x = 0
|
||||
let start = images.createImage(`
|
||||
. . # . . . . # . .
|
||||
. . # . . . # . # .
|
||||
. . # . . . . . # .
|
||||
. . . . . . . # . .
|
||||
. . # . . . . # . .
|
||||
`)
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
start.showImage(x)
|
||||
x = x + 5
|
||||
if (x >= start.width()) {
|
||||
x = 0
|
||||
}
|
||||
basic.pause(300)
|
||||
}
|
||||
// Wait for button(s) to be released
|
||||
while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
// Run 10 random cognition response tests
|
||||
for (let i = 0; i < 9; i++) {
|
||||
// Choose random delay and random outcome
|
||||
let delay = Math.randomInt(5) + 5
|
||||
let outcome = Math.randomInt(2)
|
||||
// Draw moving dots on screen until delay expires
|
||||
basic.clearScreen()
|
||||
for (let j = 0; j < delay; j++) {
|
||||
led.plot(j % 5, 2)
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
}
|
||||
// Show shake or button icon
|
||||
if (outcome == 0) {
|
||||
// Press the button!
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. # # # .
|
||||
. # # # .
|
||||
. # # # .
|
||||
. . . . .
|
||||
`)
|
||||
} else {
|
||||
// Shake the bit!
|
||||
basic.showLeds(`
|
||||
# . # . .
|
||||
# . . # .
|
||||
# # # # #
|
||||
# . . # .
|
||||
# . # . .
|
||||
`)
|
||||
}
|
||||
// Wait up to 3 seconds for button, shake, or timeout
|
||||
wasShake = false
|
||||
let timer = input.runningTime()
|
||||
let timeout = 3000
|
||||
while (input.runningTime() < timer + timeout) {
|
||||
if (wasShake) {
|
||||
break
|
||||
} else if (input.buttonIsPressed(Button.B)) {
|
||||
break
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
// Assess the response and the response time
|
||||
let response = input.runningTime() - timer
|
||||
if (outcome == 0 && input.buttonIsPressed(Button.B) && response <= goodResponse) {
|
||||
score = score + 1
|
||||
} else if (outcome == 1 && wasShake && response <= goodResponse) {
|
||||
score = score + 1
|
||||
}
|
||||
}
|
||||
// Show final score flashing 5 times (0..9)
|
||||
for (let k = 0; k < 5; k++) {
|
||||
basic.showNumber(score, 0)
|
||||
basic.pause(250)
|
||||
basic.clearScreen()
|
||||
basic.pause(250)
|
||||
}
|
||||
basic.showNumber(score, 0)
|
||||
basic.pause(500)
|
||||
if (score < threshold) {
|
||||
// Time for a break, show coffee cup animation
|
||||
for (let l = 0; l < 3; l++) {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . # . . . . # . . . . . . . . . . # . . . . # . . . . . . .
|
||||
. . . . . . # . . . . # . . . . . . . . . . # . . . . # . . . . . . . . . . . .
|
||||
# . . # . # # . # . # . . # . # . . # . # . # # . # . . # . # . . # . # . . # .
|
||||
# . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # #
|
||||
# # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # .
|
||||
`, 400)
|
||||
}
|
||||
} else {
|
||||
// All ok, back to work, show digging animation
|
||||
for (let m = 0; m < 3; m++) {
|
||||
basic.showAnimation(`
|
||||
# . # . . # . . . . # . . . .
|
||||
. # # . . . # . # . . # . . .
|
||||
# # # . . . . # # . . . # . #
|
||||
. . . . . . # # # . . . . # #
|
||||
. . . . . . . . . . . . # # #
|
||||
`, 400)
|
||||
}
|
||||
}
|
||||
// Wait for any button press to finish test
|
||||
while (!input.buttonIsPressed(Button.A) && !input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* alert the user it is time to take the test
|
||||
* in a real system, this might give them 5 1 minute warnings
|
||||
*/
|
||||
function timeForTest() {
|
||||
basic.showAnimation(`
|
||||
. # # # . . # . . . . # # . . . # # . . . . # . .
|
||||
. # . . . . # . . . . . . # . . . . # . . # # . .
|
||||
. . # . . . # # # . . # # . . . . # . . . . # . .
|
||||
. . . # . . . # . . . . . # . . # . . . . . # . .
|
||||
. # # . . . . # . . . # # . . . # # # . . # # # .
|
||||
`, 700)
|
||||
}
|
157
tests/wg-paintroller.ts
Normal file
157
tests/wg-paintroller.ts
Normal file
@ -0,0 +1,157 @@
|
||||
let maxGameTime: number
|
||||
let wasShake: boolean
|
||||
|
||||
maxGameTime = 60000
|
||||
input.onShake(() => {
|
||||
wasShake = true
|
||||
})
|
||||
while (true) {
|
||||
splashScreen()
|
||||
if (input.buttonIsPressed(Button.B)) {
|
||||
basic.showAnimation(`
|
||||
# # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # # #
|
||||
# # # . . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # . . # . . . . # . . . . # . . . . # . . . . # # # # # # # # # #
|
||||
# # # . . # # # . . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # . . # # # . . # # # . . # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # # . . # # # . # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
`, 400)
|
||||
let score = playOneGame()
|
||||
flashDigit(score, 5)
|
||||
waitButtonB()
|
||||
basic.showAnimation(`
|
||||
# # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
# # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . # . # . . . . . .
|
||||
# # # # # # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
# # # # # # # # # # # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
`, 400)
|
||||
} else if (input.buttonIsPressed(Button.A)) {
|
||||
calibrate()
|
||||
}
|
||||
}
|
||||
|
||||
function playOneGame(): number {
|
||||
let countDots = 0
|
||||
let x = 2
|
||||
let y = 2
|
||||
let xdir = true
|
||||
let canvas = images.createImage(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
wasShake = false
|
||||
let bearing = input.compassHeading()
|
||||
let startTime = input.runningTime()
|
||||
while (countDots < 25 && input.runningTime() - startTime < maxGameTime) {
|
||||
if (wasShake) {
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . # # # . . . # . . . # # # . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . . . . . .
|
||||
. . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . .
|
||||
. # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . .
|
||||
`, 50)
|
||||
let pos = Math.randomInt(5)
|
||||
if (xdir) {
|
||||
if (!canvas.pixel(pos, y)) {
|
||||
canvas.setPixel(pos, y, true)
|
||||
countDots = countDots + 1
|
||||
}
|
||||
} else if (!canvas.pixel(x, pos)) {
|
||||
canvas.setPixel(x, pos, true)
|
||||
countDots = countDots + 1
|
||||
}
|
||||
wasShake = false
|
||||
canvas.showImage(0)
|
||||
} else if (Math.abs(input.compassHeading() - bearing) > 60) {
|
||||
xdir = !xdir
|
||||
bearing = input.compassHeading()
|
||||
if (xdir) {
|
||||
x = Math.randomInt(5)
|
||||
} else {
|
||||
y = Math.randomInt(5)
|
||||
}
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
return dotsToScore(countDots)
|
||||
}
|
||||
|
||||
function splashScreen() {
|
||||
let img = images.createImage(`
|
||||
# # # # . # # # # . # # # # . # # # # . # # # # . # # # # . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . # # . . # # # . # # # # . # # # # . . # # # . . . # # . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # . # # # # . # # # # . # # # # . # # # # .
|
||||
# . . . # # . . . # # . . . # # . . . # # . . . # . # # # . . . # . . . # # # . . . . . . . . . . . . . . . . . . . . . # . . . . . # . . . . . # . . . . . # . . . . . # . . . # # . . # . # . # . . # # . . . # # . . . # # . . . # # . . . # . # . . # . . # . # . . . # # . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . # . . . # # # . # . . . # # . . . # # . . . # # . . . #
|
||||
# # # # . # # # # . # # # # . # # # # . . # # # . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # # # # # # . # # # . . # # . . . # . . . . . . . . . . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . # # # . # # # # . # # # # . # # # # .
|
||||
# . . . . # . . . . # . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . # . . . . . # . . . . . # . . . . . # . . . . . # . . . # . . . # # . . # . # . # . . # . # . . # . # . . # . # . . # . . # . # . . . # # . . . . # . . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . # . . . . # . . . .
|
||||
# . . . . # . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # . . . . # . . . . # # . . . # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . # . . . .
|
||||
`)
|
||||
let x = 0
|
||||
while (!input.buttonIsPressed(Button.A) && !input.buttonIsPressed(Button.B)) {
|
||||
img.showImage(x)
|
||||
basic.pause(200)
|
||||
x = x + 5
|
||||
if (x >= img.width()) {
|
||||
x = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rotate canvas
|
||||
*/
|
||||
function rotateImage() { }
|
||||
|
||||
function flashDigit(digit: number, times: number) {
|
||||
for (let i = 0; i < times; i++) {
|
||||
basic.showNumber(digit, 0)
|
||||
basic.pause(500)
|
||||
basic.clearScreen()
|
||||
basic.pause(500)
|
||||
}
|
||||
basic.showNumber(digit, 0)
|
||||
}
|
||||
|
||||
function waitButtonB() {
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function dotsToScore(dots: number): number {
|
||||
if (dots == 25) {
|
||||
return 9
|
||||
} else if (dots >= 22) {
|
||||
return 8
|
||||
} else if (dots >= 19) {
|
||||
return 7
|
||||
} else if (dots >= 16) {
|
||||
return 6
|
||||
} else if (dots >= 13) {
|
||||
return 5
|
||||
} else if (dots >= 10) {
|
||||
return 4
|
||||
} else if (dots >= 7) {
|
||||
return 3
|
||||
} else if (dots >= 4) {
|
||||
return 2
|
||||
} else if (dots >= 1) {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
function calibrate() {
|
||||
basic.showString("CAL", 150)
|
||||
if (input.compassHeading() == -4) {
|
||||
input.calibrate()
|
||||
}
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
let h = input.compassHeading()
|
||||
basic.showNumber(h, 150)
|
||||
}
|
||||
}
|
267
tests/wg-perfect-pancakes.ts
Normal file
267
tests/wg-perfect-pancakes.ts
Normal file
@ -0,0 +1,267 @@
|
||||
let state: string
|
||||
let timer: number
|
||||
let gesturesRunning: boolean
|
||||
let wasShake: boolean
|
||||
let wasLogoUp: boolean
|
||||
let wasLogoDown: boolean
|
||||
let wasScreenUp: boolean
|
||||
let wasScreenDown: boolean
|
||||
|
||||
while (true) {
|
||||
splashScreen()
|
||||
if (input.buttonIsPressed(Button.B)) {
|
||||
// animate: add pancake
|
||||
basic.showAnimation(`
|
||||
# # # # # # . . . # . . . . . . . . . . . . . . .
|
||||
. . . . . . # # # . . # # # . . . . . . . . . . .
|
||||
. . . . . . . . . . # . . . # # . . . # . . . . .
|
||||
. . . . . . . . . . . . . . . . # # # . . # # # .
|
||||
. . . . . . . . . . . . . . . . . . . . # . . . #
|
||||
`, 250)
|
||||
runGameOnce()
|
||||
// animate: pancake done
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . # . . . # # # # # # # . . . # . . . . . . . . . . . # . # . . . . . . . # . # . . . . . .
|
||||
. . . . . . . . . . . # # # . # # # # # . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
# . . . # # # # # # # . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
`, 250)
|
||||
} else if (input.buttonIsPressed(Button.A)) {
|
||||
testShake()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs one complete game from start to end
|
||||
*/
|
||||
function runGameOnce() {
|
||||
let score = 0
|
||||
let cooks = 0
|
||||
let target_time = 0
|
||||
// make sure no gestures are outstanding from last game
|
||||
wasShake = false
|
||||
wasLogoUp = false
|
||||
wasLogoDown = false
|
||||
wasScreenUp = false
|
||||
wasScreenDown = false
|
||||
state = "NEWSIDE"
|
||||
while (true) {
|
||||
// Handle any gestures that can happen at any time
|
||||
let gesture = getGesture()
|
||||
if (gesture == "FLOOR") {
|
||||
state = "DROPPED"
|
||||
}
|
||||
// Run code appropriate to the present state of the game
|
||||
if (state == "NEWSIDE") {
|
||||
target_time = 5 + Math.randomInt(5)
|
||||
state = "COOKING"
|
||||
startTimer()
|
||||
} else if (state == "COOKING") {
|
||||
// animate: cooking
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . # . . . . . . . . . . . . . #
|
||||
# # # # # . # # # # # # # # # # # # # .
|
||||
`, 100)
|
||||
|
||||
if (gesture == "FLIP") {
|
||||
state = "FLIPPING"
|
||||
} else if (getTimerSec() >= target_time) {
|
||||
state = "READY"
|
||||
score = score + 1
|
||||
startTimer()
|
||||
}
|
||||
} else if (state == "READY") {
|
||||
// animate: ready
|
||||
basic.showAnimation(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
# . . . #
|
||||
. # # # .
|
||||
`, 100)
|
||||
if (getTimerSec() > 2) {
|
||||
state = "BURNING"
|
||||
score = score - 1
|
||||
startTimer()
|
||||
} else if (gesture == "FLIP") {
|
||||
state = "FLIPPING"
|
||||
}
|
||||
} else if (state == "BURNING") {
|
||||
// animate: burning
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . # . . . . # .
|
||||
. . . . . . . . # . . # . # . . # . . .
|
||||
. . . . . . # . # . . # . . . . . . . .
|
||||
. . . . . . # . . . . . . . . . . . . .
|
||||
# # # # # # # # # # # # # # # # # # # #
|
||||
`, 100)
|
||||
if (gesture == "SKY") {
|
||||
state = "NEWSIDE"
|
||||
} else if (getTimerSec() > 2) {
|
||||
state = "BURNT"
|
||||
}
|
||||
} else if (state == "FLIPPING") {
|
||||
// animate: flipping
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . # # # # # . # # . . . # # # . . . # # . # # # # # . . . . . . . . . .
|
||||
. . . . . . . . . . # # # # # . . . . . . . . # # . # # # . # # . . . . . . . . # # # # # . . . . .
|
||||
. . . . . # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # # #
|
||||
# # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
`, 100)
|
||||
// Prevent a spurious double-flip from happening
|
||||
wasShake = false
|
||||
cooks = cooks + 1
|
||||
if (cooks == 5) {
|
||||
state = "GAMEOVER"
|
||||
} else {
|
||||
state = "NEWSIDE"
|
||||
}
|
||||
} else if (state == "DROPPED") {
|
||||
// animate: dropped
|
||||
basic.showAnimation(`
|
||||
# . . . # . . . . . # . . . # . . . . .
|
||||
. # . # . . . . . . . # . # . . . . . .
|
||||
. . # . . . . . . . . . # . . . . . . .
|
||||
. # . # . . . . . . . # . # . . . . . .
|
||||
# . . . # . . . . . # . . . # . . . . .
|
||||
`, 250)
|
||||
score = 0
|
||||
state = "GAMEOVER"
|
||||
} else if (state == "BURNT") {
|
||||
// animate: burnt
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . # . # . . . . . . . # # # .
|
||||
. . . . . . . . . . . . . . . . . # . . . . . . . . # . # . . . . . . . # # # . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . # # # . . . . . . . . . . .
|
||||
. . . . . . # . # . . # # # . . # . # . . . . . . . # # # . . . . . . . . . . . . . . . .
|
||||
# # # # # . # # # . . # # # . . # # # . . # # # . . . . . . . . . . . . . . . . . . . . .
|
||||
`, 250)
|
||||
score = 0
|
||||
state = "GAMEOVER"
|
||||
} else if (state == "GAMEOVER") {
|
||||
animateScore(score)
|
||||
state = "WAITEJECT"
|
||||
} else if (state == "WAITEJECT") {
|
||||
if (gesture == "UPSIDEDOWN") {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show score (0..9) flashing
|
||||
* @param score TODO
|
||||
*/
|
||||
function animateScore(score: number) {
|
||||
score = Math.clamp(0, 9, score)
|
||||
for (let i = 0; i < 5; i++) {
|
||||
basic.showNumber(score, 0)
|
||||
basic.pause(500)
|
||||
basic.clearScreen()
|
||||
basic.pause(500)
|
||||
}
|
||||
basic.showNumber(score, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Eventually this will move into a gesture library
|
||||
* It hides all the nasty detail of detecting gestures
|
||||
*/
|
||||
function getGesture(): string {
|
||||
if (!gesturesRunning) {
|
||||
input.onShake(() => {
|
||||
wasShake = true
|
||||
})
|
||||
input.onLogoUp(() => {
|
||||
wasLogoUp = true
|
||||
})
|
||||
input.onLogoDown(() => {
|
||||
wasLogoDown = true
|
||||
})
|
||||
input.onScreenUp(() => {
|
||||
wasScreenUp = true
|
||||
})
|
||||
input.onScreenDown(() => {
|
||||
wasScreenDown = true
|
||||
})
|
||||
gesturesRunning = true
|
||||
}
|
||||
// work out which of a possible set of gestures has occurred:
|
||||
// Button gestures and movement gestures both handled
|
||||
// This is so that it is easy to also use this on the simulator too
|
||||
// Generally, B is used for normal OK, A is used for abnormal RECOVERY
|
||||
// (flip is a normal action, touch sky to turn off smoke alarm is recovery)
|
||||
let a = input.buttonIsPressed(Button.A)
|
||||
let b = input.buttonIsPressed(Button.B)
|
||||
if (state == "COOKING" || state == "READY") {
|
||||
if (b || wasShake) {
|
||||
wasShake = false
|
||||
return "FLIP"
|
||||
}
|
||||
} else if (state == "FLIPPING") {
|
||||
if (a || wasLogoDown) {
|
||||
wasLogoDown = false
|
||||
return "FLOOR"
|
||||
}
|
||||
} else if (state == "BURNING") {
|
||||
if (a || wasLogoUp) {
|
||||
wasLogoUp = false
|
||||
return "SKY"
|
||||
}
|
||||
} else if (state == "GAMEOVER" || state == "WAITEJECT") {
|
||||
if (b || wasScreenDown) {
|
||||
wasScreenDown = false
|
||||
return "UPSIDEDOWN"
|
||||
}
|
||||
}
|
||||
return "NONE"
|
||||
}
|
||||
|
||||
/**
|
||||
* start timer by sampling runningtime and storing into starttime
|
||||
*/
|
||||
function startTimer() {
|
||||
timer = input.runningTime()
|
||||
}
|
||||
|
||||
/**
|
||||
* get the elapsed time from the global starttime with ref to running time
|
||||
* in seconds.
|
||||
*/
|
||||
function getTimerSec(): number {
|
||||
let t = (input.runningTime() - timer) / 1000
|
||||
return t
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a splash screen "Perfect Pancakes >>>"
|
||||
* Splash screen "PP" with little arrow pointing to the start button
|
||||
*/
|
||||
function splashScreen() {
|
||||
let splash = images.createImage(`
|
||||
# # # # . . . . . . # # # # . . . . . . . . . . . . . . . . . . . . .
|
||||
# . . . # . . . . . # . . . # # . . . . . # . . . . . # . . . . . # .
|
||||
# # # # . . . . . . # # # # . . # . . . . . # . . . . . # . . . . . #
|
||||
# . . . . . . . . . # . . . . # . . . . . # . . . . . # . . . . . # .
|
||||
# . . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
`)
|
||||
// use show image (not show animation) so that button press is more responsive
|
||||
let index = 0
|
||||
// Any button press finishes the splash screen
|
||||
while (!input.buttonIsPressed(Button.B) && !input.buttonIsPressed(Button.A)) {
|
||||
splash.showImage(index * 5)
|
||||
index = index + 1
|
||||
if (index > splash.width() / 5) {
|
||||
index = 0
|
||||
}
|
||||
basic.pause(250)
|
||||
}
|
||||
}
|
||||
|
||||
function testShake() { }
|
242
tests/wg-right-sugar.ts
Normal file
242
tests/wg-right-sugar.ts
Normal file
@ -0,0 +1,242 @@
|
||||
let sugarThreshold: number
|
||||
let ketoneThreshold: number
|
||||
|
||||
// Important parameters
|
||||
sugarThreshold = 14
|
||||
ketoneThreshold = 6
|
||||
while (true) {
|
||||
// splash screen sugar cube (just the right sugar)
|
||||
basic.showAnimation(`
|
||||
# # # . . . . . . . . . . . . . . . . .
|
||||
# # # . . . # # # . . . . . . . . . . .
|
||||
# # # . . . # # # . . . # # # . . # # #
|
||||
. . . . . . # # # . . . # # # . . # # #
|
||||
. . . . . . . . . . . . # # # . . # # #
|
||||
`, 400)
|
||||
// ask questions and give advice
|
||||
quiz()
|
||||
// wait for button press before restart
|
||||
waitAnyButton()
|
||||
}
|
||||
|
||||
function getSugar(): string {
|
||||
waitNoButtons()
|
||||
let selection = "MID"
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
// high, low, normal?
|
||||
basic.showAnimation(`
|
||||
. . . . . # . # . . . . # . .
|
||||
. # # # . # . # . . . # . # .
|
||||
. # # # . # . # # # . . . # .
|
||||
. # # # . # . . # . . . # . .
|
||||
. . . . . # . . # . . . # . .
|
||||
`, 400)
|
||||
// show low, mid, or high as a bar
|
||||
selection = getLowMidHigh(selection)
|
||||
}
|
||||
return selection
|
||||
}
|
||||
|
||||
function getKetone(): string {
|
||||
waitNoButtons()
|
||||
let selection = "MID"
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
// high, low, normal?
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . # . . . # . .
|
||||
# # . . . . . # . . . # . # .
|
||||
# # # # # . . # # . . . . # .
|
||||
# # . . # . . # . # . . # . .
|
||||
. . . . . # . . # . . . # . .
|
||||
`, 400)
|
||||
// show low, mid, or high as a bar
|
||||
selection = getLowMidHigh(selection)
|
||||
}
|
||||
return selection
|
||||
}
|
||||
|
||||
function getIll(): boolean {
|
||||
waitNoButtons()
|
||||
let selection = false
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
// ask question 'happy or sad'
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . # . . . . # . .
|
||||
. # . # . . # . # . . # . # . . # . # .
|
||||
. . . . . . . . . . . . . # . . . . # .
|
||||
# . . . # . # # # . . . # . . . . # . .
|
||||
. # # # . # . . . # . . # . . . . # . .
|
||||
`, 400)
|
||||
// get answer from user
|
||||
selection = getHappySad(selection)
|
||||
}
|
||||
// if we are happy, we are not ill
|
||||
return !selection
|
||||
}
|
||||
|
||||
function getLowMidHigh(selection: string): string {
|
||||
let timeout = 2000
|
||||
let timer = input.runningTime()
|
||||
while (true) {
|
||||
// show the present level as a line
|
||||
if (selection == "LOW") {
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
# # # # #
|
||||
`)
|
||||
} else if (selection == "HIGH") {
|
||||
basic.showLeds(`
|
||||
# # # # #
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
} else {
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
# # # # #
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
}
|
||||
// process any user input
|
||||
if (input.buttonIsPressed(Button.A)) {
|
||||
// cycle round the 3 possible levels
|
||||
if (selection == "LOW") {
|
||||
selection = "MID"
|
||||
} else if (selection == "MID") {
|
||||
selection = "HIGH"
|
||||
} else {
|
||||
selection = "LOW"
|
||||
}
|
||||
// This is the 'hold repeat' time if you hold the A button
|
||||
basic.pause(300)
|
||||
// restart timer, 2 seconds of inactivity before return to main
|
||||
timer = input.runningTime()
|
||||
} else if (input.buttonIsPressed(Button.B)) {
|
||||
// user is selecting so better return quickly
|
||||
return selection
|
||||
} else if (input.runningTime() > timer + timeout) {
|
||||
// timeout, so return to main to re-prompt user
|
||||
return selection
|
||||
} else {
|
||||
// This slows the loop down to stop the emulator being busy
|
||||
// and also preserves battery life on the micro:bit
|
||||
// it also affects the worst case response time
|
||||
// it also affects the response time
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for all buttons to be released
|
||||
* This prevents spurious selection in next question
|
||||
*/
|
||||
function waitNoButtons() {
|
||||
while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function getHappySad(selection: boolean): boolean {
|
||||
let timeout = 2000
|
||||
let timer = input.runningTime()
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
// Show present selection
|
||||
if (selection) {
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. # . # .
|
||||
. . . . .
|
||||
# . . . #
|
||||
. # # # .
|
||||
`)
|
||||
} else {
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. # . # .
|
||||
. . . . .
|
||||
. # # # .
|
||||
# . . . #
|
||||
`)
|
||||
}
|
||||
// Wait for any change in the selection
|
||||
if (input.buttonIsPressed(Button.A)) {
|
||||
selection = !selection
|
||||
// This is the repeat time if button A held down
|
||||
basic.pause(500)
|
||||
timer = input.runningTime()
|
||||
} else if (input.runningTime() > timer + timeout) {
|
||||
return selection
|
||||
} else {
|
||||
// Preserve battery life on micro:bit and prevent emulator being busy
|
||||
// This is also the response time to a button press
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
return selection
|
||||
}
|
||||
|
||||
/**
|
||||
* Button A changes value, Button B selects value
|
||||
*/
|
||||
function quiz() {
|
||||
let sugar = getSugar()
|
||||
if (sugar != "HIGH") {
|
||||
// All is ok (tick)
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . #
|
||||
. . . . . . . . . . . . . . . . . . # . . . . # .
|
||||
# . . . . # . . . . # . # . . # . # . . # . # . .
|
||||
. . . . . . # . . . . # . . . . # . . . . # . . .
|
||||
`, 400)
|
||||
} else {
|
||||
// Button A changes value, Button B selects value
|
||||
let ketone = getKetone()
|
||||
if (ketone != "HIGH") {
|
||||
// Button A changes value, Button B selects value
|
||||
let ill = getIll()
|
||||
if (!ill) {
|
||||
// Time to rest (jump into bed)
|
||||
basic.showAnimation(`
|
||||
. . . . . # # . . . . # . . . . # . . . . . . # . . . . . .
|
||||
. . . . # . . . . # # # . . # . # . . # . . # . # . . . . #
|
||||
. . . . # . . . . # . . . . # # # . . # # # . . # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# . . . # # . . . # # . . . # # . . . # # . . . # # . . . #
|
||||
`, 400)
|
||||
} else {
|
||||
// Test more often (clock shows 2 hour interval)
|
||||
basic.showAnimation(`
|
||||
. . # . . . . . . . . . . . . . . . . . . # # . . . . . . . . # # . . . . . . . . # # . .
|
||||
. . # . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . # . . . . . . . . . # .
|
||||
. . # . . . . # # # . . # . . # # # . . . . # . . . . . . . . . # . . . . . . . . . # . .
|
||||
. . . . . . . . . . . . # . . . . . . . . # . . . . . . . . . # . . . . . . . . . # . . .
|
||||
. . . . . . . . . . . . # . . . . . . . . # # # . . . . . . . # # # . . . . . . . # # # .
|
||||
`, 400)
|
||||
}
|
||||
} else {
|
||||
// Get some help (call the diabetes care team on the phone)
|
||||
basic.showAnimation(`
|
||||
. . . . . . . . . . # # # # # # # . . . # # . . . # # . . . # # . . . # # # . . # # . # . # # . . #
|
||||
. . . . . # # # # # # . . . # # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . .
|
||||
# # # # # # . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . .
|
||||
# . # . # . . # . . . . # . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . .
|
||||
. # # # . . # # # . . # # # . # # . . . # # . . # # # . # . # # # . . # # . . . # # . . . # # . . .
|
||||
`, 400)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function waitAnyButton() {
|
||||
while (!input.buttonIsPressed(Button.A) && !input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
488
tests/wg-user-confidance.ts
Normal file
488
tests/wg-user-confidance.ts
Normal file
@ -0,0 +1,488 @@
|
||||
let AWasPressed: boolean
|
||||
let BWasPressed: boolean
|
||||
let wasShake: boolean
|
||||
let dots025: Image
|
||||
|
||||
dots025 = images.createImage(`
|
||||
. . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # #
|
||||
`)
|
||||
let tests = "DABPXYZSCT"
|
||||
let test = 0
|
||||
let prevTest = -1
|
||||
startIOMonitor()
|
||||
while (true) {
|
||||
let testLetter = tests[test]
|
||||
let autoRun = false
|
||||
if (testLetter == "D" || testLetter == "A" || testLetter == "B") {
|
||||
autoRun = true
|
||||
}
|
||||
if (!(test == prevTest)) {
|
||||
basic.showString(tests[test], 200)
|
||||
prevTest = test
|
||||
}
|
||||
if (AWasPressed || autoRun) {
|
||||
AWasPressed = false
|
||||
if (testLetter == "D") {
|
||||
testDisplay()
|
||||
test = test + 1
|
||||
} else if (testLetter == "A") {
|
||||
testButtonA()
|
||||
test = test + 1
|
||||
} else if (testLetter == "B") {
|
||||
testButtonB()
|
||||
test = test + 1
|
||||
} else if (testLetter == "P") {
|
||||
testPads()
|
||||
} else if (testLetter == "X") {
|
||||
testTiltX()
|
||||
} else if (testLetter == "Y") {
|
||||
testTiltY()
|
||||
} else if (testLetter == "Z") {
|
||||
testTiltZ()
|
||||
} else if (testLetter == "S") {
|
||||
testShake()
|
||||
} else if (testLetter == "C") {
|
||||
testCompass()
|
||||
} else if (testLetter == "T") {
|
||||
testTemperature()
|
||||
} else {
|
||||
// end of tests
|
||||
basic.showLeds(`
|
||||
. . . . .
|
||||
. . . . #
|
||||
. . . # .
|
||||
# . # . .
|
||||
. # . . .
|
||||
`, 400)
|
||||
}
|
||||
prevTest = -1
|
||||
AWasPressed = false
|
||||
BWasPressed = false
|
||||
} else if (BWasPressed) {
|
||||
BWasPressed = false
|
||||
if (test < tests.length - 1) {
|
||||
test = test + 1
|
||||
} else {
|
||||
test = 3
|
||||
}
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flash all LEDs 5 times
|
||||
*/
|
||||
function testDisplay() {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
basic.plotLeds(`
|
||||
# # # # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
`)
|
||||
basic.pause(200)
|
||||
basic.clearScreen()
|
||||
basic.pause(200)
|
||||
}
|
||||
// cycle all LEDs from 1 to 25
|
||||
basic.showAnimation(`
|
||||
# . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # #
|
||||
`, 400)
|
||||
}
|
||||
|
||||
function testButtonA() {
|
||||
basic.plotLeds(`
|
||||
. . # . .
|
||||
. # . # .
|
||||
. # # # .
|
||||
. # . # .
|
||||
. # . # .
|
||||
`)
|
||||
// wait for A pressed
|
||||
while (!input.buttonIsPressed(Button.A)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
basic.plotLeds(`
|
||||
. # . . .
|
||||
# . # . .
|
||||
# # # . .
|
||||
# . # . .
|
||||
# . # . .
|
||||
`)
|
||||
// wait for A released
|
||||
while (input.buttonIsPressed(Button.A)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
basic.plotLeds(`
|
||||
. . # . .
|
||||
. # . # .
|
||||
. # # # .
|
||||
. # . # .
|
||||
. # . # .
|
||||
`)
|
||||
basic.pause(1000)
|
||||
}
|
||||
|
||||
function testTiltX() {
|
||||
basic.clearScreen()
|
||||
let prevx = 0
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
basic.pause(100)
|
||||
let x = input.acceleration(Dimension.X)
|
||||
let x2 = x / 512 + 2
|
||||
let x3 = Math.clamp(0, 4, x2)
|
||||
// sticky trace
|
||||
led.plot(x3, 0)
|
||||
// middle line is actual/live
|
||||
if (x3 != prevx) {
|
||||
led.unplot(prevx, 2)
|
||||
prevx = x3
|
||||
}
|
||||
led.plot(x3, 2)
|
||||
// bottom line is -4G, -2G, 1G, +2G, +4G
|
||||
if (x <= -2048) {
|
||||
led.plot(0, 4)
|
||||
} else if (x <= -1024) {
|
||||
led.plot(1, 4)
|
||||
} else if (x <= 1024) {
|
||||
led.plot(2, 4)
|
||||
} else if (x <= 2048) {
|
||||
led.plot(3, 4)
|
||||
} else {
|
||||
led.plot(4, 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testShake() {
|
||||
wasShake = false
|
||||
basic.plotLeds(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . # . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
if (wasShake) {
|
||||
wasShake = false
|
||||
basic.plotLeds(`
|
||||
# # # # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
# # # # #
|
||||
`)
|
||||
basic.pause(500)
|
||||
basic.plotLeds(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . # . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
} else {
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testCompass() {
|
||||
if (input.compassHeading() < 0) {
|
||||
input.calibrate()
|
||||
}
|
||||
basic.clearScreen()
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
let d = input.compassHeading()
|
||||
d = d / 22
|
||||
d = Math.clamp(0, 15, d)
|
||||
d = (d + 2) % 16
|
||||
if (d < 4) {
|
||||
led.plot(d, 0)
|
||||
} else if (d < 8) {
|
||||
led.plot(4, d - 4)
|
||||
} else if (d < 12) {
|
||||
led.plot(4 - d - 8, 4)
|
||||
} else {
|
||||
led.plot(0, 4 - d - 12)
|
||||
}
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function testPads() {
|
||||
let TESTSPEED = 500
|
||||
AWasPressed = false
|
||||
BWasPressed = false
|
||||
// Make sure all pins are inputs, before test starts
|
||||
let p0 = pins.digitalReadPin(DigitalPin.P0)
|
||||
let p1 = pins.digitalReadPin(DigitalPin.P1)
|
||||
let p2 = pins.digitalReadPin(DigitalPin.P2)
|
||||
let ok0 = 0
|
||||
let ok1 = 0
|
||||
let ok2 = 0
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
basic.clearScreen()
|
||||
// ## P0 out low, read from P1 and P2
|
||||
ok0 = 0
|
||||
pins.digitalWritePin(DigitalPin.P0, 0)
|
||||
basic.pause(TESTSPEED)
|
||||
p1 = pins.digitalReadPin(DigitalPin.P1)
|
||||
p2 = pins.digitalReadPin(DigitalPin.P2)
|
||||
if (p1 == 0) {
|
||||
led.plot(0, 0)
|
||||
ok0 = ok0 + 1
|
||||
}
|
||||
if (p2 == 0) {
|
||||
led.plot(1, 0)
|
||||
ok0 = ok0 + 1
|
||||
}
|
||||
// ## P0 out high, read from P1 and P2
|
||||
pins.digitalWritePin(DigitalPin.P0, 1)
|
||||
basic.pause(TESTSPEED)
|
||||
p1 = pins.digitalReadPin(DigitalPin.P1)
|
||||
p2 = pins.digitalReadPin(DigitalPin.P2)
|
||||
if (p1 == 1) {
|
||||
led.plot(2, 0)
|
||||
ok0 = ok0 + 1
|
||||
}
|
||||
if (p2 == 1) {
|
||||
led.plot(3, 0)
|
||||
ok0 = ok0 + 1
|
||||
}
|
||||
// set back to an input
|
||||
p0 = pins.digitalReadPin(DigitalPin.P0)
|
||||
// ## P1 out low, read from P0 and P2
|
||||
ok1 = 0
|
||||
pins.digitalWritePin(DigitalPin.P1, 0)
|
||||
basic.pause(TESTSPEED)
|
||||
p0 = pins.digitalReadPin(DigitalPin.P0)
|
||||
p2 = pins.digitalReadPin(DigitalPin.P2)
|
||||
if (p0 == 0) {
|
||||
led.plot(0, 1)
|
||||
ok1 = ok1 + 1
|
||||
}
|
||||
if (p2 == 0) {
|
||||
led.plot(1, 1)
|
||||
ok1 = ok1 + 1
|
||||
}
|
||||
// ## P1 out high, read from P0 and P2
|
||||
pins.digitalWritePin(DigitalPin.P1, 1)
|
||||
basic.pause(TESTSPEED)
|
||||
p0 = pins.digitalReadPin(DigitalPin.P0)
|
||||
p2 = pins.digitalReadPin(DigitalPin.P2)
|
||||
if (p0 == 1) {
|
||||
led.plot(2, 1)
|
||||
ok1 = ok1 + 1
|
||||
}
|
||||
if (p2 == 1) {
|
||||
led.plot(3, 1)
|
||||
ok1 = ok1 + 1
|
||||
}
|
||||
// set back to an input
|
||||
p0 = pins.digitalReadPin(DigitalPin.P1)
|
||||
// ## P2 out low, read from P0 and P1
|
||||
ok2 = 0
|
||||
pins.digitalWritePin(DigitalPin.P2, 0)
|
||||
basic.pause(TESTSPEED)
|
||||
p0 = pins.digitalReadPin(DigitalPin.P0)
|
||||
p1 = pins.digitalReadPin(DigitalPin.P1)
|
||||
if (p0 == 0) {
|
||||
led.plot(0, 2)
|
||||
ok2 = ok2 + 1
|
||||
}
|
||||
if (p1 == 0) {
|
||||
led.plot(1, 2)
|
||||
ok2 = ok2 + 1
|
||||
}
|
||||
// ## P2 out high, read from P0 and P1
|
||||
pins.digitalWritePin(DigitalPin.P2, 1)
|
||||
basic.pause(TESTSPEED)
|
||||
p0 = pins.digitalReadPin(DigitalPin.P0)
|
||||
p1 = pins.digitalReadPin(DigitalPin.P1)
|
||||
if (p0 == 1) {
|
||||
led.plot(2, 2)
|
||||
ok2 = ok2 + 1
|
||||
}
|
||||
if (p1 == 1) {
|
||||
led.plot(3, 2)
|
||||
ok2 = ok2 + 1
|
||||
}
|
||||
p2 = pins.digitalReadPin(DigitalPin.P2)
|
||||
// ## Assess final test status
|
||||
if (ok0 == 4) {
|
||||
led.plot(4, 0)
|
||||
}
|
||||
basic.pause(TESTSPEED)
|
||||
if (ok1 == 4) {
|
||||
led.plot(4, 1)
|
||||
}
|
||||
basic.pause(TESTSPEED)
|
||||
if (ok2 == 4) {
|
||||
led.plot(4, 2)
|
||||
}
|
||||
basic.pause(TESTSPEED)
|
||||
if (ok0 + ok1 + ok2 == 12) {
|
||||
// all tests passed
|
||||
led.plot(4, 4)
|
||||
}
|
||||
// ## Test cycle finished
|
||||
basic.pause(1000)
|
||||
}
|
||||
// intentionally don't clear A and B flags, so main loop can process them.
|
||||
}
|
||||
|
||||
/**
|
||||
* - show number of dots on screen (0..25) to represent temperature in celcius
|
||||
*/
|
||||
function testTemperature() {
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
let temp = input.temperature() - 10
|
||||
temp = Math.clamp(0, 25, temp)
|
||||
dots025.plotFrame(temp)
|
||||
basic.pause(500)
|
||||
}
|
||||
}
|
||||
|
||||
function testButtonB() {
|
||||
basic.plotLeds(`
|
||||
. # # . .
|
||||
. # . # .
|
||||
. # # . .
|
||||
. # . # .
|
||||
. # # . .
|
||||
`)
|
||||
// wait for B pressed
|
||||
while (!input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
basic.plotLeds(`
|
||||
. . # # .
|
||||
. . # . #
|
||||
. . # # .
|
||||
. . # . #
|
||||
. . # # .
|
||||
`)
|
||||
// wait for B released
|
||||
while (input.buttonIsPressed(Button.B)) {
|
||||
basic.pause(100)
|
||||
}
|
||||
basic.plotLeds(`
|
||||
. # # . .
|
||||
. # . # .
|
||||
. # # . .
|
||||
. # . # .
|
||||
. # # . .
|
||||
`)
|
||||
basic.pause(1000)
|
||||
}
|
||||
|
||||
function testTiltY() {
|
||||
basic.clearScreen()
|
||||
let prevy = 0
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
basic.pause(100)
|
||||
let y = input.acceleration(Dimension.Y)
|
||||
let y2 = y / 512 + 2
|
||||
let y3 = Math.clamp(0, 4, y2)
|
||||
// sticky trace
|
||||
led.plot(0, y3)
|
||||
// middle line is actual/live
|
||||
if (y3 != prevy) {
|
||||
led.unplot(2, prevy)
|
||||
prevy = y3
|
||||
}
|
||||
led.plot(2, y3)
|
||||
// bottom line is -4G, -2G, 1G, +2G, +4G
|
||||
if (y <= -2048) {
|
||||
led.plot(4, 0)
|
||||
} else if (y <= -1024) {
|
||||
led.plot(4, 1)
|
||||
} else if (y <= 1024) {
|
||||
led.plot(4, 2)
|
||||
} else if (y <= 2048) {
|
||||
led.plot(4, 3)
|
||||
} else {
|
||||
led.plot(4, 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testTiltZ() {
|
||||
basic.clearScreen()
|
||||
while (!AWasPressed && !BWasPressed) {
|
||||
let z = input.acceleration(Dimension.Z)
|
||||
if (z < -2000) {
|
||||
basic.plotLeds(`
|
||||
# . . . #
|
||||
# . . . #
|
||||
# . . . #
|
||||
# . . . #
|
||||
# . . . #
|
||||
`)
|
||||
} else if (z <= -1030) {
|
||||
basic.plotLeds(`
|
||||
. # . # .
|
||||
. # . # .
|
||||
. # . # .
|
||||
. # . # .
|
||||
. # . # .
|
||||
`)
|
||||
} else if (z <= 1000) {
|
||||
basic.plotLeds(`
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
. . # . .
|
||||
`)
|
||||
} else if (z <= 1030) {
|
||||
basic.plotLeds(`
|
||||
. . . . .
|
||||
. . . . .
|
||||
# # # # #
|
||||
. . . . .
|
||||
. . . . .
|
||||
`)
|
||||
} else if (z <= 2000) {
|
||||
basic.plotLeds(`
|
||||
. . . . .
|
||||
# # # # #
|
||||
. . . . .
|
||||
# # # # #
|
||||
. . . . .
|
||||
`)
|
||||
} else {
|
||||
basic.plotLeds(`
|
||||
# # # # #
|
||||
. . . . .
|
||||
. . . . .
|
||||
. . . . .
|
||||
# # # # #
|
||||
`)
|
||||
}
|
||||
basic.pause(100)
|
||||
}
|
||||
}
|
||||
|
||||
function startIOMonitor() {
|
||||
input.onButtonPressed(Button.A, () => {
|
||||
AWasPressed = true
|
||||
})
|
||||
input.onButtonPressed(Button.B, () => {
|
||||
BWasPressed = true
|
||||
})
|
||||
input.onShake(() => {
|
||||
wasShake = true
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user