Welcome, Guest |
You have to register before you can post on our site.
|
Latest Threads |
astuce pour survivre fina...
Forum: Utilities
Last Post: coletteleger
05-14-2025, 04:47 AM
» Replies: 0
» Views: 47
|
trouver permis de conduir...
Forum: Utilities
Last Post: nicolasrene
05-05-2025, 05:24 AM
» Replies: 0
» Views: 56
|
LIGHTBAR Menu
Forum: Programs
Last Post: nicolasrene
05-05-2025, 05:08 AM
» Replies: 15
» Views: 1,067
|
Learning Pallet Rack Safe...
Forum: Utilities
Last Post: Sandrapew
04-03-2025, 09:36 AM
» Replies: 0
» Views: 62
|
Choosing New Versus or Pr...
Forum: Utilities
Last Post: Sandrapew
03-18-2025, 01:11 AM
» Replies: 0
» Views: 61
|
The QB64 IDE shell
Forum: Utilities
Last Post: JasonPag
09-16-2024, 05:37 PM
» Replies: 9
» Views: 1,144
|
Importance regarding Ches...
Forum: Utilities
Last Post: JasonPag
09-01-2024, 06:34 PM
» Replies: 0
» Views: 90
|
Chess and Analysis and En...
Forum: Utilities
Last Post: JasonPag
08-28-2024, 02:37 PM
» Replies: 0
» Views: 92
|
DAY 009:_PutImage
Forum: Keyword of the Day!
Last Post: grymmjack
09-02-2023, 02:57 PM
» Replies: 54
» Views: 3,784
|
Fall Banner Contest?
Forum: Site Suggestions
Last Post: grymmjack
08-31-2023, 11:50 PM
» Replies: 36
» Views: 2,406
|
|
|
QB64 Phoenix Edition v3.8.0 Released! |
Posted by: RhoSigma - 06-14-2023, 08:19 AM - Forum: Announcements
- Replies (57)
|
 |
QB64 Phoenix Edition v3.8.0!
https://github.com/QB64-Phoenix-Edition/...tag/v3.8.0
Enhancements - #338 - C/C++ compiler update. - @a740g
- Updates the MinGW toolchain to v12.2.0 r2.
- #339 - Improvements on the various dialog functions. - @a740g
- Many mandatory dialog parameters are now optional.
- Parsable option string arguments are case-insensitive now (required lower case before).
- #341 - Adds _UCHARPOS() to the _U* functions family. - @a740g
- Ideally, this should have been added in v3.7.0 but was not due to an oversight. This function calculates the pixel distance of every character in a string from the origin and is especially helpful for variable width fonts.
- #347 - Audio enhancements. - @a740g
- Updates miniaudio to v0.11.17, which adds support for Apple AIFF and AIFC audio formats. So, we get those too.
- PLAY has been extended to:
- Select waveforms @n (square = 1, sawtooth = 2, triangle = 3 (default), sine = 4, noise = 5).
- Adjust volume ramping Qn (0ms to 100ms).
- SOUND has been extended to use the following syntax:
- SOUND frequency#, duration#[, volume#][, panning#][, waveform&]
- #346 - Improves the IDE code export abilities. - @RhoSigma-QB64
- Added ability to export into a [ q b = e x p o r t ] Forum codebox.
- The Forum/Wiki exports now go to the clipboard instead of a file and can directly be pasted into the Forum post or Wiki page.
- Progress of export is shown in the status line and you'll get a message upon export completion.
Bug Fixes- #341 - Fixing the cut-off on certain letters in conjunction with _LOADFONT and PRINT. - @a740g
- #347 - Fixing issues with PLAY statement. - @a740g
- PLAY is now feature complete supporting "X" + VARPTR$()
Full Changelog: v3.7.0...v3.8.0
|
|
|
Jump due to timeout in response |
Posted by: JuanjoGomez - 06-14-2023, 07:36 AM - Forum: General Discussion
- Replies (2)
|
 |
HI,
I have a problem. When I enter my program, the first thing I do is find out what my external IP is. For that I use a function that I saw from another programmer.
The problem is that depending on the computer, connection, times you enter the program......, sometimes it does it instantly and sometimes it takes a long time to get it (1 minute or more).
Can anyone think of how to set a timer so that if it hasn't responded in, say, 3 seconds, then program continues at another line? or by presing a key if is more easy?
Tanks
Code: (Select All)
| Dim miip As String | | Cls: Locate 10, 20: Print "COSULTING PUBLIC IP ...." | | | | miip = GetPublicIP | | Locate 10, 20: Print "PUBLIC IP: "; miip | | | | continue: | | | | | | End | | | | | | Function GetPublicIP$ | | Dim URL As String | | Dim URLFile As String | | Dim publicip As String | | Dim a% | | URLFile = "publicip" | | URL = "https://api.ipify.org/" | | a% = FileDownload(URL, URLFile) | | Dim U As Integer | | U = FreeFile | | Open URLFile For Binary As #U | | If LOF(U) <> 0 Then | | Line Input #U, publicip | | Else | | Close #U | | Kill URLFile | | GetPublicIP = "" | | Exit Function | | End If | | Close #U | | Kill URLFile | | GetPublicIP = publicip | | End Function | | | | Declare Dynamic Library "urlmon" | | Function URLDownloadToFileA (ByVal pCaller As Long, szURL As String, szFileName As String, Byval dwReserved As Long, Byval lpfnCB As Long) | | End Declare | | | | Function FileDownload (URL As String, File As String) | | FileDownload = URLDownloadToFileA(0, URL, File, 0, 0) | | End Function |
|
|
|
No warning to mix screen 0 and screen graphic commands! |
Posted by: TempodiBasic - 06-14-2023, 01:24 AM - Forum: Help Me!
- Replies (8)
|
 |
Help!
For all coders like me that are too old to abandon the old Qbasic Keywords vs new QB63pe keywords, it should be a warning AI in the parser!
run this code and you can experimenting what I'm saying.
Code: (Select All) Dim Shared S1 As Long, S2 As Long
S1 = _NewImage(1200, 900, 32)
S2 = _NewImage(1200, 300, 32)
_SetAlpha 100, 0, S2
Screen S1
Paint (1, 1), _RGBA32(0, 100, 100, 256)
_Delay 1
_Dest S2
Print "If you see color back to this text all is ok"
_PutImage (1, 600), S2, S1
well, if you watch at the output... you see that all that is a screen 0 output (PRINT in this case) has been _putimaged on the application screen without no alpha effect!
At a first time it has been clear to my old mind! Why the part of S2 that brings PRINT output is not under the effect of _setalpha?
Yes PRINT is a keyword of SCREEN 0, but I believe that _setalpha should work on the whole S2 and not only to the part that brings a graphic effect.
In other words I should get this result if I make output directly to the main screen, while if I copy a screen that has a not full grade of trasparency (alpha < 256) I should get that the whole image shows the trasparency effect.
In this case it seems that copying the output of a SCREEN 0 let it at screen 0 level!
Like I cannot use screen function with graphic text (using Fonts).
|
|
|
PLAY music grid wiki example code review |
Posted by: grymmjack - 06-12-2023, 11:11 PM - Forum: Programs
- Replies (2)
|
 |
In this video I walk through the simple PLAY music grid wiki example by JP, to learn and understand the way it works.
Check out the QB64PE Wiki Example here:
https://qb64phoenix.com/qb64wiki/index.php/PLAY
The commented source is here:
https://gist.github.com/grymmjack/d7fdcd...5a7da9b765
Experimentation and dissection as usual!
I'm still uploading the video - it should be up in an hour.
Thanks for watching!
https://youtu.be/8vCHnr1MAU4
This is an awesome example!
Code: (Select All)
| DIM SHARED grid(16, 16), grid2(16, 16), cur | | CONST maxx = 512 | | CONST maxy = 512 | | SCREEN _NEWIMAGE(maxx, maxy, 32) | | _TITLE "MusicGrid" | | cleargrid | | DO | | IF TIMER - t# > 1 / 8 THEN cur = (cur + 1) AND 15: t# = TIMER | | IF cur <> oldcur THEN | | figuregrid | | drawgrid | | playgrid | | oldcur = cur | | END IF | | domousestuff | | in$ = INKEY$ | | IF in$ = "C" OR in$ = "c" THEN cleargrid | | LOOP UNTIL in$ = CHR$(27) | | | | SUB drawgrid | | scale! = maxx / 16 | | scale2 = maxx \ 16 - 2 | | FOR y = 0 TO 15 | | y1 = y * scale! | | FOR x = 0 TO 15 | | x1 = x * scale! | | c& = _RGB32(grid2(x, y) * 64 + 64, 0, 0) | | LINE (x1, y1)-(x1 + scale2, y1 + scale2), c&, BF | | NEXT x | | NEXT y | | END SUB | | | | SUB figuregrid | | FOR y = 0 TO 15 | | FOR x = 0 TO 15 | | grid2(x, y) = grid(x, y) | | NEXT x | | NEXT y | | FOR y = 1 TO 14 | | FOR x = 1 TO 14 | | IF grid(x, y) = 1 AND cur = x THEN | | grid2(x, y) = 2 | | IF grid(x - 1, y) = 0 THEN grid2(x - 1, y) = 1 | | IF grid(x + 1, y) = 0 THEN grid2(x + 1, y) = 1 | | IF grid(x, y - 1) = 0 THEN grid2(x, y - 1) = 1 | | IF grid(x, y + 1) = 0 THEN grid2(x, y + 1) = 1 | | END IF | | NEXT x | | NEXT y | | END SUB | | | | SUB domousestuff | | DO WHILE _MOUSEINPUT | | IF _MOUSEBUTTON(1) THEN | | x = _MOUSEX \ (maxx \ 16) | | y = _MOUSEY \ (maxy \ 16) | | grid(x, y) = 1 - grid(x, y) | | END IF | | LOOP | | END SUB | | | | SUB playgrid | | n$ = "L16 " | | | | scale$ = "o1fo1go1ao2co2do2fo2go2ao3co3do3fo3go3ao4co4do4fo" | | FOR y = 15 TO 0 STEP -1 | | IF grid(cur, y) = 1 THEN | | note$ = MID$(scale$, 1 + (15 - y) * 3, 3) | | n$ = n$ + note$ + "," | | END IF | | NEXT y | | n$ = LEFT$(n$, LEN(n$) - 1) | | PLAY n$ | | END SUB | | | | SUB cleargrid | | FOR y = 0 TO 15 | | FOR x = 0 TO 15 | | grid(x, y) = 0 | | NEXT x | | NEXT y | | END SUB |
|
|
|
Catch some rays |
Posted by: bplus - 06-12-2023, 08:02 PM - Forum: Programs
- Replies (3)
|
 |
Couldn't find the exotic landscape background mod but found this for a sun:
Code: (Select All)
| | | Screen _NewImage(800, 600, 32) | | Do | | For r = 0 To 500 Step .25 | | Circle (400, 300), r, Ink~&(&HFFFFFF44, &HFF220088, r / 500) | | Next | | For i = 1 To 100 | | a = Rnd * _Pi(2) | | r1 = 20 + Rnd * 100 | | r2 = r1 + 20 + Rnd * 260 | | midx = _Width / 2 + (r1 + (r2 - r1) / 2) * Cos(a): midy = _Height / 2 + (r1 + (r2 - r1) / 2) * Sin(a) | | ray& = _NewImage(r2 - r1, 1, 32) | | _PutImage , 0, ray&, (400, 300)-Step(r2 - r1, 1) | | RotoZoom midx, midy, ray&, 1, _R2D(a) | | _FreeImage ray& | | Next | | _Display | | _Limit 10 | | Loop Until _KeyDown(27) | | | | Sub cAnalysis (c As _Unsigned Long, outRed, outGrn, outBlu, outAlp) | | outRed = _Red32(c): outGrn = _Green32(c): outBlu = _Blue32(c): outAlp = _Alpha32(c) | | End Sub | | | | Function Ink~& (c1 As _Unsigned Long, c2 As _Unsigned Long, fr##) | | Dim R1, G1, B1, A1, R2, G2, B2, A2 | | cAnalysis c1, R1, G1, B1, A1 | | cAnalysis c2, R2, G2, B2, A2 | | Ink~& = _RGB32(R1 + (R2 - R1) * fr##, G1 + (G2 - G1) * fr##, B1 + (B2 - B1) * fr##, A1 + (A2 - A1) * fr##) | | End Function | | | | Sub RotoZoom (X As Long, Y As Long, Image As Long, Scale As Single, degreesRotation As Single) | | Dim px(3) As Single, py(3) As Single, W&, H&, sinr!, cosr!, i&, x2&, y2& | | W& = _Width(Image&): H& = _Height(Image&) | | px(0) = -W& / 2: py(0) = -H& / 2: px(1) = -W& / 2: py(1) = H& / 2 | | px(2) = W& / 2: py(2) = H& / 2: px(3) = W& / 2: py(3) = -H& / 2 | | sinr! = Sin(-degreesRotation / 57.2957795131): cosr! = Cos(-degreesRotation / 57.2957795131) | | For i& = 0 To 3 | | x2& = (px(i&) * cosr! + sinr! * py(i&)) * Scale + X: y2& = (py(i&) * cosr! - px(i&) * sinr!) * Scale + Y | | px(i&) = x2&: py(i&) = y2& | | Next | | _MapTriangle (0, 0)-(0, H& - 1)-(W& - 1, H& - 1), Image& To(px(0), py(0))-(px(1), py(1))-(px(2), py(2)) | | _MapTriangle (0, 0)-(W& - 1, 0)-(W& - 1, H& - 1), Image& To(px(0), py(0))-(px(3), py(3))-(px(2), py(2)) | | End Sub |
|
|
|
2D Physics Engine Help |
Posted by: TerryRitchie - 06-12-2023, 03:16 PM - Forum: Help Me!
- Replies (11)
|
 |
Over the past few months I've made a few attempts at creating a 2D physics library for QB64 but have failed miserably. My first few attempts were writing something from scratch. I quickly realized that while I have a fair grasp on basic trig and vector math I have nowhere near the knowledge to implement such things as angular momentum, raytracing, and 2D collision physics. Even after trying to tutor myself on the subject I seem to still be just as confused (if not more).
I then decided to follow a few video tutorials I found on Youtube related to creating a 2D physics engine. Of course these are all either meant for C++, Java, or JavaScript using OOP. I figured the process of converting the Java OOP code to functions and procedures would be fairly straight forward ... not so much. (Below I provide a link to the video series I am following along with the code I created so far).
My next thought was to incorporate the Box2D physics engine (the engine that Rovio used to create Angry Birds) into QB64. The Library is written in C++ and I figured by using DECLARE LIBRARY I could get this done. However, my C++ knowledge is lacking as well. Trying to figure out where pointers are used versus variables, their types, and when I need _OFFSETs is just confusing this old thick headed brain of mine. Here is a link to the Box2D physics engine:
https://box2d.org/about/
I feel QB64 needs a 2D physics engine to help attract more users. I know my games would be vastly improved if I had access to something that could create Angry Birds style game physics.
Is anyone with more knowledge on either subject, importing Box2D into QB64, or tutoring and helping me build an engine, willing to help? Box2D also has a light version, Box2D_Lite, that may be a good start if porting the engine is an option.
Below is a link to the video series I was following. I got to the end of Lesson 9 and am totally confused on what the presenter did when introducing the FOR loop.
The video series:
https://www.youtube.com/watch?v=vcgtwY39...iO&index=2
And the code I hacked together so far trying to follow along and convert OOP to QB64 on the fly.
Code: (Select All)
| | | | | | | OPTION _EXPLICIT | | | | CONST MIN_VALUE = -2.802597E-45 | | | | | | TYPE Type_Vector2 | | x AS SINGLE | | y AS SINGLE | | END TYPE | | | | TYPE Type_Ray2D | | origin AS Type_Vector2 | | direction AS Type_Vector2 | | END TYPE | | | | TYPE Type_RaycastResult | | ppoint AS Type_Vector2 | | normal AS Type_Vector2 | | t AS SINGLE | | hit AS INTEGER | | | | END TYPE | | | | TYPE Type_Line2D | | from AS Type_Vector2 | | too AS Type_Vector2 | | colour AS _UNSIGNED LONG | | lifetime AS INTEGER | | END TYPE | | | | TYPE Type_Rigidbody2D | | position AS Type_Vector2 | | rotation AS SINGLE | | END TYPE | | | | TYPE Type_Box2D | | size AS Type_Vector2 | | halfSize AS Type_Vector2 | | rigidbody AS Type_Rigidbody2D | | END TYPE | | | | TYPE Type_AABB | | size AS Type_Vector2 | | halfSize AS Type_Vector2 | | rigidbody AS Type_Rigidbody2D | | END TYPE | | | | TYPE Type_Circle | | Radius AS SINGLE | | rigidbody AS Type_Rigidbody2D | | END TYPE | | | | | | DIM __AABB AS Type_AABB | | DIM __Circle AS Type_Circle | | DIM __rigidbody2D AS Type_Rigidbody2D | | DIM Vertices(4) AS Type_Vector2 | | | | | | | | | | | | SUB Line2D.setFromToo (__line2D AS Type_Line2D, from AS Type_Vector2, too AS Type_Vector2) | | | | __line2D.from = from | | __line2D.too = too | | | | END SUB | | | | | | SUB Line2D (__line2D AS Type_Line2D, from AS Type_Vector2, too AS Type_Vector2, colour AS _UNSIGNED LONG, lifetime AS INTEGER) | | | | __line2D.from = from | | __line2D.too = too | | __line2D.colour = colour | | __line2D.lifetime = lifetime | | | | END SUB | | | | | | FUNCTION Line2D.beginFrame (__line2d AS Type_Line2D) | | | | __line2d.lifetime = __line2d.lifetime - 1 | | Line2D.beginFrame = __line2d.lifetime | | | | END FUNCTION | | | | | | SUB Line2D.getFrom (__line2d AS Type_Line2D, from AS Type_Vector2) | | | | from = __line2d.from | | | | END SUB | | | | SUB Line2D.getToo (__line2d AS Type_Line2D, too AS Type_Vector2) | | | | too = __line2d.too | | | | END SUB | | | | | | SUB Line2D.getStart (__line2d AS Type_Line2D, start AS Type_Vector2) | | | | start = __line2d.from | | | | END SUB | | | | SUB Line2D.getEnd (__line2d AS Type_Line2D, endd AS Type_Vector2) | | | | endd = __line2d.too | | | | END SUB | | | | | | FUNCTION Line2D.getColour (__line2d AS Type_Line2D) | | | | Line2D.getColour = __line2d.colour | | | | END FUNCTION | | | | | | FUNCTION Line2D.lengthSquared (__line2d AS Type_Line2D) | | | | DIM from AS Type_Vector2 | | DIM too AS Type_Vector2 | | DIM length AS Type_Vector2 | | | | Line2D.getFrom __line2d, from | | Line2D.getToo __line2d, too | | | | length.x = too.x - from.x | | length.y = too.y - from.y | | | | Line2D.lengthSquared = lengthSquared(length) | | | | END FUNCTION | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | FUNCTION PointOnLine (TestPoint AS Type_Vector2, __line2D AS Type_Line2D) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DIM lineStart AS Type_Vector2 | | DIM lineEnd AS Type_Vector2 | | DIM dx AS SINGLE | | DIM dy AS SINGLE | | DIM m AS SINGLE | | DIM b AS SINGLE | | | | PointOnLine = 0 | | | | | | lineStart = __line2D.from | | lineEnd = __line2D.too | | | | | | | | | | dy = lineEnd.y - lineStart.y | | dx = lineEnd.x - lineStart.x | | IF dx = 0 THEN | | IF TestPoint.x = lineStart.x THEN | | PointOnLine = -1 | | EXIT FUNCTION | | END IF | | END IF | | m = dy / dx | | b = lineStart.y - (m * lineStart.x) | | IF TestPoint.y = m * TestPoint.x + b THEN PointOnLine = -1 | | | | END FUNCTION | | | | | | FUNCTION PointInCircle (TestPoint AS Type_Vector2, __circle AS Type_Circle) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DIM circleCenter AS Type_Vector2 | | DIM centerToPoint AS Type_Vector2 | | DIM radius AS SINGLE | | | | PointInCircle = 0 | | | | | | circleCenter = __circle.rigidbody.position | | | | | | | | | | radius = __circle.Radius | | | | | | | | centerToPoint.x = TestPoint.x - circleCenter.x | | centerToPoint.y = TestPoint.y - circleCenter.y | | IF lengthSquared(centerToPoint) <= radius * radius THEN PointInCircle = -1 | | | | END FUNCTION | | | | | | FUNCTION PointInAABB (TestPoint AS Type_Vector2, box AS Type_AABB) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DIM min AS Type_Vector2 | | DIM max AS Type_Vector2 | | | | AABB.getMin box, min | | AABB.getMax box, max | | PointInAABB = 0 | | IF TestPoint.x <= max.x THEN | | IF min.x <= TestPoint.x THEN | | IF TestPoint.y <= max.y THEN | | IF min.y <= TestPoint.y THEN | | PointInAABB = -1 | | END IF | | END IF | | END IF | | END IF | | | | END FUNCTION | | | | | | FUNCTION PointInBox2D (TestPoint AS Type_Vector2, box AS Type_Box2D) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DIM pointLocalBoxSpace AS Type_Vector2 | | DIM min AS Type_Vector2 | | DIM max AS Type_Vector2 | | | | PointInBox2D = 0 | | Box2D.getMin box, min | | Box2D.getMax box, max | | pointLocalBoxSpace = TestPoint | | | | | | | | | | | | Rotate pointLocalBoxSpace, box.rigidbody.rotation, box.rigidbody.position | | | | | | | | | | | | IF pointLocalBoxSpace.x <= max.x THEN | | IF min.x <= pointLocalBoxSpace.x THEN | | IF pointLocalBoxSpace.y <= max.y THEN | | IF min.y <= pointLocalBoxSpace.y THEN | | PointInBox2D = -1 | | END IF | | END IF | | END IF | | END IF | | | | END FUNCTION | | | | | | FUNCTION lineAndCircle (__line2D AS Type_Line2D, __circle AS Type_Circle) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DIM LineStart AS Type_Vector2 | | DIM LineEnd AS Type_Vector2 | | DIM ab AS Type_Vector2 | | DIM circleCenter AS Type_Vector2 | | DIM centerToLineStart AS Type_Vector2 | | DIM t AS SINGLE | | DIM closestPoint AS Type_Vector2 | | | | lineAndCircle = 0 | | | | | | LineStart = __line2D.from | | LineEnd = __line2D.too | | | | | | | | | | IF PointInCircle(LineStart, __circle) OR PointInCircle(LineEnd, __circle) THEN | | lineAndCircle = -1 | | EXIT FUNCTION | | END IF | | ab.x = LineEnd.x - LineStart.x | | ab.y = LineEnd.y - LineStart.y | | | | | | | | | | | | | | | | circleCenter = __circle.rigidbody.position | | | | | | | | centerToLineStart.x = circleCenter.x - LineStart.x | | centerToLineStart.y = circleCenter.y - LineStart.y | | t = Dot(centerToLineStart, ab) / Dot(ab, ab) | | IF t < 0 OR t > 1 THEN EXIT FUNCTION | | | | | | | | | | | | closestPoint.x = LineStart.x + ab.x * t | | closestPoint.y = LineStart.y + ab.y * t | | lineAndCircle = PointInCircle(closestPoint, __circle) | | | | END FUNCTION | | | | | | FUNCTION lineAndAABB (__line2D AS Type_Line2D, box AS Type_AABB) | | | | | | | | DIM lineStart AS Type_Vector2 | | DIM lineEnd AS Type_Vector2 | | DIM unitVector AS Type_Vector2 | | DIM min AS Type_Vector2 | | DIM max AS Type_Vector2 | | DIM tmin AS SINGLE | | DIM tmax AS SINGLE | | DIM t AS SINGLE | | | | lineAndAABB = 0 | | Line2D.getStart __line2D, lineStart | | Line2D.getEnd __line2D, lineEnd | | | | IF PointInAABB(lineStart, box) OR PointInAABB(lineEnd, box) THEN | | lineAndAABB = -1 | | EXIT FUNCTION | | END IF | | | | unitVector.x = lineEnd.x - lineStart.x | | unitVector.y = lineEnd.y - lineEnd.y | | | | Normalize unitVector | | | | IF unitVector.x <> 0 THEN unitVector.x = 1 / unitVector.x | | IF unitVector.y <> 0 THEN unitVector.y = 1 / unitVector.y | | | | AABB.getMin box, min | | min.x = min.x - lineStart.x * unitVector.x | | min.y = min.y - lineStart.y * unitVector.y | | AABB.getMax box, max | | max.x = max.x - lineStart.x * unitVector.x | | max.y = max.y - lineStart.y * unitVector.y | | | | tmin = MathMax(MathMin(min.x, max.x), MathMin(min.y, max.y)) | | tmax = MathMin(MathMax(min.x, max.x), MathMax(min.y, max.y)) | | | | IF tmax < 0 OR tmin > tmax THEN EXIT FUNCTION | | | | IF tmin < 0 THEN t = tmax ELSE t = tmin | | | | IF t > 0 AND t * t < Line2D.lengthSquared(__line2D) THEN lineAndAABB = -1 | | | | | | END FUNCTION | | | | | | FUNCTION lineAndBox2D (__line2d AS Type_Line2D, box AS Type_Box2D) | | | | | | | | DIM theta AS SINGLE | | DIM center AS Type_Vector2 | | DIM localStart AS Type_Vector2 | | DIM localEnd AS Type_Vector2 | | DIM localLine AS Type_Line2D | | DIM min AS Type_Vector2 | | DIM max AS Type_Vector2 | | DIM __aabb AS Type_AABB | | | | theta = -box.rigidbody.rotation | | center = box.rigidbody.position | | | | Line2D.getStart __line2d, localStart | | Line2D.getEnd __line2d, localEnd | | Rotate localStart, theta, center | | Rotate localEnd, theta, center | | | | | | | | localLine.from = localStart | | localLine.too = localEnd | | | | Box2D.getMin box, min | | Box2D.getMax box, max | | | | AABB __aabb, min, max | | | | lineAndBox2D = lineAndAABB(localLine, __aabb) | | | | END FUNCTION | | | | | | | | | | | | | | FUNCTION RaycastCircle (__circle AS Type_Circle, ray AS Type_Ray2D, result AS Type_RaycastResult) | | | | DIM originToCircle AS Type_Vector2 | | DIM center AS Type_Vector2 | | DIM origin AS Type_Vector2 | | DIM radius AS SINGLE | | DIM radiusSquared AS SINGLE | | DIM originToCircleLengthSquared AS SINGLE | | DIM direction AS Type_Vector2 | | DIM a AS SINGLE | | DIM bSq AS SINGLE | | DIM f AS SINGLE | | DIM t AS SINGLE | | DIM ppoint AS Type_Vector2 | | DIM normal AS Type_Vector2 | | | | RaycastCircle = 0 | | | | RaycastResult.reset result | | | | Circle.getCenter __circle, center | | Ray2D.getOrigin ray, origin | | | | originToCircle.x = center.x - origin.x | | originToCircle.y = center.y - origin.y | | | | radius = Circle.getRadius(__circle) | | | | radiusSquared = radius * radius | | | | originToCircleLengthSquared = lengthSquared(originToCircle) | | | | | | | | Ray2D.getDirection ray, direction | | | | a = Dot(originToCircle, direction) | | | | bSq = originToCircleLengthSquared - (a * a) | | | | IF radiusSquared - bSq < 0 THEN EXIT FUNCTION | | | | f = SQR(radiusSquared - bSq) | | | | t = 0 | | IF originToCircleLengthSquared < radiusSquared THEN | | t = a + f | | ELSE | | t = a - f | | END IF | | | | IF result.ppoint.x + result.ppoint.y = 0 THEN | | | | ppoint.x = origin.x + direction.x * t | | ppoint.y = origin.y + direction.y * t | | | | normal.x = ppoint.x - center.x | | normal.y = ppoint.y - center.y | | | | Normalize normal | | | | result.ppoint = ppoint | | result.normal = normal | | result.t = t | | result.hit = -1 | | | | END IF | | | | RaycastCircle = -1 | | | | END FUNCTION | | | | | | FUNCTION RaycastAABB (box AS Type_AABB, __Ray2D AS Type_Ray2D, result AS Type_RaycastResult) | | | | | | | | DIM unitVector AS Type_Vector2 | | DIM min AS Type_Vector2 | | DIM max AS Type_Vector2 | | DIM tmin AS SINGLE | | DIM tmax AS SINGLE | | DIM t AS SINGLE | | DIM hit AS INTEGER | | DIM ppoint AS Type_Vector2 | | DIM normal AS Type_Vector2 | | | | RaycastAABB = 0 | | RaycastResult.reset result | | | | unitVector.x = __Ray2D.direction.x | | unitVector.y = __Ray2D.direction.y | | | | Normalize unitVector | | | | IF unitVector.x <> 0 THEN unitVector.x = 1 / unitVector.x | | IF unitVector.y <> 0 THEN unitVector.y = 1 / unitVector.y | | | | AABB.getMin box, min | | min.x = min.x - __Ray2D.origin.x | | min.y = min.y - __Ray2D.origin.y | | AABB.getMax box, max | | max.x = max.x - __Ray2D.origin.x | | max.y = max.y - __Ray2D.origin.y | | | | tmin = MathMax(MathMin(min.x, max.x), MathMin(min.y, max.y)) | | tmax = MathMin(MathMax(min.x, max.x), MathMax(min.y, max.y)) | | | | IF tmax < 0 OR tmin > tmax THEN EXIT FUNCTION | | | | IF tmin < 0 THEN t = tmax ELSE t = tmin | | | | IF t > 0 THEN hit = -1 | | | | IF NOT hit THEN EXIT FUNCTION | | | | IF result.ppoint.x = 0 AND result.ppoint.y = 0 THEN | | ppoint.x = __Ray2D.origin.x + __Ray2D.direction.x * t | | ppoint.y = __Ray2D.origin.y + __Ray2D.direction.y * t | | | | normal.x = __Ray2D.origin.x - ppoint.x | | normal.y = __Ray2D.origin.y - ppoint.y | | | | Normalize normal | | | | result.ppoint = ppoint | | result.normal = normal | | result.t = t | | result.hit = -1 | | | | | | END IF | | | | RaycastAABB = -1 | | | | | | END FUNCTION | | | | | | FUNCTION RaycastBox2D (box AS Type_Box2D, __Ray2D AS Type_Ray2D, result AS Type_RaycastResult) | | | | DIM xAxis AS Type_Vector2 | | DIM yAxis AS Type_Vector2 | | DIM zerozero AS Type_Vector2 | | DIM p AS Type_Vector2 | | DIM f AS Type_Vector2 | | DIM e AS Type_Vector2 | | DIM size AS Type_Vector2 | | | | RaycastBox2D = 0 | | RaycastResult.reset result | | | | Box2D.halfSize box, size | | | | xAxis.x = 1 | | xAxis.y = 0 | | yAxis.x = 0 | | yAxis.y = 1 | | | | Rotate xAxis, -box.rigidbody.rotation, zerozero | | Rotate yAxis, -box.rigidbody.rotation, zerozero | | | | p.x = box.rigidbody.position.x - __Ray2D.origin.x | | p.y = box.rigidbody.position.y - __Ray2D.origin.y | | | | | | | | f.x = Dot(xAxis, __Ray2D.direction) | | f.y = Dot(yAxis, __Ray2D.direction) | | | | | | | | e.x = Dot(xAxis, p) | | e.y = Dot(yAxis, p) | | | | | | | | | | | | RaycastBox2D = -1 | | | | END FUNCTION | | | | | | | | | | | | | | | | | | | | | | | | | | SUB RigidBody2D.getPosition (__rigidbody2D AS Type_Rigidbody2D, position AS Type_Vector2) | | | | position.x = __rigidbody2D.position.x | | position.y = __rigidbody2D.position.y | | | | END SUB | | | | SUB RigidBody2D.setPosition (__rigidbody2D AS Type_Rigidbody2D, position AS Type_Vector2) | | | | __rigidbody2D.position.x = position.x | | __rigidbody2D.position.y = position.y | | | | END SUB | | | | FUNCTION RigidBody2D.getRotation (__rigidbody2D AS Type_Rigidbody2D) | | | | RigidBody2D.getRotation = __rigidbody2D.rotation | | | | END FUNCTION | | | | SUB RigidBody2D.setRotation (__rigidbody2D AS Type_Rigidbody2D, rotation AS SINGLE) | | | | __rigidbody2D.rotation = rotation | | | | END SUB | | | | | | | | | | | | | | | | | | | | | | | | SUB AABB (__AABB AS Type_AABB, min AS Type_Vector2, max AS Type_Vector2) | | | | __AABB.size.x = max.x - min.x | | __AABB.size.y = max.y - min.y | | __AABB.halfSize.x = __AABB.size.x * .5 | | __AABB.halfSize.y = __AABB.size.y * .5 | | | | END SUB | | | | | | SUB AABB.halfSize (__AABB AS Type_AABB, halfSize AS Type_Vector2) | | | | halfSize.x = __AABB.size.x * .5 | | halfSize.y = __AABB.size.y * .5 | | | | END SUB | | | | | | SUB AABB.getMin (__AABB AS Type_AABB, min AS Type_Vector2) | | | | DIM halfSize AS Type_Vector2 | | | | AABB.halfSize __AABB, halfSize | | min.x = __AABB.rigidbody.position.x - halfSize.x | | min.y = __AABB.rigidbody.position.y - halfSize.y | | | | END SUB | | | | | | SUB AABB.getMax (__AABB AS Type_AABB, max AS Type_Vector2) | | | | DIM halfSize AS Type_Vector2 | | | | AABB.halfSize __AABB, halfSize | | max.x = __AABB.rigidbody.position.x + halfSize.x | | max.y = __AABB.rigidbody.position.y + halfSize.y | | | | END SUB | | | | | | | | | | | | SUB Box2D (__box2D AS Type_Box2D, min AS Type_Vector2, max AS Type_Vector2) | | | | __box2D.size.x = max.x - min.x | | __box2D.size.y = max.y - min.y | | __box2D.halfSize.x = __box2D.size.x * .5 | | __box2D.halfSize.y = __box2D.size.y * .5 | | | | END SUB | | | | | | SUB Box2D.halfSize (__box2D AS Type_Box2D, halfSize AS Type_Vector2) | | | | halfSize.x = __box2D.size.x * .5 | | halfSize.y = __box2D.size.y * .5 | | | | END SUB | | | | | | SUB Box2D.getMin (__box2D AS Type_Box2D, min AS Type_Vector2) | | | | DIM halfSize AS Type_Vector2 | | | | Box2D.halfSize __box2D, halfSize | | min.x = __box2D.rigidbody.position.x - halfSize.x | | min.y = __box2D.rigidbody.position.y - halfSize.y | | | | END SUB | | | | | | SUB Box2D.getMax (__box2D AS Type_Box2D, max AS Type_Vector2) | | | | DIM halfSize AS Type_Vector2 | | | | Box2D.halfSize __box2D, halfSize | | max.x = __box2D.rigidbody.position.x + halfSize.x | | max.y = __box2D.rigidbody.position.y + halfSize.y | | | | END SUB | | | | | | SUB Box2D.getVertices (__box2d AS Type_Box2D, Vertices() AS Type_Vector2) | | | | DIM min AS Type_Vector2 | | DIM max AS Type_Vector2 | | DIM vert AS Type_Vector2 | | DIM vCount AS INTEGER | | | | Box2D.getMin __box2d, min | | Box2D.getMax __box2d, max | | | | Vertices(1).x = min.x | | Vertices(1).y = min.y | | Vertices(2).x = min.x | | Vertices(2).y = max.y | | Vertices(3).x = max.x | | Vertices(3).y = min.y | | Vertices(4).x = max.x | | Vertices(4).y = max.y | | | | IF __box2d.rigidbody.rotation <> 0 THEN | | vCount = 0 | | DO | | vert = Vertices(vCount) | | Rotate vert, __box2d.rigidbody.rotation, __box2d.rigidbody.position | | LOOP UNTIL vCount = 4 | | END IF | | | | END SUB | | | | | | | | | | | | | | FUNCTION Circle.getRadius (__circle AS Type_Circle) | | | | Circle.getRadius = __circle.Radius | | | | END FUNCTION | | | | SUB Circle.setRadius (__circle AS Type_Circle, radius AS SINGLE) | | | | __circle.Radius = radius | | | | END SUB | | | | | | SUB Circle.getCenter (__circle AS Type_Circle, center AS Type_Vector2) | | | | center = __circle.rigidbody.position | | | | END SUB | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | SUB Ray2D (__Ray2D AS Type_Ray2D, origin AS Type_Vector2, direction AS Type_Vector2) | | | | __Ray2D.origin = origin | | __Ray2D.direction = direction | | Normalize __Ray2D.direction | | | | END SUB | | | | SUB Ray2D.getOrigin (__ray2D AS Type_Ray2D, origin AS Type_Vector2) | | | | origin = __ray2D.origin | | | | END SUB | | | | | | SUB Ray2D.getDirection (__ray2D AS Type_Ray2D, direction AS Type_Vector2) | | | | direction = __ray2D.direction | | | | END SUB | | | | | | | | | | | | | | SUB RaycastResult (__RaycastResult AS Type_RaycastResult) | | | | __RaycastResult.ppoint.x = 0 | | __RaycastResult.ppoint.y = 0 | | __RaycastResult.normal.x = 0 | | __RaycastResult.normal.y = 0 | | __RaycastResult.t = -1 | | __RaycastResult.hit = 0 | | | | END SUB | | | | SUB RaycastResult.init (__RaycastResult AS Type_RaycastResult, ppoint AS Type_Vector2, normal AS Type_Vector2, t AS SINGLE, hit AS INTEGER) | | | | __RaycastResult.ppoint = ppoint | | __RaycastResult.normal = normal | | __RaycastResult.t = t | | __RaycastResult.hit = hit | | | | END SUB | | | | SUB RaycastResult.reset (result AS Type_RaycastResult) | | | | IF result.ppoint.x OR result.ppoint.y THEN | | result.ppoint.x = 0 | | result.ppoint.y = 0 | | result.normal.x = 0 | | result.normal.y = 0 | | result.t = -1 | | result.hit = 0 | | END IF | | | | END SUB | | | | | | | | | | SUB AddVectors (V1 AS Type_Vector2, V2 AS Type_Vector2, Vout AS Type_Vector2) | | | | | | | | | | | | | | | | | | Vout.x = V1.x + V2.x | | Vout.y = V1.y + V2.y | | | | END SUB | | | | | | SUB SubtractVectors (V1 AS Type_Vector2, V2 AS Type_Vector2, Vout AS Type_Vector2) | | | | | | | | | | | | | | | | | | Vout.x = V1.x - V2.x | | Vout.y = V1.y - V2.y | | | | END SUB | | | | | | SUB ScalarMultiplyVector (V AS Type_Vector2, Scalar AS SINGLE, Vout AS Type_Vector2) | | | | | | | | | | | | | | | | | | | | | | Vout.x = V.x * Scalar | | Vout.y = V.y * Scalar | | | | END SUB | | | | | | FUNCTION Dot (V1 AS Type_Vector2, V2 AS Type_Vector2) | | | | | | | | | | | | Dot = V1.x * V2.x + V1.y * V2.y | | | | END FUNCTION | | | | | | FUNCTION CrossProductVectors (V1 AS Type_Vector2, V2 AS Type_Vector2) | | | | | | | | | | | | | | | | CrossProductVectors = V1.x * V2.y - V1.y * V2.x | | | | END FUNCTION | | | | | | FUNCTION VectorLength (V AS Type_Vector2) | | | | | | | | | | VectorLength = _HYPOT(V.x, V.y) | | | | END FUNCTION | | | | | | SUB Normalize (v AS Type_Vector2) | | | | | | | | | | | | | | DIM VecLength AS SINGLE | | | | VecLength = _HYPOT(v.x, v.y) | | v.x = v.x / VecLength | | v.y = v.y / VecLength | | | | END SUB | | | | | | SUB Rotate (vec AS Type_Vector2, angleDeg AS SINGLE, origin AS Type_Vector2) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DIM x AS SINGLE | | DIM y AS SINGLE | | DIM __cos AS SINGLE | | DIM __sin AS SINGLE | | DIM xPrime AS SINGLE | | DIM yPrime AS SINGLE | | | | x = vec.x - origin.x | | y = vec.y - origin.y | | __cos = COS(_D2R(angleDeg)) | | __sin = SIN(_D2R(angleDeg)) | | xPrime = (x * __cos) - (y * __sin) | | yPrime = (x * __sin) + (y * __cos) | | xPrime = xPrime + origin.x | | yPrime = yPrime + origin.y | | vec.x = xPrime | | vec.y = yPrime | | | | END SUB | | | | | | FUNCTION compareXYEpsilon (x AS SINGLE, y AS SINGLE, epsilon AS SINGLE) | | | | compareXYEpsilon = 0 | | IF ABS(x - y) <= epsilon * MathMax(1, MathMax(ABS(x), ABS(y))) THEN compareXYEpsilon = -1 | | | | END FUNCTION | | | | FUNCTION compareVecEpsilon (vec1 AS Type_Vector2, vec2 AS Type_Vector2, epsilon AS SINGLE) | | | | compareVecEpsilon = 0 | | IF compareXYEpsilon(vec1.x, vec2.x, epsilon) AND compareXYEpsilon(vec1.y, vec2.y, epsilon) THEN compareVecEpsilon = -1 | | | | END FUNCTION | | | | FUNCTION compareXY (x AS SINGLE, y AS SINGLE) | | | | compareXY = 0 | | IF ABS(x - y) <= MIN_VALUE * MathMax(1, MathMax(ABS(x), ABS(y))) THEN compareXY = -1 | | | | END FUNCTION | | | | FUNCTION compareVec (vec1 AS Type_Vector2, vec2 AS Type_Vector2) | | | | compareVec = 0 | | IF compareXY(vec1.x, vec2.x) AND compareXY(vec1.y, vec2.y) THEN compareVec = -1 | | | | END FUNCTION | | | | | | FUNCTION lengthSquared (length AS Type_Vector2) | | | | lengthSquared = length.x * length.x + length.y + length.y | | | | END FUNCTION | | | | | | | | | | FUNCTION MathMax (num1 AS SINGLE, num2 AS SINGLE) | | | | IF num1 >= num2 THEN MathMax = num1 ELSE MathMax = num2 | | | | END FUNCTION | | | | | | FUNCTION MathMin (num1 AS SINGLE, num2 AS SINGLE) | | | | IF num1 <= num2 THEN MathMin = num1 ELSE MathMin = num2 | | | | END FUNCTION | | | | | | |
|
|
|
BAM and the CIRCLE statement |
Posted by: CharlieJV - 06-11-2023, 05:25 PM - Forum: QBJS, BAM, and Other BASICs
- Replies (4)
|
 |
I'm going through this old BASIC book to sanity-check BAM's implementation of BASIC statements and functions.
From the Handbook of BASIC: for the IBM PC, XT, AT, PS/2, and compatibles (chapter starting on page 42), 1988
( https://archive.org/details/handbookofbasicf00schn ), I'm happy to find that the code samples work A-1 in BAM:
Code: (Select All) again:
SCREEN 1 : CIRCLE (160, 100), 23
PRINT "SCREEN 1 : CIRCLE (160, 100), 23"
_delay 1.5
SCREEN 2 : CIRCLE (160, 100), 23
PRINT "SCREEN 2 : CIRCLE (160, 100), 23"
_delay 1.5
' NOTE: BAM requires a space where a parameter is omitted
SCREEN 1 : CIRCLE (160, 110),150,1, , ,.45
PRINT "SCREEN 1" : PRINT "CIRCLE (160, 110),150,1, , ,.45"
_delay 1.5
SCREEN 1 : CIRCLE (160, 120),70,2, , ,1.4
PRINT "SCREEN 1" : PRINT "CIRCLE (160, 120),70,2, , ,1.4"
_delay 1.5
SCREEN 1
CIRCLE (50, 160), 25, ,-.8,-5.5
CIRCLE (200, 160), 25
CIRCLE (200, 160),20, ,4, 5.5, .4
CIRCLE (192,152),1
CIRCLE (210,152),1
_delay 1.5
SCREEN 1
FOR I = 10 TO 70 STEP 5
CIRCLE (200,120), I
NEXT I
_delay 1.5
SCREEN 1
CIRCLE (70, 125), 45,2,-1,6,2
CIRCLE (180,125), 35, ,0,3.14
CIRCLE (250,126), 30, ,-.0000001,-1.57
_delay 1.5
SCREEN 1
FOR I = .1 TO 2 STEP .3
CIRCLE (160,120),50, , , ,I
NEXT I
_delay 1.5
GOTO again
|
|
|
array assigned in SUBs |
Posted by: sivacc - 06-11-2023, 03:10 AM - Forum: Repo Discussion
- Replies (5)
|
 |
ReDim and assign an array within a SUB and pass through the SUB's parameters
.......
getarray z%()
print ubound(z%), z%(5)
end
SUB getarray( x() as integer)
n%= 25
ReDim as ineger x(0 to n%-1)
for p%= 0 to n%-1
x%(p%)= p%*p%
next
end sub
|
|
|
Connect 4 with AI |
Posted by: bplus - 06-10-2023, 07:03 PM - Forum: Programs
- No Replies
|
 |
This game is generalized to do any number of columns and rows, I think. I have it setup for Standard Board Game at 7 columns and 6 Rows. This has been proven to be a certain winner but I forget, the first or 2nd player.
Don't worry AI aint that good but OK.
Code: (Select All)
| | | Option _Explicit | | DefLng A-Z | | Const SQ = 60 | | Const NumCols = 7 | | Const NumRows = 6 | | Const NCM1 = NumCols - 1 | | Const NRM1 = NumRows - 1 | | Const SW = SQ * (NumCols + 2) | | Const SH = SQ * (NumRows + 3) | | Const P = 1 | | Const AI = -1 | | Const XO = SQ | | Const YO = 2 * SQ | | | | ReDim Shared Grid(NCM1, NRM1) | | ReDim Shared DX(7), DY(7) | | DX(0) = 1: DY(0) = 0 | | DX(1) = 1: DY(1) = 1 | | DX(2) = 0: DY(2) = 1 | | DX(3) = -1: DY(3) = 1 | | DX(4) = -1: DY(4) = 0 | | DX(5) = -1: DY(5) = -1 | | DX(6) = 0: DY(6) = -1 | | DX(7) = 1: DY(7) = -1 | | ReDim Shared Scores(NCM1) | | ReDim Shared AIX, AIY | | ReDim Shared WinX, WinY, WinD | | ReDim Shared GameOn, Turn, GoFirst, PlayerLastMoveCol, PlayerLastMoveRow, MoveNum | | ReDim Shared Record$(NCM1, NRM1) | | | | Screen _NewImage(SW, SH, 32) | | _ScreenMove 360, 60 | | Dim mb, mx, my, row, col, r | | _Title "Connect 4: " + _Trim$(Str$(NumCols)) + "x" + _Trim$(Str$(NumRows)) + " with AI" | | GameOn = -1: GoFirst = AI: Turn = AI: MoveNum = 0 | | ShowGrid | | While GameOn | | If Turn = P Then | | While _MouseInput: Wend | | mb = _MouseButton(1): mx = _MouseX: my = _MouseY | | If mb Then | | _Delay .25 | | row = ((my - YO) / SQ - .5): col = ((mx - XO) / SQ - .5) | | If col >= 0 And col <= NCM1 And row >= 0 And row < 8 Then | | r = GetOpenRow(col) | | If r <> NumRows Then | | Grid(col, r) = P: Turn = AI: PlayerLastMoveCol = col: PlayerLastMoveRow = r: MoveNum = MoveNum + 1 | | End If | | Else | | Beep | | End If | | End If | | Else | | AIMove | | Turn = P: MoveNum = MoveNum + 1 | | End If | | ShowGrid | | _PrintString (10, 10), Space$(50) | | _PrintString (10, 10), Str$(AIX) + Str$(AIY) | | _Display | | _Limit 60 | | Wend | | | | Sub AIMove | | | | | | | | | | | | | | | | Dim c, r, d, cntA, cntP, bestScore, startR, startC, iStep, test, goodF, i | | Dim openRow(NCM1) | | ReDim Scores(NCM1) | | AIX = -1: AIY = -1 | | For c = 0 To NCM1 | | openRow(c) = GetOpenRow(c) | | r = openRow(c) | | If r <> NumRows Then | | For d = 0 To 3 | | startC = c + -3 * DX(d): startR = r + -3 * DY(d) | | For i = 0 To 3 | | cntA = 0: cntP = 0: goodF = -1 | | | | For iStep = 0 To 3 | | test = GR(startC + i * DX(d) + iStep * DX(d), startR + i * DY(d) + iStep * DY(d)) | | If test = NumRows Then goodF = 0: Exit For | | If test = AI Then cntA = cntA + 1 | | If test = P Then cntP = cntP + 1 | | Next iStep | | If goodF Then | | If cntA = 3 Then | | AIX = c: AIY = r | | Grid(c, r) = AI | | Scores(c) = Scores(c) + 1000 | | Exit Sub | | ElseIf cntP = 3 Then | | AIX = c: AIY = r | | Scores(c) = Scores(c) + 900 | | ElseIf cntA = 0 And cntP = 2 Then | | Scores(c) = Scores(c) + 8 | | ElseIf cntA = 2 And cntP = 0 Then | | Scores(c) = Scores(c) + 4 | | ElseIf cntA = 0 And cntP = 1 Then | | Scores(c) = Scores(c) + 4 | | ElseIf (cntA = 1 And cntP = 0) Then | | Scores(c) = Scores(c) + 2 | | ElseIf (cntA = 0 And cntP = 0) Then | | Scores(c) = Scores(c) + 1 | | End If | | End If | | Next i | | Next d | | If Stupid(c, r) Then Scores(c) = -1000 + Scores(c) | | End If | | Next | | If AIX <> -1 Then | | Grid(AIX, AIY) = AI | | Exit Sub | | Else | | If GetOpenRow(PlayerLastMoveCol) < NumRows Then | | bestScore = Scores(PlayerLastMoveCol): AIY = PlayerLastMoveRow - 1: AIX = PlayerLastMoveCol | | Else | | bestScore = -1000 | | End If | | For c = 0 To NCM1 | | r = openRow(c) | | If r <> NumRows Then | | If Scores(c) > bestScore Then bestScore = Scores(c): AIY = r: AIX = c | | End If | | Next | | If AIX <> -1 Then | | Grid(AIX, AIY) = AI | | Else | | | | | | Beep: Locate 4, 2: Print "AI has failed to find a proper move, press any to end..." | | Sleep | | End | | End If | | End If | | End Sub | | | | Function GetOpenRow (forCol) | | Dim i | | GetOpenRow = NumRows | | If forCol < 0 Or forCol > NCM1 Then Exit Function | | For i = NRM1 To 0 Step -1 | | If Grid(forCol, i) = 0 Then GetOpenRow = i: Exit Function | | Next | | End Function | | | | Function Stupid (c, r) | | Dim pr | | Grid(c, r) = AI | | pr = GetOpenRow(c) | | If pr <> NumRows Then | | Grid(c, pr) = P | | If CheckWin = 4 Then Stupid = -1 | | Grid(c, pr) = 0 | | End If | | Grid(c, r) = 0 | | End Function | | | | Function GR (c, r) | | | | If c < 0 Or c > NCM1 Or r < 0 Or r > NRM1 Then GR = NumRows Else GR = Grid(c, r) | | End Function | | | | Sub ShowGrid | | Static lastMoveNum | | Dim i, r, c, check, s$, k$ | | If MoveNum <> lastMoveNum Then | | If MoveNum = 1 Then ReDim Record$(NCM1, NRM1) | | If Turn = -1 Then | | Record$(PlayerLastMoveCol, PlayerLastMoveRow) = _Trim$(Str$(MoveNum)) + " " + "P" | | Else | | Record$(AIX, AIY) = _Trim$(Str$(MoveNum)) + " " + "A" | | End If | | lastMoveNum = MoveNum | | End If | | Cls | | Line (XO, YO)-Step(NumCols * SQ, NumRows * SQ), &HFF004400, BF | | For i = 0 To NumCols | | Line (SQ * i + XO, YO)-Step(0, NumRows * SQ), &HFFFFFFFF | | Next | | For i = 0 To NumRows | | Line (XO, SQ * i + YO)-Step(NumCols * SQ, 0), &HFFFFFFFF | | Next | | For r = NRM1 To 0 Step -1 | | For c = 0 To NCM1 | | If Grid(c, r) = P Then | | Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFFFF2200, BF | | ElseIf Grid(c, r) = AI Then | | If c = AIX And r = AIY Then | | Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF680044, BF | | Else | | Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF390027, BF | | End If | | End If | | s$ = _Trim$(Str$(Scores(c))) | | _PrintString (XO + c * SQ + (60 - Len(s$) * 8) / 2, YO + SQ * NumRows + 22), s$ | | Next | | Next | | _Display | | check = CheckWin | | If check Then | | If check = 4 Or check = -4 Then | | For i = 0 To 3 | | Line ((WinX + i * DX(WinD)) * SQ + XO + 5, (WinY + i * DY(WinD)) * SQ + YO + 5)-Step(SQ - 10, SQ - 10), &HFFFFFF00, B | | Next | | End If | | For r = 0 To NRM1 | | For c = 0 To NCM1 | | If Record$(c, r) <> "" Then | | s$ = Mid$(Record$(c, r), 1, InStr(Record$(c, r), " ") - 1) | | If Right$(Record$(c, r), 1) = "A" Then Color , &HFF390027 Else Color , &HFFFF2200 | | _PrintString (SQ * c + XO + (SQ - Len(s$) * 8) / 2, SQ * r + YO + 22), s$ | | End If | | Next | | Color , &HFF000000 | | Next | | If check = -4 Then | | s$ = " AI is Winner!" | | ElseIf check = 4 Then | | s$ = " Human is Winner!" | | ElseIf check = NumRows Then | | s$ = " Board is full, no winner." | | End If | | Locate 2, ((SW - Len(s$) * 8) / 2) / 8: Print s$ | | s$ = " Play again? press spacebar, any other to quit... " | | Locate 4, ((SW - Len(s$) * 8) / 2) / 8: Print s$ | | _Display | | While Len(k$) = 0 | | k$ = InKey$ | | _Limit 200 | | Wend | | If k$ = " " Then | | ReDim Grid(NCM1, NRM1), Scores(NCM1) | | If GoFirst = P Then GoFirst = AI Else GoFirst = P | | Turn = GoFirst: MoveNum = 0 | | Else | | GameOn = 0 | | End If | | End If | | End Sub | | | | Function CheckWin | | Dim gridFull, r, c, s, i | | gridFull = NumRows | | For r = NRM1 To 0 Step -1 | | For c = 0 To NCM1 | | If Grid(c, r) Then | | If c < NCM1 - 2 Then | | s = 0 | | For i = 0 To 3 | | s = s + Grid(c + i, r) | | Next | | If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 0: CheckWin = s: Exit Function | | End If | | If r > 2 Then | | s = 0 | | For i = 0 To 3 | | s = s + Grid(c, r - i) | | Next | | If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 6: CheckWin = s: Exit Function | | End If | | If r > 2 And c < NCM1 - 2 Then | | s = 0 | | For i = 0 To 3 | | s = s + Grid(c + i, r - i) | | Next | | If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 7: CheckWin = s: Exit Function | | End If | | If r > 2 And c > 2 Then | | s = 0 | | For i = 0 To 3 | | s = s + Grid(c - i, r - i) | | Next | | If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 5: CheckWin = s: Exit Function | | End If | | Else | | gridFull = 0 | | End If | | Next | | Next | | CheckWin = gridFull | | End Function |
Must be something wrong < 300 LOC!?!?
I threw out a challenge for an 8x8 board not proven that I could find to be anyone's certain advantage if they played perfect.
That news may be old as maths love to prove such things for all rows and cols.
|
|
|
|